OnClick event handler for control in custom component not working (Lazarus)

一个人想着一个人 提交于 2019-12-25 12:12:24

问题


Using: Lazarus 1.2.0; Windows 32-bit application

I have written a custom component derived from TPanel and it conains 4 TEdit controls. I've written the OnClick event handler code for the TEdits. However its not working at runtime ie the events are not firing. I'm not sure what I missed. Please can you tell me what I'm doing wrong?

Component code follows:

unit uEditPanel;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;

type

  { TEditPanel }

  TEditPanel = class(TCustomPanel)
    Edit0: TEdit;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;

    procedure SetEdit1OnClick(const AEvent: TNotifyEvent);
    procedure SetEdit2OnClick(const AEvent: TNotifyEvent);
    procedure SetEdit3OnClick(const AEvent: TNotifyEvent);
    procedure SetEdit4OnClick(const AEvent: TNotifyEvent);

  private
    { Private declarations }
    FEdit1OnClick: TNotifyEvent;
    FEdit2OnClick: TNotifyEvent;
    FEdit3OnClick: TNotifyEvent;
    FEdit4OnClick: TNotifyEvent;

    function GetEdit0Text: string;
    procedure SetEdit0Text(AText: string);
    function GetEdit1Text: string;
    procedure SetEdit1Text(AText: string);
    function GetEdit2Text: string;
    procedure SetEdit2Text(AText: string);
    function GetEdit3Text: string;
    procedure SetEdit3Text(AText: string);
    function GetEdit4Text: string;
    procedure SetEdit4Text(AText: string);

  protected
    { Protected declarations }
    procedure DoEdit1Click;
    procedure DoEdit2Click;
    procedure DoEdit3Click;
    procedure DoEdit4Click;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
    property Edit0Text: string read GetEdit0Text write SetEdit0Text;
    property Edit1Text: string read GetEdit1Text write SetEdit1Text;
    property Edit2Text: string read GetEdit2Text write SetEdit2Text;
    property Edit3Text: string read GetEdit3Text write SetEdit3Text;
    property Edit4Text: string read GetEdit4Text write SetEdit4Text;

    property OnEdit1Click: TNotifyEvent read FEdit1OnClick write SetEdit1OnClick;
    property OnEdit2Click: TNotifyEvent read FEdit2OnClick write SetEdit2OnClick;
    property OnEdit3Click: TNotifyEvent read FEdit3OnClick write SetEdit3OnClick;
    property OnEdit4Click: TNotifyEvent read FEdit4OnClick write SetEdit4OnClick;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Standard', [TEditPanel]);
end;

{ TEditPanel }

procedure TEditPanel.SetEdit1OnClick(const AEvent: TNotifyEvent);
begin
  FEdit1OnClick := AEvent;
end;

procedure TEditPanel.SetEdit2OnClick(const AEvent: TNotifyEvent);
begin
  FEdit2OnClick := AEvent;
end;


procedure TEditPanel.SetEdit3OnClick(const AEvent: TNotifyEvent);
begin
  FEdit3OnClick := AEvent;
end;


procedure TEditPanel.SetEdit4OnClick(const AEvent: TNotifyEvent);
begin
  FEdit4OnClick := AEvent;
end;

function TEditPanel.GetEdit0Text: string;
begin
  Result := Edit0.Text;
end;

procedure TEditPanel.SetEdit0Text(AText: string);
begin
  Edit0.Text := AText;
end;

function TEditPanel.GetEdit1Text: string;
begin
  Result := Edit1.Text;
end;

procedure TEditPanel.SetEdit1Text(AText: string);
begin
  Edit1.Text := AText;
end;

function TEditPanel.GetEdit2Text: string;
begin
  Result := Edit2.Text;
end;

procedure TEditPanel.SetEdit2Text(AText: string);
begin
  Edit2.Text := AText;
end;

function TEditPanel.GetEdit3Text: string;
begin
  Result := Edit3.Text;
end;

