procedure TControl.Click;
begin
{ Call OnClick if assigned and not equal to associated action's OnExecute.
If associated action's OnExecute assigned then call it, otherwise, call
OnClick. }
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute
else if Assigned(FOnClick) then
FOnClick(Self);
end;
//这段代码是什么意思呀
begin
{ Call OnClick if assigned and not equal to associated action's OnExecute.
If associated action's OnExecute assigned then call it, otherwise, call
OnClick. }
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute
else if Assigned(FOnClick) then
FOnClick(Self);
end;
//这段代码是什么意思呀
csDesigning The component is in a form being manipulated by the form designer.
csDestroying The component is about to be destroyed.
csFixups The component is linked to a component in another form that has not yet been loaded. This flag is cleared when all pending fixups are resolved.
csFreeNotification One or more other components have requested that this component notify them when it is destroyed. This flag is set when another component calls this component抯 FreeNotification method.csInline The component is a top-level component that can be modified at design time and also embedded in a form. This flag is used to identify nested frames while loading and saving.
csLoading A filer object is currently loading the component. This flag is set when the component is first created and not cleared until the component and all its children are fully loaded (when the Loaded method is called).
csReading The component is reading its property values from a stream. Note that the csLoading flag is always set as well when csReading is set. That is, csReading is set for the subinterval of the time when a component is loading that covers reading in property values.csUpdating The component is being updated to reflect changes in an ancestor form. Only set if csAncestor is also set.
csWriting The component is writing its property values to a stream.
csDesignInstance The component is the root object in a designer. For example, it is set for a frame when you are designing it, but not on a frame that acts like a component. This flag always appears with csDesigning.
begin
{ Call OnClick if assigned and not equal to associated action's OnExecute.
If associated action's OnExecute assigned then call it, otherwise, call
OnClick. }
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then//如果FOnClick已被赋值,并且Action属性不为空,并且FOnClick不等于Action组件的OnExecute,则
FOnClick(Self)//触发OnClick事件
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then//否则,如果控件不处在设计时刻,并且ActionLink属性不为空,则
ActionLink.Execute//触发Action组件的OnExecute事件
else if Assigned(FOnClick) then//其他情况,只要FOnClick存在,则
FOnClick(Self);//触发OnClick事件
end;
(Action <> nil) 判断有没有挂接一个Action。
(@FOnClick <> @Action.OnExecute) 判断组件的OnClick是不是挂接了Action的OnExecute事件。
csDesigning in ComponentState 判断组件是不是处于设计期。由此可以看出事件句柄的执行顺序。说实话,我对这几句也没有理解透彻。
我来研究一下在接帖。
Action.OnExecute和ActionLink.Execute有什么联系和区别?
我觉得这段代码好乱,是不是应该反过来写?
现在牵涉到四个:
组件本身的OnClick,
ActionList的OnExecute,
Action的OnExecute,
ActionLink的Execute。我发现组件本身的OnClick,优先级是最高的,然后是ActionList的OnExecute(它和ActionLink的Execute有什么区别?),最后才是Action的OnExecute。还有:当点一下按钮后,delphi会两次调用TControl.Click;
这表示如果不在设计期以下代码才执行,即运行期才执行
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ActnList, StdCtrls;type
TMainForm = class(TForm)
ActionList1: TActionList;
Action1: TAction;
Button1: TButton;
procedure Action1Execute(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
MainForm: TMainForm;implementation{$R *.dfm}procedure TMainForm.Action1Execute(Sender: TObject);
begin
ShowMessage('Action1Execute');
end;procedure TMainForm.Button1Click(Sender: TObject);
begin
ShowMessage('Button1Click');
end;end.先把Button1.OnClick设为Button1Click,action不设置
点按钮procedure TControl.Click;
begin
{ Call OnClick if assigned and not equal to associated action's OnExecute.
If associated action's OnExecute assigned then call it, otherwise, call
OnClick. }
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute(Self)
else if Assigned(FOnClick) then
FOnClick(Self);
end;
那么执行到
else if Assigned(FOnClick) then
FOnClick(Self);
接着在把action与Action1关联上,Button.OnClick为Button1Click,点按钮
执行的是 if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
也就是ylmg说的当一个按钮有OnClick事件句柄和Action,以执行OnClick为先把按扭的OnClick事件删掉,只剩下Action,点按钮,执行的是
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute(Self)
因为按钮有Action,所以ActionLink不为nil,
可以从下面看到
procedure TControl.SetAction(Value: TBasicAction);
begin
if Value = nil then
begin
ActionLink.Free;
ActionLink := nil;
Exclude(FControlStyle, csActionClient);
end
else
begin
Include(FControlStyle, csActionClient);
if ActionLink = nil then
ActionLink := GetActionLinkClass.Create(Self);
ActionLink.Action := Value;
ActionLink.OnChange := DoActionChange;
ActionChange(Value, csLoading in Value.ComponentState);
Value.FreeNotification(Self);
end;
end;
而且是运行时即 not (csDesigning in ComponentState)
执行ActionLink.Execute,也就执行Action1.OnExecute,具体可以在跟下去
这个就是保证当Button的Action设为Action1而OnClick没有事件句柄时
而执行到Action1.OnExecute