Hi Folks,

In trying to build a class that consists of several controls placed on a panel, I've encountered two problems.

With the exception of a RadioGroup, I've been able to succesfully create the object and surface properties from the various controls. However, the radio buttons for the RadioGroup are defined by having their labels in the Items list, and I've been unble to come up with acceptable code to do this.

My big problem is that I have not been able to surface events from these controls. Specifically, I need the OnClick events from Buttons and the UpDown button.

Thanks,
Jon

Hi Folks,

In trying to build a class that consists of several controls placed on a panel, I've encountered two problems.

With the exception of a RadioGroup, I've been able to succesfully create the object and surface properties from the various controls. However, the radio buttons for the RadioGroup are defined by having their labels in the Items list, and I've been unble to come up with acceptable code to do this.

My big problem is that I have not been able to surface events from these controls. Specifically, I need the OnClick events from Buttons and the UpDown button.

Thanks,
Jon

Just a sample. I hoppe help you.

unit PanelControls;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls;

type
  TPanelControls = class(TPanel)
    constructor Create(AOwner :TComponent); override;
    destructor Destroy; override;
  private
    FEdit :TEdit;
    FRadioGroup :TRadioGroup;
    FButton :TButton;
  protected
    procedure SetText(value :string);
    function GetText :string;
    procedure SetItems(value :TStrings);
    function GetItems :TStrings;
    procedure SetItemIndex(value :Integer);
    function GetItemIndex :Integer;
    procedure SetOnClick(value :TNotifyEvent);
    function GetOnClick :TNotifyEvent;
  public
    { Public declarations }
  published
    property EditValue :string read GetText write SetText;
    property RadioItems :TStrings read GetItems write SetItems;
    property RadioItemIndex :Integer read GetItemIndex write SetItemIndex;
    property OnButtonClick :TNotifyEvent read GetOnClick write SetOnClick;
  end;

procedure Register;

implementation

constructor TPanelControls.Create(AOwner :TComponent);
begin
  inherited;
  Caption := '';
  Width := 8 *18;
  Height := 8 *15;
  FEdit := TEdit.Create(Self);
  FEdit.Parent := Self;
  FEdit.Top := 8;
  FEdit.Left := 8;
  FEdit.Width := 54;

  FButton := TButton.Create(Self);
  FButton.Parent := Self;
  FButton.Top := FEdit.Top;
  FButton.Left := FEdit.Left + FEdit.Width + 8;

  FRadioGroup := TRadioGroup.Create(Self);
  FRadioGroup.Parent := Self;
  FRadioGroup.Top := FEdit.Top +FEdit.Height +4;
  FRadioGroup.TabStop := True;
  FRadioGroup.Left := FEdit.Left;
  FRadioGroup.Width := 8 *16;
  FRadioGroup.Height := 3 *16;
end;

destructor TPanelControls.Destroy;
begin
  FRadioGroup.Free;
  FEdit.Free;
  FButton.Free;
  inherited;
end;

procedure TPanelControls.SetText(value :string);
begin
  if FEdit.Text <> value then
    FEdit.Text := value;
end;

function TPanelControls.GetText :string;
begin
  Result := FEdit.Text;
end;

procedure TPanelControls.SetItems(value :TStrings);
begin
  FRadioGroup.Items.Assign(value);
end;

function TPanelControls.GetItems :TStrings;
begin
  Result := FRadioGroup.Items;
end;

procedure TPanelControls.SetItemIndex(value :Integer);
begin
  if FRadioGroup.ItemIndex <> value then
    FRadioGroup.ItemIndex := value;
end;

function TPanelControls.GetItemIndex :Integer;
begin
  Result := FRadioGroup.ItemIndex;
end;

procedure TPanelControls.SetOnClick(value :TNotifyEvent);
begin
  FButton.OnClick := value;
end;

function TPanelControls.GetOnClick :TNotifyEvent;
begin
  Result := FButton.OnClick;
end;

procedure Register;
begin
  RegisterComponents('Samples', [TPanelControls]);
end;

end.

Micheus,

Thanks for the sample code. It was very helpful. However, I have a couple of problems you may be able to help with.

First, I've been unable to compile the event procedures for the UpDown button. They require a parameter for the button -- up or down. Do you have a sample of code for this?