procedure TEditPanel.SetEdit3Text(AText: string);
begin
  Edit3.Text := AText;
end;

function TEditPanel.GetEdit4Text: string;
begin
  Result := Edit4.Text;
end;

procedure TEditPanel.SetEdit4Text(AText: string);
begin
  Edit4.Text := AText;
end;

procedure TEditPanel.DoEdit1Click;
begin
  if Assigned(FEdit1OnClick) then
    FEdit1OnClick(Self);
end;

procedure TEditPanel.DoEdit2Click;
begin
  if Assigned(FEdit2OnClick) then
    FEdit2OnClick(Self);
end;

procedure TEditPanel.DoEdit3Click;
begin
  if Assigned(FEdit3OnClick) then
    FEdit3OnClick(Self);
end;

procedure TEditPanel.DoEdit4Click;
begin
  if Assigned(FEdit4OnClick) then
    FEdit4OnClick(Self);
end;

constructor TEditPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  Edit0 := TEdit.Create(Self);
  Edit1 := TEdit.Create(Self);
  Edit2 := TEdit.Create(Self);
  Edit3 := TEdit.Create(Self);
  Edit4 := TEdit.Create(Self);

  Edit0.Parent := Self;
  Edit1.Parent := Self;
  Edit2.Parent := Self;
  Edit3.Parent := Self;
  Edit4.Parent := Self;

  Edit0.SetSubComponent(True);
  Edit1.SetSubComponent(True);
  Edit2.SetSubComponent(True);
  Edit3.SetSubComponent(True);
  Edit4.SetSubComponent(True);

  Edit1.ReadOnly := True;
  Edit2.ReadOnly := True;
  Edit3.ReadOnly := True;
  Edit4.ReadOnly := True;

  Edit1.OnClick := FEdit1OnClick;
  Edit2.OnClick := FEdit2OnClick;
  Edit3.OnClick := FEdit3OnClick;
  Edit4.OnClick := FEdit4OnClick;

  Caption := EmptyStr;
  Height := 117;
  Width := 289;
  BevelOuter := bvNone;
  ClientHeight := 117;
  ClientWidth := 289;

  Edit0.Left := 0;
  Edit0.Height := 21;
  Edit0.Top := 0;
  Edit0.Width := 288;
  Edit0.BorderStyle := bsNone;
  Edit0.TabOrder := 0;

  Edit1.Left := 0;
  Edit1.Height := 21;
  Edit1.Top := 24;
  Edit1.Width := 288;
  Edit1.BorderStyle := bsNone;
  Edit1.TabOrder := 1;
  Edit1.Font.Color := clGray;

  Edit2.Left := 0;
  Edit2.Height := 21;
  Edit2.Top := 48;
  Edit2.Width := 288;
  Edit2.BorderStyle := bsNone;
  Edit2.TabOrder := 2;
  Edit2.Font.Color := clGray;

  Edit3.Left := 0;
  Edit3.Height := 21;
  Edit3.Top := 72;
  Edit3.Width := 288;
  Edit3.BorderStyle := bsNone;
  Edit3.TabOrder := 3;
  Edit3.Font.Color := clGray;

  Edit4.Left := 0;
  Edit4.Height := 21;
  Edit4.Top := 96;
  Edit4.Width := 288;
  Edit4.BorderStyle := bsNone;
  Edit4.TabOrder := 4;
  Edit4.Font.Color := clGray;

end;



end.

At runtime my component looks like this:


回答1:


You store the events into a field but you do not set the controls event.

constructor TEditPanel.Create(AOwner: TComponent);
begin
  ...
  // Assign the current value, but is nil at this moment
  Edit1.OnClick := FEdit1OnClick;
  ...
end;

procedure TEditPanel.SetEdit1OnClick(const AEvent: TNotifyEvent);
begin
  // set a new value only to the field
  FEdit1OnClick := AEvent;
end;

There is no magic value transport from the field and the edit control event handler. You have to set the value also the the control event.


But you can access the event properties direct from the controls as you do with the Text properties.

