Recent

Author Topic: Better workaround for this class definition hack in dbxDBGridController?  (Read 946 times)

vfclists

  • Hero Member
  • *****
  • Posts: 1152
    • HowTos Considered Harmful?
I upgraded dxDBGridController to the latest 1.0.3.1 version and the developer has added this code as a way to make it a property of TDBGrid

Code: Pascal  [Select][+][-]
  1.    // Hack to redeclare your TDBGrid here whitout the the form designer going mad
  2.    { TDBGrid }
  3.    TDBGrid = Class(DBGrids.TDBGrid)
  4.    private
  5.       FDBGridController: TdxCustomDBGridController;
  6.       Procedure WMHScroll(Var Msg: TWMHScroll); message WM_HSCROLL;
  7.    End;
  8.  

Here is a link to the line in the repo - https://gitlab.com/lazaruscomponent/dbgridcontroller/-/blob/master/dxDBGridController.pas?ref_type=heads#L123


I had a component derived from TDBGrid and so had to change how I subclassed by including dxDBGridController in the units and changing the subclassing

Code: Pascal  [Select][+][-]
  1.  
  2.   // from
  3.  TRcaDBGrid = class(TDBGrid)
  4.   //to
  5.  TRcaDBGrid = class(dxDBGridController.TDBGrid)
  6.   private
  7.     FNotification: string;
  8.     FNotificationEvent: TNotificationEvent;
  9.   protected
  10.     procedure KeyDown(var Key: Word; Shift: TShiftState);override;
  11.     procedure SetNotification (notificationMessage: string);
  12.   public
  13.     property Notification: string read FNotification write SetNotification;
  14.     //constructor Create; virtual;
  15.   published
  16.     property OnNotification: TNotificationEvent read FNotificationEvent write FNotificationEvent;
  17.   end;
  18.  

I consider this to be a messy hack and it will mean changing the subclassing of every grid which uses the dxDBGridController.

Is there a more elegant way of working around this issue?
« Last Edit: January 02, 2026, 01:07:23 am by vfclists »
Lazarus 3.0/FPC 3.2.2

jamie

  • Hero Member
  • *****
  • Posts: 7493
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #1 on: December 29, 2025, 10:06:01 pm »
Yeah, for production code that isn't very good indeed.

Personally I would have that control simply have a property that can be set to the DBgrid of your choice and with that property you can then hook into the WndProc message loop of the Grid and get and control anything message related and that would be keyboard and scrolling items etc.

Jamie
The only true wisdom is knowing you know nothing

vfclists

  • Hero Member
  • *****
  • Posts: 1152
    • HowTos Considered Harmful?
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #2 on: December 30, 2025, 04:50:49 am »
Yeah, for production code that isn't very good indeed.

Personally I would have that control simply have a property that can be set to the DBgrid of your choice and with that property you can then hook into the WndProc message loop of the Grid and get and control anything message related and that would be keyboard and scrolling items etc.

Jamie

That is how the previous version of dxDBGridController worked. It is the latest version that seems has adopted such an approach. Why does the author describe it as a "hack"?

If I include the code in every component subclassed from TDBGrid ie

Code: Pascal  [Select][+][-]
  1.    TDBGrid = Class(DBGrids.TDBGrid)
  2.    private
  3.       FDBGridController: TdxCustomDBGridController;
  4.       Procedure WMHScroll(Var Msg: TWMHScroll); message WM_HSCROLL;
  5.    End;
  6.  

or add it to forms which contain TDBGrid derived components that will that work?

Another approach I'm thinking of is to add a property called OrigDBGrid which references Inherited.DBGrid or something along those lines so that the dxDBGridController uses OrigDBGrid of any such grid. Does this make sense?

« Last Edit: December 30, 2025, 05:21:58 am by vfclists »
Lazarus 3.0/FPC 3.2.2

jamie

  • Hero Member
  • *****
  • Posts: 7493
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #3 on: December 30, 2025, 02:55:23 pm »
A step back is in order.

Read up and studdy the VMT tables to hook into the virtual stream of calls.

Jamie
The only true wisdom is knowing you know nothing

swissbob

  • Newbie
  • Posts: 5
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #4 on: December 30, 2025, 05:28:12 pm »
It's not a hack, it amateur nonsense.  The whole point of having a TCustomDBGrid is to avoid this kind of nonsense.  Component developers inheritance from the custom version, while consumers inherit from the published version. 

