• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 231
  • Last Modified:

OnClick for button in a component

I have a component derived from TStringGrid that dynamically creates a button which appears in the top left corner of the string grid.

How/Where do I put the code that I want to be executed when the button is clicked?
0
zebada
Asked:
zebada
  • 3
  • 3
  • 2
  • +1
1 Solution
 
intheCommented:
hi:
this was for a menu created at runtime but the same aplies for a button:

just set the OnClick property of Item to a TNotifyEvent. For instance:
{public}
Procedure TMyForm.ClickItem(Sender:TObject);

.....
implementation


//event handler
 
Procedure TMyForm.ClickItem(Sender:TObject);
begin
showmessage('menu item clicked');
end;


var item:TMenuItem;
begin
item:=TmenuItem.create(nil);
item.caption='test';
Item.OnClick := ClickItem;
form1.new1.add(item);


happy programming
Regards Barry
0
 
kretzschmarCommented:
hi barry,

i don't think that this it is, what zebada wanted, because itds a component-builing question.

hi zebada,
i guess u must first create a property in your published area like OnButtonClick, then in the procedure where you detect, if the button is clicked do simple use

if assigned(OnButtonClick) then OnButtonClick(Self);

or do you have a problem to detect, if the button was clicked?

meikl
0
 
intheCommented:
oh i may have read that wrong sorry :-)
is it somethng like this what zeabda needs (a button on a panel example follows:)

TMyComponent = class(TPanel)
  SubButton : TButton;
private
  procedure fSetButtonClick(Value : TNotifyEvent);
  function  fGetButtonClick :TNotifyEvent;
  <yadayada>
published
  property OnButtonClick : TNotifyEvent read fGetButtonClick write fSetButtonClick;
end.
 
implementation
 
procedure TMyComponent.fSetButtonClick(Value : TNotifyEvent);
begin
  SubButton.OnClick := Value;
end;
 
function TMyComponent.fGetButtonClick : TNotifyEvent;
begin
  Result := SubButton.OnClick;
end;
 
 
With these changes, the button should call whatever event handler was assigned to the OnButtonClick event in the object inspector.
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
kretzschmarCommented:
yup, much better, barry ;-)
0
 
intheCommented:
its early and im tired so eyes half closed , now time for some sleep :-))
0
 
zebadaAuthor Commented:
Thanks Meikl and Barry,

But the problem is not so much how do I handle the event etc... but how do I handle the event when the component is derived from **TStringGrid**.

I can do exactly what I want when I have a TCustomControl as the base class of my component.

It just doesn't work for a TStringGrid.

What I have now done to "solve" the problem is created a component based on a TCustomControl that in turns creates BOTH a TstringGrid AND a button. Everything works fine.

Do you know what might be the problem when I try to do it with TStringGrid as the base class for my component?

Cheers
Paul
0
 
synatureCommented:
In the declaration you will need:

MyComp = class(tstringgrid)
private
....
  fbutton : tbutton;
....
  fonClickTheButton : tnotifyEvent;
....
protected
  Procedure HandleButtonClick(sender : tobject);
....
public
....
  Property OnClickTheButton : TnotifyEvent read fOnClickTheButton write fOnClickTheButton;
....
end;

Now, to hook things together, two more items.  In the implementation of HandleButtonClick, you do the

// pre event code you write, if desired
If assigned(fOnClickTheButton) then fOnClickTheButton(sender);
// post even code you write, if desired


Then, in your create method you surface or expose the button's onclick event:

  fButton.Click := HandleButtonClick;

That's it!  When an end user clicks the button, the code in HandleButtonClick will be fired.  If the user has written a handler off the property, it will be fired, and, in any case, any extra code you have put in the HandleButtonClick method will fire.

I hope this is clear.  It took me a while to get clear on this, but once you see how these parts come together, it will open your eyes.



0
 
zebadaAuthor Commented:
Hi Synature,

I really appreciate the reply but I still can't make it work....

I had to change:
> fButton.Click := HandleButtonClick;
to
> fButton.OnClick := HandleButtonClick;
I hope that's how its meant to be.

But the OnClick event (the ShowMessage('heelo') )never seems to get executed.

Help! what am I doing wrong.

By the way what I said previously:
> What I have now done to "solve" the
> problem is created a component based
> on a TCustomControl that in turns
> creates BOTH a TstringGrid AND a
> button. Everything works fine.
still stands. However I would still like to know how to do it the way you are suggesting.


Here's my code:

-----------------------------------
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, StringGrid1;

type
  TForm1 = class(TForm)
    StringGrid11: TStringGrid1;
    procedure StringGrid11ClickTheButton(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.StringGrid11ClickTheButton(Sender: TObject);
begin
  ShowMessage('Hello');
end;

end.

-----------------------------------
unit StringGrid1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, StdCtrls;

type
  TStringGrid1 = class(TStringGrid)
  private
    { Private declarations }
    Fbutton: TButton;
    FOnClickTheButton: TNotifyEvent;

  protected
    { Protected declarations }
    procedure HandleButtonClick(Sender: TObject);

  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
    property OnClickTheButton: TNotifyEvent read FOnClickTheButton write FOnClickTheButton;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('My Stuff', [TStringGrid1]);
end;

{ TStringGrid1 }

procedure TStringGrid1.HandleButtonClick(Sender: TObject);
begin
  If Assigned(FOnClickTheButton) then
    FOnClickTheButton(Sender);
end;

constructor TStringGrid1.Create(AOwner: TComponent);
begin
  inherited;
  FButton := TButton.Create(self);
  FButton.Parent := self;
  FButton.Left := 0;
  FButton.Top := 0;
  FButton.Width := 80;
  FButton.Height := 20;

  FButton.OnClick := HandleButtonClick;
end;

destructor TStringGrid1.Destroy;
begin
  FButton.Free;
  inherited;
end;

end.
-----------------------------------

0
 
synatureCommented:
This may not be the answer you want, but the problem is with TStringGrid.  If you substitute tpanel for TstringGrid in the class declaration above, it'll work just fine.  

I've run into this before, just didn't realize it applied to stringgrids also.  My usual tactic is to simply make TCustomPanel my ancestor, and in your case, put a stringgrid and a button on the panel.

The root of the problem is probably in the createParams method of TCustomGrid.  Here's the help file entry for that proc in TCustomGrid:

<<procedure CreateParams(var Params: TCreateParams); override;
Description
The CreateWnd method is called internally to specify the properties of the window that implements this control. These properties are set in the window-creation parameter record passed as Params. The fields of this record become the parameters to a call to the CreateWindowEx API function.

After calling the inherited method, CreateParams adjusts the value of Params to request that the grid receive double click messages, and to implement the values of the Ctrl3D, ScrollBars, and BorderStyle properties.
>>

In contrast, the help file entry for the same proc for TCustomPanel only mentions BorderStyle.  You could override the Tstringgrid.createparams for your component so that it will allow the click to be handled by a contained component, but this might produce unwanted side effects in other aspects of the grid's behavior.  In any case, in order to use CreateParams effectively you need to find a Windows API book that is understandable by humans.


Your solution of using TCustomControl for the ancestor is a good way to go.  The only reason I would use TCusomPanel is that this gives me align and borders already present.

0
 
zebadaAuthor Commented:
Thanks Synature, I might just change it to use TCustomPanel instead of TCustomControl :)

0

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 3
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now