And you should have a look at repeating code to simplify/shorten it.

unit uEditPanel;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;

type

  { TEditPanel }

  TEditPanel = class( TCustomPanel )
  private
    Edit0 : TEdit;
    Edit1 : TEdit;
    Edit2 : TEdit;
    Edit3 : TEdit;
    Edit4 : TEdit;
    { Private declarations }
    function GetEditOnClick( const Index : Integer ) : TNotifyEvent;
    function GetEditText( const Index : Integer ) : string;
    procedure SetEditOnClick( const Index : Integer; const Value : TNotifyEvent );
    procedure SetEditText( const Index : Integer; const Value : string );
    procedure InitEdit( AEdit : TEdit; ATop, ATabOrder : Integer; AReadOnly : Boolean );
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create( AOwner : TComponent ); override;
  published
    { Published declarations }
    property Edit0Text : string index 0 read GetEditText write SetEditText;
    property Edit1Text : string index 1 read GetEditText write SetEditText;
    property Edit2Text : string index 2 read GetEditText write SetEditText;
    property Edit3Text : string index 3 read GetEditText write SetEditText;
    property Edit4Text : string index 4 read GetEditText write SetEditText;

    property OnEdit1Click : TNotifyEvent index 1 read GetEditOnClick write SetEditOnClick;
    property OnEdit2Click : TNotifyEvent index 2 read GetEditOnClick write SetEditOnClick;
    property OnEdit3Click : TNotifyEvent index 3 read GetEditOnClick write SetEditOnClick;
    property OnEdit4Click : TNotifyEvent index 4 read GetEditOnClick write SetEditOnClick;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents( 'Standard', [TEditPanel] );
end;

{ TEditPanel }

function TEditPanel.GetEditOnClick( const Index : Integer ) : TNotifyEvent;
begin
  case index of
    0 :
      Result := Edit0.OnClick;
    1 :
      Result := Edit1.OnClick;
    2 :
      Result := Edit2.OnClick;
    3 :
      Result := Edit3.OnClick;
    4 :
      Result := Edit4.OnClick;
  end;
end;

function TEditPanel.GetEditText( const Index : Integer ) : string;
begin
  case index of
    0 :
      Result := Edit0.Text;
    1 :
      Result := Edit1.Text;
    2 :
      Result := Edit2.Text;
    3 :
      Result := Edit3.Text;
    4 :
      Result := Edit4.Text;
  end;
end;

procedure TEditPanel.SetEditOnClick( const Index : Integer; const Value : TNotifyEvent );
begin
  case index of
    0 :
      Edit0.OnClick := Value;
    1 :
      Edit1.OnClick := Value;
    2 :
      Edit2.OnClick := Value;
    3 :
      Edit3.OnClick := Value;
    4 :
      Edit4.OnClick := Value;
  end;
end;

procedure TEditPanel.SetEditText( const Index : Integer; const Value : string );
begin
  case index of
    0 :
      Edit0.Text := Value;
    1 :
      Edit1.Text := Value;
    2 :
      Edit2.Text := Value;
    3 :
      Edit3.Text := Value;
    4 :
      Edit4.Text := Value;
  end;
end;

procedure TEditPanel.InitEdit( AEdit : TEdit; ATop, ATabOrder : Integer; AReadOnly : Boolean );
begin
  AEdit.Parent := Self;
  AEdit.SetSubComponent( True );
  AEdit.ReadOnly := AReadOnly;
  AEdit.Left := 0;
  AEdit.Top := ATop;
  AEdit.Height := 21;
  AEdit.Width := 288;
  AEdit.BorderStyle := bsNone;
  AEdit.TabOrder := ATabOrder;
  if AReadOnly
  then
    AEdit.Color := clGray;
end;

