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

I put a TWebStringGrid on a form and I clicked to create an OnDrawCell handler. I got this compiler error:

[Error] frmWEBTest1Main.pas(402): identifier not found "TRect"

I added System.Types to the upper uses clause and it went away.

But then this error appeared:

[Error] frmWEBTest1Main.pas(404): identifier not found "TGridDrawState"

I tried defining type TGridDrawState = integer; but it throws a bunch of typing errors at run-time. So I changed it to this (from the Help file):

TGridDrawState = set of (gdSelected, gdFocused, gdFixed, gdRowSelected, gdHotTrack, gdPressed);

That brought up something totally different. See the screenshot below.

Usually when you add visual components to a form, they automatically add the necessary units to the uses clause.

We'll add a SelectionEditor to handle this automatically in the next update.

1 Like

what do you have in mind? I mean ... it seems like the TGridDrawState isn't defined in the proper scope. But I'm not sure why the requisite units aren't being included in the uses clause. (Actually, I don't even know how that happens, but it seems to be a feature of the IDE. If you delete a bunch of things from the uses clause then save the file, the IDE will add back all of the units it needs to compile into the uses clause.)

I had another situation where I defined an enum with ssNone as the first element, and I got a very strange compiler error saying the type was wrong for something in the javascript relating to scroll bars. It took me quite a while to realize that it was conflicting with an enum element in the TScrollStyle enum definition that also had a ssNone defined in it. It seemed very odd that my locally-defined enum would impact an enum in another unit. I thought Delphi added implicit unit scoping to things since 10.2 or thereabouts?

Why would there be scoping conflicts like this? They seem related. In one case, there's no wall that led to strange conflicts, and in another case there was an impenetrable wall that led to an inability to find common declarations.

https://docwiki.embarcadero.com/Libraries/Alexandria/en/DesignEditors.TSelectionEditor

I added the patches that David noted to my uses and type statements, which also allowed me to compile the OnDrawCell procedure (Thanks, David!), but then I got the following error at runtime:

ERROR
uncaught exception: [object Object] | FMessage::Unknown property: "OnDrawCell" FHelpContext::0 FJSError::Error: Unknown property: "OnDrawCell" FStack::this.Create$1@http://localhost:8000/CW_EPG_Remote/CW_EPG_Remote_1_0_428.js:3431:23 this.CreateFmt@http://localhost:8000/CW_EPG_Remote/CW_EPG_Remote_1_0_428.js:3437:12 createClass/c.$create@http://localhost:8000/

Edit: I see that David got a similar runtime error. I haven't yet reviewed the embarcadero docwiki because I thought that his patches were the full fix. I'll review the docwiki and revert if it doesn't solve the issue.

Edit2: It's not clear to me that the embarcadero docwiki item solves my problem. Am I missing it or is there an unresolved issue with TWebStringGrid.OnDrawCell ??

I wouldn't call those "patches", just things I tried to work-around the problem. They didn't help.

The TGridDrawState enum appears to be improperly scoped, and defining it locally fixes that. But there's something else hiding behind it that I don't understand. It throws a run-time error.

Which is why I can't really understand what the use of the selection editor might do to solve the problem. One is a compile-time error, and the other is a run-time error. The selection editor is something that goes into the IDE's Object Inspector.

The OnDrawCell handler isn't in need of any kind of selection. It just isn't working properly.

