This is unusual ... TRect not defined in TWebStringGrid.OnDrawCell?

Thanks again, Bruno. I see that these elements are "deprecated" and CSS is recommended instead. Is there an equivalent method available via TMS WEB Core?

FWIW, you're talking about stuff that's been around since HTML3, 30+ years, and is still supported in HTML5. Maybe when HTML6 rolls around, they won't be there, but I suspect there will be plenty of websites that still use them 10 years from now. Look how long it took for site designers and tools to switch from HTML4 to HTML5, and there are still TONS of sites that use HTML4. I'd bet the wizards at TMS will have figured out a workaround long before then. :slight_smile:

The equivalent CSS property is "text-align"

Thanks, Bruno, but what I was asking about was how to use CSS rather than the td elements to set WebStringGrid cell attributes if it can be done. As David pointed out, this is not highly critical since the td elements are not going away soon even though "deprecated".

TD element is not deprecated. It is a couple of attributes of the TD element that are deprecated.

Deprecated attributes

abbr Deprecated

This attribute contains a short abbreviated description of the cell's content. Some user-agents, such as speech readers, may present this description before the content itself.

Note: Do not use this attribute as it is obsolete in the latest standard. Alternatively, you can put the abbreviated description inside the cell and place the long content in the title attribute.

align Deprecated

This enumerated attribute specifies how the cell content's horizontal alignment will be handled. Possible values are:

  • left: The content is aligned to the left of the cell.
  • center: The content is centered in the cell.
  • right: The content is aligned to the right of the cell.
  • justify (with text only): The content is stretched out inside the cell so that it covers its entire width.
  • char (with text only): The content is aligned to a character inside the <th> element with minimal offset. This character is defined by the char and charoff attributes.

The default value when this attribute is not specified is left.

Actually, that article shows ALL of the td attributes except colspan, headers, and rowspan with the trashcan icon indicating that they are deprecated.

And while that's technically true, the global attributes (which includes the id attribute you were asking about) are not deprecated, and most of the useful attributes that are marked as deprecated can be easily replaced with much more powerful CSS equivalents, thankfully! This is a very good thing.

OK Andrew, but it's still not clear to me how to go about implementing those "more powerful CSS equivalents" in TWebStringGrid if that is currently possible. Perhaps, as David suggested, such is still on TMS' to-do list.

Perhaps I'm late to the conversation and missing something obvious. We can usually add CSS to a TMS WEB Core project and override anything we like, so long as straight HTML is used and none of those pesky <canvas> elements, anyway. The FNC components tend to use those, which can be customized also with CSS but not in as obvious a manner.

A TWebStringGrid just generates an HTML table though, no <canvas> element, so we're free to add CSS to style it any way we'd like. So...

  1. Create a new TMS WEB Core project
  2. Drop a TWebStringGrid on the form
  3. Set its ElementID property to something, say, GRID.
  4. Add something in WebFormCreate to populate the grid
  5. Add a CSS file to the project.
  6. Add a link to the CSS file in Project1.html
  7. Add CSS rules to apply whatever styling we want.

Here's what I put in WebFormCreate:

procedure TForm1.WebFormCreate(Sender: TObject);
var
  data: TStringList;
begin

  data := TStringList.Create;
  data.Add('zebra;orange;New York City;32');
  data.Add('horse;yellow;Tokyo;33');
  data.Add('cow;purple;London;44');
  data.Add('moose;green;Berlin;24');

  WebStringGrid1.LoadFromStrings(data);
end;

For the component dropped on the form, I just set the fixed columns to zero and set the default width to 100. Just as a sample here, nothing exotic. The CSS file was named custom.css and a line in the Project1.html file might look like this.

   <link href="custom.css" rel="stylesheet"/>

The CSS file is where the interesting bits are. Here's what I came up with. Not a best practices or anything, just to give you an idea of how it might work. Too many !important flags (there's a way to do that better) and a bit repetitive and specific (nth-child(1) for example could b handled differently) but it gets the job done.

#GRID {
  border: 2px solid black !important;
  border-radius: 10px !important;
  padding: 5px;
  background: gray;
}


#GRIDtblNormalCellTable tr > td:nth-child(1) {
  background-color: maroon !important;
  text-align: left;
  padding-left: 5px;
  color: white;
}
#GRIDtblNormalCellTable tr > td:nth-child(2) {
  background-color: cyan !important;
  text-align: right;
  padding-right: 5px;
  color: black;
}
#GRIDtblNormalCellTable tr > td:nth-child(3) {
  background-color: purple !important;
  width: 200px !important;
  max-width: 200px !important;
  text-align:center;
  color: white;
}
#GRIDtblNormalCellTable tr > td:nth-child(4) {
  background-color: yellow !important;
  width: 50px !important;
  text-align: right;
  padding-right: 5px;
  color: black;
}

