问题
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