We checked but there is at this moment no run-time implementation of OnDrawCell (because the grid is at run-time built via the HTML TABLE element that doesn't support custom drawing)..
Note that design-time is something happening in a Win32 VCL form designer and run-time is happening via JavaScript in the browser DOM. Two completely different worlds. We'll look to exclude OnDrawCell for design-time as long as we can't provide a solution for run-time.

ahh, well, now THAT makes sense! I'm sure there are lots of places where this same logic applies, and it would certainly be good to know, because it's hardly obvious.

That said, perhaps there's a way to have a slightly different handler that lets you know there's some HTML behind it rather than the usual Delphi stuff, and that allows you to inject HTML tags there?

For an HTML table, you can say something like,

<td color="white" bgcolor="magenta">my-data</td>

which is effectively the same as what OnDrawCell offers. But maybe you need to let the tag elements be specified separately from the data?

An HTML table has several tags:

<table>
<tr>...</tr> -- rows
<th>...</th>  -- the row header
<td>...</td>  -- individual data cells
</table>

And all of the opening tags can have a bunch of tag elements in them, including CSS.

I was just trying to set the background color of some cells. HTML allows it, but not exactly the same way that Delphi typically does.

Why not allow those tags, but at run-time show something that says it's not supported and to use some other khandler in its place?

David, have you tried, either directly in the WebStringGrid.Cells or using OnGetCellData events, wrapping the <td color=...>...</td> tags around your cell data to see what happens? Presumably the HTML table would end up with double tags for each cell, but perhaps that would be OK?

I tried embedding tags in the StringGrid.Cells and it seems that they get ignored or stripped out. :frowning_face:

I've tried doing this in different places using both <...> and &lt;...&gt; and they get stripped out as well. It makes it hard to send content to services that require XML tags for meta-commands. I haven't even been able to figure out exactly where in the stack they're being removed.

@brunofierens since these controls are built on top of HTML, I think there should be ways to inject HTML tags into the framework to leverage what's there, as well as pass them through to remote services. I can understand why that's not the case for these components, as it would be meaningless for VCL and FMX apps. But there are libraries for those frameworks that let you work with HTML (https://delphihtmlcomponents.com comes to mine), so perhaps use them as guidance for what to offer here. Clearly, there are things that won't work the same way they do in VCL/FMX, but that's no reason to simply disable them or just say, "they don't work here". I realize there's a goal to keep things as consistent as possible for all platforms, but in cases like this that means, do you allow the use of logic that does the same thing in multiple frameworks using slightly different approaches, or do you just make it impossible to do?

My vote is that things like OnDrawCell here should accept HTML tags to provide the same UI benefits that you can accomplish in VCL and FMX, even though it requires different (and incompatible) code. If you NEED to make it work with VCL/FMX, then conditional compilation directives can be used. I don't see that as an insurmountable obstacle.

Just something to consider for future releases. :slight_smile:

  1. OnGetCellChildren is the event to use when you want to insert child HTML elements.
  2. The html components you refer to are native controls and have nothing to do with browser based HTML.
  3. As I said multiple times now, the VCL framework has 28 years of history. To expect that we replicate ALL VCL functionality in just a few years in a completely different environment is unrealistic. We do things step by step with the constraints of the browser and within the scope of interest of majority of users.
  4. To have a real custom cell drawing feature in the grid, our thinking is in the direction of embedding a HTML CANVAS element in a cell (where needed). But it comes with complexities and we haven't been able to define the best architecture for it and given many other things to, haven't given this the top priority.

I don't think anybody expects you to replicate ALL VCL functionality, especially things that clearly don't make sense.

It's good to have a work-around for such things, and these incompatibilities just leave users stuck with no solution at all. I'll certainly take a look at that OnGetCellChildren handler.

The VCL approach from the start (in Delphi 1) was very simple: "here, render it yourself!" At least there's a path to a solution that way.

So lots of grids were derived from a regular StringGrid that simplified common things appropriately, like changing font attributes and the color of the cell.

In this case, it's impossible, because there's just nothing we can do -- access is completely blocked. Or maybe there is if someone feels like doing sufficient reverse-engineering of the component.

The VCL approach is not something I'd like to see implemented literally, meaning that code that works in VCL would work here. VCL is not working with HTML underneath. And as you say, the other components I pointed to are working with it. I only pointed to them as a possible source of inspiration for a solution; maybe it makes no sense.

But having something that simply lets you take over a bit of the rendering the same way the VCL does is quite sufficient. There's already code doing that here. So just offer a way to inject another method, or the results of another method, at that point. That's all the VCL does, and that's what I'd expect here. Maybe you're saying it's not as simple as that... well, ok. That's how things go sometimes. :slight_smile:

That is exactly why OnGetCellChildren has been there in TWebStringGrid from TMS WEB Core v1.0!

1 Like

Bruno, I'm clearly still missing a key setting. I've added that Event to my WebStringGrid1 and copied the only example I've found of OnGetCellChildren (in TMSWEBCoreReleaseNotes.pdf) as follows:

procedure TCWRmainFrm.WebStringGrid1GetCellChildren(Sender: TObject; ACol,
  ARow: Integer; AField: TField; AValue: string;
  AElement: TJSHTMLElementRecord);
begin
  case ACol of
  0: AElement.element['align'] := 'right';
  1: AElement.element['align'] := 'center';
  end;
end;

Columns 0 and 1 still display as LeftJustified (the default) whether or not DefaultDrawing is True.

What am I missing? It would be very helpful to me at least to have some additional examples of using this event. (E.g., where to find the allowed properties of "element")

How does this comment about TWebMemo relate to this thread about TWebStringGrid.OnDrawCell?

How do you load the grid? Through LoadFromJSON? LoadFromCSV?
If not, use something like:

var
  el: TJSHTMLElement;
begin
  webstringgrid1.InitSample(imRandom);
  el := webstringgrid1.CellElements[1,1];
  el['align'] := 'right';
end;
1 Like

sorry, I posted by mistake.

Thanks, Bruno, I don't understand the syntax, but it does work to assign an appropriate string to el[x] with x = either 'align' or 'bgcolor' after defining it as you show. The latter is, I believe, what David was trying to accomplish in the OP here.

Can you please point this Javascript newbie in the right direction to discover what other values x may take on and what are the possible ranges of those? In a few experiments I've found that most of the x string values that I've tried produce no results (and no errors).

x are all the attribute names a HTML element can have.
In this case, this is a TD, so attributes can be found here: