Jump to content
ewong

changing inherited control

Recommended Posts

Hi,

I have added a DBGrid control on a form, and after fiddling with it, I realized I needed to override the MouseDown event.  So I added a new Custom control and following the idea of  http://www.delphigroups.info/2/f8/90624.html I thought changing the Text from  MyGrid: TDBGrid to MyGrid: TCustDBGrid would work; but Delphi complains.  If I click on ignore, it deletes the db control.    If I have included the following code in the same unit as the form:

 

  TCustomDBGrid = class(TDBGrid)
  protected
    procedure MouseDown(Button: TMouseButton; ShiftState: TShiftState; X, Y: integer);
  end;

Then if I change the DFM of the MyGrid from:

 

  MyGrid: TDBGrid;

 

To:

  MyGrid: TCustDBGrid;

 

It should work; but it doesn't, so I'm guessing I'm getting something wrong.

 

What's the right way of doing this?

 

Thanks

 

Ed

Share this post


Link to post
1 hour ago, Dany Marmur said:

You do not have to do anything to your dfm.

To use OO like that use the same classname, qualify the ancestor with it's unit.

https://zarko-gajic.iz.hr/delphi-interceptor-classes-tbutton-classtbutton/

 

 

Or ... create a package with TMyDBGrid,install into the IDE and drop your TMyDBGrid on forms.

 

HTH

 

/D

Hi Dany,

 

The first option isn't going to work as that'll affect other dbgrids. 

 

So I guess I'll need to use the second option even though it's a bit overkill for just this.  I'm very surprised that

even with TCustDBGrid defined within the same unit as the form,   the dfm processing can't see that. 

 

Thanks

 

Ed

Share this post


Link to post
6 hours ago, ewong said:

realized I needed to override the MouseDown event

I might be missing something, but if you need to do that, why are you omitting the override; behind your declaration?

  • Like 1

Share this post


Link to post

what does Delphi complain? Component not found? What about placing your grid to the form? Same error? Probably only a path issue.

If it's just the MouseDown not working: use override as explained in Günther's  post.

I used the same technique multiple times.

Share this post


Link to post
13 hours ago, joachimd said:

what does Delphi complain? Component not found? What about placing your grid to the form? Same error? Probably only a path issue.

If it's just the MouseDown not working: use override as explained in Günther's  post.

I used the same technique multiple times.

Delphi complains that it can't find "TCustDBGrid".

 

So what I have is:

TCustDBGrid = class(TDBGrid)
protected
  procedure MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y :integer);
end;

TForm1 = class(TForm)
  ..
  recentinfo: TDBGrid;
 ..

end;

implementation
procedure TCustDBGrid.MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: integer);
begin
  if button = mbRight then
    showmessage("testing");
end;

 

From [1], I tried:

constructor TForm1.create;
begin
   recentinfo.onMouseDown = MouseDown;
end;

This didn't work as it's complaining that there's not enough parameters.

 

Then I tried (as mentioned above) changing in the dfm text to change "recentinfo: TDBGrid;" into "recentinfo: TCustDBGrid".  Since the definition of TCustDBGrid is in the same unit as the tform, I figured it would work.  I'm guessing it's wrong thinking this way as what I'm doing is in essence using a visible component which uses a different set of rules than simple "TpointX = class(TPoint)" type of definition.

 

If I just click on the grid, and create an event handler for "OnMouseDown",  as mentioned in [2], it doesn't work as it fires only if I click on the headers.

 

Then I came across [3] and while I think it should work,  I haven't yet found out how to find out whether the componentclass' instance is what I wanted.

 

Tbh, it would've been just simpler had I made this custom dbgrid as a package and be done with it; but I feel there has to be a way other than the package route.

 

Thanks

 

Edmund

 

[1] - http://www.delphigroups.info/2/2f/507785.html

[2] - http://www.delphigroups.info/2/4a/305663.html

[3] - https://stackoverflow.com/questions/4685863/replacing-a-component-class-in-delphi/4686920#4686920

Share this post


Link to post
44 minutes ago, ewong said:

Delphi complains that it can't find "TCustDBGrid".

Makes sense. You didn't put TCustDBGrid into a package and install it into the IDE, so you can't use TCustDBGrid in a DFM resource, unless you call RegisterClass(TCustDBGrid) before the DFM is loaded when the TForm object is created.