With a bit of effort, anything there can be customized further. And I do mean anything. And no table attributes were used, just CSS. Not that it is anything fancy, but a simple example of setting a few colors and cell alignments, widths and so on. Much more control is possible here, just didn't want to spend too much time if this is already old news. Here's what it looks like.

This might even be the hardest way to do this, but all it involves really is editing a CSS file. A different set of rules could work on a row-basis rather than a column-basis, for example, and we could change anything we like about the contents of the cell, or the surrounding table aspects.

Thanks, Andrew. That is the sort of hand holding I needed as a CSS newbie. In your example, IIUC, the table's cell attributes are all statically defined. What I want to do is change a row's font color (or background shading) to one of several values dynamically based on its contents. Does that mean that I'd have to dynamically define the CSS?

Not at all. You can also target an element directly in code and apply CSS that way. For example, this bit of JavaScript can change the colors of one of the columns to whatever their value is... Code is in JavaScript because it was quicker for me, but there are Delphi equivalents I'm sure.

  asm
    var colorcells = document.querySelectorAll('#GRIDtblNormalCellTable tr > td:nth-child(2)');
    for (var i = 0; i < colorcells.length; i++) {
      colorcells[i].style.setProperty('background',colorcells[i].innerHTML,'important');
    }
  end;

Another idea is to just add classes to things that you want to change, so you can apply changes to those elements later. So if we wanted the second row. we could try this. Let's try a Delphi variant.


  rowcells := document.querySelectorAll('#GRIDtblNormalCellTable tr:nth-child(2) > td');
  for i := 0 to rowcells.length-1 do
  begin
    (rowcells.Nodes[i] as TJSHTMLElement).classList.add('Special');
    (rowcells.Nodes[i] as TJSHTMLElement).style.setProperty('border','2px solid black');
    (rowcells.Nodes[i] as TJSHTMLElement).style.setProperty('opacity','0.5');
  end;

The 'Special' class is something we added above, so in the CSS file, we can define something specific for that.

.Special {
  font-style: italic !important;
  font-weight: 700 !important;
}

And we end up with the following.

Here's the whole WebFormCreate function, so you can see how the variables are defined, and how easy it is to slip back and forth between Delphi and JavaScript, with CSS wherever we like.

procedure TForm1.WebFormCreate(Sender: TObject);
var
  data: TStringList;
  rowcells: TJSNodeList;
  i: integer;
begin

  data := TStringList.Create;
  data.Add('zebra;orange;New York City;32');
  data.Add('horse;yellow;Tokyo;33');
  data.Add('cow;purple;London;44');
  data.Add('moose;green;Berlin;24');

  WebStringGrid1.LoadFromStrings(data);


  asm
    var colorcells = document.querySelectorAll('#GRIDtblNormalCellTable tr > td:nth-child(2)');
    for (var i = 0; i < colorcells.length; i++) {
      colorcells[i].style.setProperty('background',colorcells[i].innerHTML,'important');
    }
  end;

  rowcells := document.querySelectorAll('#GRIDtblNormalCellTable tr:nth-child(2) > td');
  for i := 0 to rowcells.length-1 do
  begin
    (rowcells.Nodes[i] as TJSHTMLElement).classList.add('Special');
    (rowcells.Nodes[i] as TJSHTMLElement).style.setProperty('border','2px solid black');
    (rowcells.Nodes[i] as TJSHTMLElement).style.setProperty('opacity','0.5');
  end;


end;
1 Like

There is certainly a bit of a hurdle moving from Delphi to the world of JavaScript/HTML/CSS. Understandable. But putting them all together is a potent combination.

And just because it is May the Fourth, here's a bit of wisdom from a galaxy far, far away....

Kenobi:
[gets up and takes a blast helmet (aka TMS WEB Core)] I suggest you try it again, Luke. Only this time, let go your conscious self and act on instinct. [puts the helmet on Luke, which covers his eyes]

Skywalker:
But with the blast shield down, I can't even see! How am I supposed to fight (aka use Delphi)?

Kenobi:
Your eyes can deceive you. Don't trust them. [remote shoots Luke (compiler error)] Stretch out with your feelings! [Watches Luke succeed in blocking the lasers] You see? You can do it.

Thanks again! I'll have to ponder this for a while for it to sink in....

You're most welcome! If you haven't seen them already, and you have a bit of time, I've also written a blog post or two that might be of interest in this area. Here's one.

I will check them out. Thanks for the pointer.