jamie

  • Hero Member
  • *****
  • Posts: 7493
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #5 on: December 30, 2025, 10:02:21 pm »
There is a "AddHandlerKeyDown" in there so you can capture that before it goes anywhere else.

There are also other add handlers etc.

If you set a property of DBGrid you can access it to add a handler pointing to other Class so if can capture it first.

That should get you started.
The only true wisdom is knowing you know nothing

vfclists

  • Hero Member
  • *****
  • Posts: 1152
    • HowTos Considered Harmful?
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #6 on: January 02, 2026, 01:03:29 am »
There is a "AddHandlerKeyDown" in there so you can capture that before it goes anywhere else.

There are also other add handlers etc.

If you set a property of DBGrid you can access it to add a handler pointing to other Class so if can capture it first.

That should get you started.

I was using the AddHandlerKeyDown method before incorporating the code into a proper component because it was becoming unwieldy.

If the author calls it a hack to stop the Form Designer from bugging out is there a way to do it correctly? I might be able to incorporate it upstream if there is a proper alternative to the hack, or I could just raise an issue on the "hack".

What are VMTs and where can I learn about them and use them?
Lazarus 3.0/FPC 3.2.2

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12019
  • Debugger - SynEdit - and more
    • wiki
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #7 on: January 02, 2026, 01:28:37 am »
I don't use the component, and I therefore don't know what the hack tries to achieve.

I would normally expect that there would be a subclass of TDBGrid, and that subclass then incorporates the functionality. And in the Form/designer you would add a TSubDbGrid instead of a TDbGrid?
But it seems that is not wanted.

So the hack uses the way the loader works, and the shortcoming of the designer to see the difference between the 2 classes (and the are 2 distinct classes, the new TDbGrid is in every way a new class as TSubDbGrid would be / just has an overlap in the name)

=> btw, have you tested that in lazarus 4.99 (with fpc 3.3.1)? Afaik Lazarus 4.99 has a designer (if not yet, then will eventually) that does see the DbGrid.TDbGrid and YourUnit.TDbGrid as different (I recall someone was talking about implementing that). So not sure what will happen to that hack....



But back to the hack.

The (old) designer only checks the not-qualified name. And so it does not realize there are 2 classes.

When loading a form from the lfm at runtime, then the loader looks at the class declaration
Code: Pascal  [Select][+][-]
  1. Tform1 = class
  2. {published}
  3.   MyGrid1: YourUnit.TDBGrid; // YourUnit is derived from the scoping, and not given in the code, but the TDBGrid points there.
The runtime lfm loader, also only has the non-qualified class name, but the TForm (RTTI) resolves that to the replacement.

So it calls create on the replacement call, because the unqualified name TDBGrid in the TForm resolves that way.


So technically the result is the same as registering TSubDbGrid, and putting that on the form (which apparently you had been doing before).

And as you have noticed the hack does not, and can not affect subclasses. Because they define there own inheritance, and the trickery does not work on that part.




Not sure what was meant by using VMT => maybe to find which "virtual" methods you may need to overwrite. But that still needs to have a subclass.

All other play with VMT (virtual method tables) is not recommended. (E.g. you can create your own class at runtime, but you can also shot your own foot while doing so...) - not sure how that would help...

You could also (not sure / I guess) at runtime play with the RTTI (maybe that was meant and mixed up), and before loading bend the pointer to the class... But that is pretty hardcore... Not something I would recommend...


vfclists

  • Hero Member
  • *****
  • Posts: 1152
    • HowTos Considered Harmful?
Re: Better workaround for this class definition hack in dbxDBGridController?
« Reply #8 on: January 02, 2026, 12:38:47 pm »

Not sure what was meant by using VMT => maybe to find which "virtual" methods you may need to overwrite. But that still needs to have a subclass.

All other play with VMT (virtual method tables) is not recommended. (E.g. you can create your own class at runtime, but you can also shot your own foot while doing so...) - not sure how that would help...

You could also (not sure / I guess) at runtime play with the RTTI (maybe that was meant and mixed up), and before loading bend the pointer to the class... But that is pretty hardcore... Not something I would recommend...
[/quote

This is an approach suggested by @jamie in an earlier reply. It is an aspect of FreePascal I need to be better acquainted with.
Lazarus 3.0/FPC 3.2.2

 

TinyPortal © 2005-2018