Quote

From [1], I tried:


constructor TForm1.create;
begin
   recentinfo.onMouseDown = MouseDown;
end;

This didn't work as it's complaining that there's not enough parameters.

Because you are trying to actually call TForm1's inherited MouseDown() method and then assign its result to the event.  Use this instead:

unit Unit1;

interface

uses
  ..., Vcl.DBGrid, ...;

type
  TDBGrid = class(Vcl.DBGrid.TDBGrid)
  protected
    procedure MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: Integer); override;
  end;

  TForm1 = class(TForm)
    ...
    recentinfo: TDBGrid;
    ..
  end;

implementation

procedure TDBGrid.MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: integer);
begin
  if Button = mbRight then
    ShowMessage("testing");
  inherited;
end;
Quote

Then I tried (as mentioned above) changing in the dfm text to change "recentinfo: TDBGrid;" into "recentinfo: TCustDBGrid".  Since the definition of TCustDBGrid is in the same unit as the tform, I figured it would work.

No, because you are not registering the TCustDBGrid class with the DFM streaming system.

 

Edited by Remy Lebeau

Share this post


Link to post
14 minutes ago, Remy Lebeau said:

Makes sense. You didn't put TCustDBGrid into a package and install it into the IDE, so you can't use TCustDBGrid in a DFM resource, unless you call RegisterClass(TCustDBGrid) before the DFM is loaded when the TForm object is created.

Because you are trying to actually call TForm1's inherited MouseDown() method and then assign its result to the event.  Use this instead:


unit Unit1;

interface

uses
  ..., Vcl.DBGrid, ...;

type
  TDBGrid = class(Vcl.DBGrid.TDBGrid)
  protected
    procedure MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: Integer); override;
  end;

  TForm1 = class(TForm)
    ...
    recentinfo: TDBGrid;
    ..
  end;

implementation

procedure TDBGrid.MouseDown(Sender: TObject; Button: TMouseButton; ShiftState: TShiftState; X, Y: integer);
begin
  if Button = mbRight then
    ShowMessage("testing");
  inherited;
end;

No, because you are not registering the TCustDBGrid class with the DFM streaming system.

 

In hindsight, I think that's what's making me confused.   That said, I've found an indirect way in accordance to [3].

 

TCustDBGrid = class(TDBGrid)
 protected
   procedure MouseDown(Sender: TObject; Button: TMouseButton;
                       ShiftState: TShiftState; X, Y: Integer);
end;

TForm1 = class(TForm)
 ...
  recentinfo: TDBGrid;
 ..
 protected
   procedure FindComponentClass(Reader: TReader; const ClassName: string;
                                    var ComponentClass: TComponentClass);
   Procedure ReadState(Reader: TReader); override
end;

procedure TCustDBGrid.MouseDown(Sender: TObject; Button: TMouseButton;
                                ShiftState: TShiftState; X, Y: Integer);
begin
  if (name = 'recentinfo') and (button = mbRight) then
  begin
    ShowMessage('testing');
  end
  else
    inherited;
end;

procedure TForm1.FindComponentClass(Reader: TReader; const ClassName: string;
                                    var ComponentClass: TComponentClass);
var
  i : integer;
  s : string;
  ts : TComponent;

begin
  if ComponentClass = TDBGrid then
  begin
    ComponentClass := TCustDBGrid;
  end
end;

procedure TForm1.ReadState(Reader: TReader);
begin
  Reader.OnFindComponentClass := FindComponentClass;
  inherited;
end;

The above 'hack' worked.   At first I had tried to find the associated ComponentClass' instance name; only to have it dawn on me that it's just finding the component class.  It hadn't instantiated the component yet so no instance exists.   Then I just gave up and had all the DBGrids to be changed to TCustDBGrid on the fly and then use the TCustDBGrid mousedown dispatcher to run when the right instance is referenced.

 

Thanks!

 

Edmund

Share this post


Link to post

In hindsight and as an anecdotal instance of losing the plot, I just realized I could have just setup a popup menu and be done with it.  ;/

 

That said,  I have learnt a bit more so that wasn't a total waste. 😜

 

Edmund

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×