EventAdapter not working

I tried to create a new EventAdapter for TDrawCell of TStringGrid.
But I am not able to compile it. What have I done wrong?

type
  TMyDrawCellEventDispatcher = class(TatEventDispatcher)
  private
    procedure __TDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
  end;

...

  DefineEventAdapter(TypeInfo(TDrawCellEvent), TMyDrawCellEventDispatcher,
    @TMyDrawCellEventDispatcher.__TDrawCell);

...

{ TMyDrawCellEventDispatcher }

procedure TMyDrawCellEventDispatcher.__TDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
begin
  if Assigned(Scripter) and (RoutineName > '') then begin
    Scripter.ExecuteSubroutine(RoutineName, [Sender, ACol, ARow, Rect, State]);
  end;
end;

The line
Scripter.ExecuteSubroutine(RoutineName, [Sender, ACol, ARow, Rect, State]);
seems to have a problem with Rect and State.

How can I fix this problem?

Records (like TRect) require a special treatment. Nevertheless, there are a few examples in Support Center about how to use it, specifically in events. Here are some references:

I have changed it like this:

type
  TRectWrapper = class(TatRecordWrapper)
  private
    FLeft: Integer;
    FTop: Integer;
    FRight: Integer;
    FBottom: Integer;
  published
    property Left: Longint read FLeft write FLeft;
    property Top: Longint read FTop write FTop;
    property Right: Longint read FRight write FRight;
    property Bottom: Longint read FBottom write FBottom;
  end;
{ TMyDrawCellEventDispatcher }

procedure TMyDrawCellEventDispatcher.__TDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  MyRect: TRectWrapper;
  MyStateTypeSet: TGridDrawState;
  MyStateType: Variant;
begin
  MyRect := TRectWrapper.Create();
  MyRect.Left := Rect.Left;
  MyRect.Top := Rect.Top;
  MyRect.Right := Rect.Right;
  MyRect.Bottom := Rect.Bottom;

  MyStateTypeSet := State;
  MyStateType := IntFromSet(MyStateTypeSet, SizeOf(TGridDrawState));

  if Assigned(Scripter) and (RoutineName > '') then begin
    Scripter.ExecuteSubroutine(RoutineName, [Sender, ACol, ARow, MyRect, MyStateType]);
  end;
  MyRect.Free;
end;

Now it compiles, but I still have the problem that Rect only contains NULL values.
When debugging in Delphi IDE I see that MyRect.Left receives a correct value and MyRect is also passed using
Scripter.ExecuteSubroutine(RoutineName, [Sender, ACol, ARow, MyRect, MyStateType]);.
But inside the script Rect.Left is NULL all the time.
Where is my mistake?

I can't seen anything wrong in your code. Are you able to pack it in a sample project reproducing the issue, so we can try to help you our more objectively?

It is difficult to give you a sample project. In which format would you need it? We store our Scripting code in an own format inside a database and are able to export it in a self developed XML-Format. This would not help you.

It works now with a tricky workaround:
Scripter.ExecuteSubroutine(RoutineName, [Sender, ACol, ARow, MyRect, MyStateType, MyRect.Left, MyRect.Top]);

I simply pass the missing values as additional parameters. This works even if the header of the function does not have these parameters.
procedure TMyDrawCellEventDispatcher.__TDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

Inside the scripting engine code it looks like this:

procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState; iLeft, iTop: integer);
begin
  if Rect = null then ShowMessage('Rect is null'); // does not show => Rect has a value
  if Rect.Left = null then ShowMessage('Rect.Left is null'); // This message box will be shown
  ShowMessage(Format('iLeft=%d/iTop=%d', [iLeft, iTop])); // The correct values are displayed
  ShowMessage(Format('Rect.Left=%d/Rect.Top=%d', [Rect.Left, Rect.Top])); // Script crashs because of null values in Rect.Left and Rect.Top

Currently I am able to process the needed values with that workaround, so I am content.
But I think there is a bug anywhere inside the scripting engine...

Sidenote:

procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState; iLeft, iTop: integer);
var
  test1: TRect;  
  test2: TRectWrapper;
begin
  test1.Left := 1; // Works
  test2.Left := 2; // Scripting-Error
end

In both cases if I type test1. or test2. I do not get any popup menu which would show me the members of TRect.

But my Delphi code already contains the lines

  AScripter.DefineRecordByRTTI(TypeInfo(TRect));
  AScripter.DefineRecordByRTTI(TypeInfo(TRectWrapper));

A Delphi project that shows the problem happening. If you are struggling with this setup, I would even recommend that you try the event adapter in a separate project instead in your main application for learning and testing purposes.

Can you give me a "empty" Delphi program with the minimum requirements for Scripting?
I use Delphi 10.1 Berlin with Scriper v7.27 (Version from March 2022)

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.

Here you go:

ScripterTest.zip (9.0 KB)

How can I implement a windows form inside that tiny demo program?
I have no clue how to do that.
In my version of scripter I can open the "TMS Scripter IDE" and create/execute a Windows Form.
In your example I can only execute simple code without a form.

That's what I need

That's what I got from you

That's what it looks like when I execute my script. With this workaround it is already able to color the grid.

You can then modify the existing ScripterProIDE project and then send it to us.