用于自定义组件中的控件的OnClick事件处理程序不起作用(Lazarus)

时间:2014-04-13 18:36:14

标签: delphi custom-component lazarus

使用:Lazarus 1.2.0; Windows 32位应用程序

我编写了一个从TPanel派生的自定义组件,它拥有4个TEdit控件。我已经为TEdits编写了OnClick事件处理程序代码。但是它不能在运行时工作,即事件不会触发。我不确定我错过了什么。请你告诉我我做错了什么?

组件代码如下:

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.

在运行时,我的组件如下所示:

enter image description here

2 个答案:

答案 0 :(得分:2)

我建议采用以下方法。它不仅可以确保各种OnClick事件正常工作,还可以整合所有重复的代码,以便于管理:

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;

答案 1 :(得分:1)

您将事件存储到字段中,但不设置控件事件。

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;

字段和编辑控件事件处理程序没有魔术值传输。您还必须将值设置为控件事件。


但您可以直接从控件访问事件属性,就像使用Text属性一样。

你应该看一下重复代码来简化/缩短它。

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.

如果使用数组管理编辑控件,您的代码可以写得非常短,甚至会变短。