constructor TEditPanel.Create( AOwner : TComponent );
begin
  inherited Create( AOwner );

  Caption := EmptyStr;
  Height := 117;
  Width := 289;
  BevelOuter := bvNone;
  ClientHeight := 117;
  ClientWidth := 289;

  Edit0 := TEdit.Create( Self );
  Edit1 := TEdit.Create( Self );
  Edit2 := TEdit.Create( Self );
  Edit3 := TEdit.Create( Self );
  Edit4 := TEdit.Create( Self );

  InitEdit( Edit0, 0, 0, False );
  InitEdit( Edit1, 24, 1, True );
  InitEdit( Edit2, 48, 2, True );
  InitEdit( Edit3, 72, 3, True );
  InitEdit( Edit4, 96, 4, True );
end;

end.

Your code can be written very short and will even become shorter if you manage the edit controls with an array.




回答2:


I would suggest the following approach instead. Not only does it ensure the various OnClick events work correctly, but it also consolidates all of the duplicate code for easier management:

type
  TEditPanel = class(TCustomPanel)
  private
    { Private declarations }
    FEdits: array[0..4] of TEdit;
    FEditOnClick: array[1..4] of TNotifyEvent;

    function GetEditOnClick(Index: Index): TNotifyEvent;
    procedure SetEditOnClick(Index: Index; const AEvent: TNotifyEvent);

    function GetEditText(Index: Integer): string;
    procedure SetEditText(Index: Integer; const AText: string);

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

  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;

  published
    { Published declarations }
    property Edit0Text: string read GetEditText write SetEditText index 0;
    property Edit1Text: string read GetEditText write SetEditText index 1;
    property Edit2Text: string read GetEditText write SetEditText index 2;
    property Edit3Text: string read GetEditText write SetEditText index 3;
    property Edit4Text: string read GetEditText write SetEditText index 4;

    property OnEdit1Click: TNotifyEvent read GetEditOnClick write SetEditOnClick index 1;
    property OnEdit2Click: TNotifyEvent read GetEditOnClick write SetEditOnClick index 2;
    property OnEdit3Click: TNotifyEvent read GetEditOnClick write SetEditOnClick index 3;
    property OnEdit4Click: TNotifyEvent read GetEditOnClick write SetEditOnClick index 4;
  end;

procedure TEditPanel.GetEditOnClick(Index: Integer): TNotifyEvent;
begin
  Result := FEditOnClick[Index];
end;

procedure TEditPanel.SetEditOnClick(Index: Integer; const AEvent: TNotifyEvent);
begin
  FEditOnClick[Index] := AEvent;
end;

function TEditPanel.GetEditText(Index: Integer): string;
begin
  Result := FEdits[Index].Text;
end;

procedure TEditPanel.SetEditText(Index: Integer; const AText: string);
begin
  FEdits[Index].Text := AText;
end;

procedure TEditPanel.DoEditClick(Sender: TObject);
var
  Evt: TNotifyEvent;
begin
  Evt := FEditOnClick[TEdit(Sender).Tag];
  if Assigned(Evt) then
    Evt(Self);
end;

constructor TEditPanel.Create(AOwner: TComponent);
var
  I: Integer;
begin
  inherited Create(AOwner);

  Caption := EmptyStr;
  Height := 117;
  Width := 289;
  BevelOuter := bvNone;
  ClientHeight := 117;
  ClientWidth := 289;

  for I := 0 To 4 do
  begin
    FEdits[I] := TEdit.Create(Self);
    FEdits[I].Parent := Self;    
    FEdits[I].SetSubComponent(True);
    FEdits[I].ReadOnly := True;
    FEdits[I].Left := 0;
    FEdits[I].Height := 21;
    FEdits[I].Top := 24 * I;
    FEdits[I].Width := 288;
    FEdits[I].BorderStyle := bsNone;
    FEdits[I].TabOrder := I;
    if I > 0 then
    begin
      FEdits[I].Tag := I;
      FEdits[I].Font.Color := clGray;
      FEdits[I].OnClick := DoEditClick;
    end;
  end;
end;


来源:https://stackoverflow.com/questions/23046743/onclick-event-handler-for-control-in-custom-component-not-working-lazarus

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!