Second, I don't understand how my event handler would work with the code you've given me. When a button is clicked, what procedure (with my event handling code) would be involked? I'm sure I'm missing the obvious here, so please excuse my ignorance.

Thanks in advance,
Jon

First, I've been unable to compile the event procedures for the UpDown button. They require a parameter for the button -- up or down. Do you have a sample of code for this?

It is very similar to others. So include into the old post:

Private
    ...
    FUpDown :TUpDown;
  Protected
    ...
    procedure SetOnUDChanging(value :TUDChangingEvent);
    function GetOnUDChanging :TUDChangingEvent;
  Published
    ...
    property OnUpDownChanging: TUDChangingEvent read GetOnUDChanging write SetOnUDChanging;
  end;

constructor TPanelControls.Create(AOwner :TComponent);
begin
  inherited;
  ...
  FEdit.Left := 8;
  FEdit.Width := 54;

  FUpDown := TUpDown.Create(Self);
  FUpDown.Parent := Self;
  FUpDown.Top := FEdit.Top;
  FUpDown.Left := FEdit.Left +FEdit.Width +4;

  FButton := TButton.Create(Self);
  FButton.Parent := Self;
  FButton.Top := FEdit.Top; 
  FButton.Left := FEdit.Left + FEdit.Width + 20;  // *** Modified
...

destructor TPanelControls.Destroy;
begin
  ...
  FEdit.Free;
  FUpDown.Free;
...

procedure TPanelControls.SetOnUDChanging(value :TUDChangingEvent);
begin
  FUpDown.OnChanging := value;
end;

function TPanelControls.GetOnUDChanging :TUDChangingEvent;
begin
  Result := FUpDown.OnChanging;
end;

procedure Register;
...

The idea is: all that property from component's child that you need to have access (out from main component) must be declared using Set/Get method.

Second, I don't understand how my event handler would work with the code you've given me. When a button is clicked, what procedure (with my event handling code) would be involked? I'm sure I'm missing the obvious here, so please excuse my ignorance.

Opss.. I'm missing the something obvious here.
I think that you don't want export some event's like Button.OnClick. So if you want process this event only into the main component there is no problem, just declare a procedure like the event handler for OnClick:

type
  TPanelControls = class(TPanel)
    ...
  private
    ...
    FUpDown :TUpDown;
    procedure BtnClick(Sender: TObject);   // ***
...
constructor TPanelControls.Create(AOwner :TComponent);
begin
  ...
  FButton.Top := FEdit.Top;
  FButton.Left := FEdit.Left + FEdit.Width + 20;
  FButton.OnClick := BtnClick;   // ***
  ...
end;
...
procedure TPanelControls.BtnClick(Sender :TObject);   // ***
begin
  ShowMessage('My buttom was pressed');
end;

procedure Register;
...

Take care if you process events into main component and exporte this event too. If user writes a event handler to it, your internal event doesn't will be called. To work by this way the code must be ajusted. Let me know about.

p.s. Sorry my poor english. I speek portuguese.

Micheus,

Sorry I took so long to acknowledge your last post. Your analysis of my problem was right on! Thanks to you, the class I was after is now working perfectly, and I've learned a few things too.

Thanks again,
Jon

Take care if you process events into main component and exporte this event too. If user writes a event handler to it, your internal event doesn't will be called. To work by this way the code must be ajusted. Let me know about.

I think is better to put this situation here. :cheesy:
Attention to "// ***" notation.

[]s

type
  TPanelControls = class(TPanel)
    ...
  private
    ...
    FOnBtnClick :TNotifyEvent;   // *** buffer to local event
    procedure BtnClick(Sender: TObject);
  published
    OnBtnClick :TNotifyEvent read FOnBtnClick write FOnBtnClick;
...
constructor TPanelControls.Create(AOwner :TComponent);
begin
  ...
  FButton.Top := FEdit.Top;
  FButton.Left := FEdit.Left + FEdit.Width + 20;
  FButton.OnClick := BtnClick;
  ...
end;
...
procedure TPanelControls.BtnClick(Sender :TObject);
begin
  if Assigned(FOnBtnClick) then   // ***
  begin
    // *** you can make some thing before or after call user event
    FOnBtnClick(Sender);  // process user button click event
  end else 
    ShowMessage('No event written to button click');
end;

procedure Register;
...
This article has been dead for over six months. Start a new discussion instead.