TActionList中的标准action是怎样执行的? DataSetInsert1执行时如何知道当前活动的数据集(没有设置DataSetInsert1的da

  • 主题发起人 主题发起人 gondsoft
  • 开始时间 开始时间
G

gondsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
TActionList中的标准action是怎样执行的? DataSetInsert1执行时如何知道当前活动的数据集(没有设置DataSetInsert1的dataSource)..? (100分)<br />TActionList中的标准事件是怎样处理的..?
如建立的DataSetInsert1标准事件,我并没有设置它的Datasource属性,程序运行时点击
一按钮的action属性连接此事件的按钮时,窗口活动的数据库插入一条新记录.
我想取得该事件的dataSource连接的控件,该如何做..?
下述代码失败:
if DataSetInsert1.dataSource&lt;&gt;nil then
caption:=DataSetInsert1.dataSource.name;
 
看DEMOS/RICHEDIT那个不就是用ACTIONLIST
 
DEMOS/RICHEDIT中的sample只是应用ACTIONLIST控件的用法, 我现在是讨论它的实现细节,
特别是其中的DataSet种类的Action.
 
Delphi6下的TActionList下的有关对数据集操作的TAction都有Datasource
 
在onupdate事件中判断
 
不明白说什么
 
楼上的大侠们说的都不全面啊,我也在考虑这个问题啊![:D]
 
有了一个线索, 是不是因为TDataLink类在操控..?
请各位继续~
 
试试DataSetInsert1.Dataset.dataSource
 
DELPHI 会把当前活动的窗体上的 DB控件的DataSource.DataSet 当作当前的DataSource.DataSet
来操作 除非你在action 中指定了一个DataSource
 
我遇到一个奇怪的现象, 就是
TActionList下的有关对数据集操作的TAction ,在窗体上非得有数据浏览控件
否则不可用, 但是自已控制其输入输出的形为,怎么办了
 
跟踪了一下,不好意思,拷了一大堆源码
当点击了Button1,执行到TControl.Click

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 &lt;&gt; nil) and (@FOnClick &lt;&gt;

@Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink &lt;&gt; nil) then
ActionLink.Execute(Self)
else if Assigned(FOnClick) then
FOnClick(Self);
end;

ActionLink.Execute(Self)执行到
function TBasicActionLink.Execute(AComponent: TComponent): Boolean;
begin
if FAction.ActionComponent &lt;&gt; AComponent then
begin
if Assigned(FAction.ActionComponent) then
FAction.ActionComponent.RemoveFreeNotification(FAction);
if Assigned(AComponent) then
AComponent.FreeNotification(FAction);
FAction.ActionComponent := AComponent;
end;
Result := FAction.Execute;
end;
这里主要是FAction.Execute;继续跟踪
function TCustomAction.Execute: Boolean;
begin
Result := False;
if Assigned(ActionList) and (ActionList.State &lt;&gt; asNormal) then Exit;
Update;
if Enabled and FAutoCheck then
Checked := not Checked;
Result := Enabled and inherited Execute;
end;
Update暂且不看
跟踪到
function TContainedAction.Execute: Boolean;
begin
Result := (ActionList &lt;&gt; nil) and ActionList.ExecuteAction(Self) or
Application.ExecuteAction(Self) or inherited Execute or
(SendAppMessage(CM_ACTIONEXECUTE, 0, Longint(Self)) = 1);
end;
这个是关键,
ActionList &lt;&gt; nil) and ActionList.ExecuteAction(Self) or
Application.ExecuteAction(Self) or inherited Execute
这些都是False,

SendAppMessage给Application发一个CM_ACTIONEXECUTE消息
在TApplication.WndProc里有个响应CM_ACTIONEXECUTE消息的代码
CM_ACTIONEXECUTE, CM_ACTIONUPDATE:
Message.Result := Ord(DispatchAction(Message.Msg,

TBasicAction(Message.LParam)));

就到了这里
function TApplication.DispatchAction(Msg: Longint; Action: TBasicAction):

Boolean;
var
Form: TCustomForm;
begin
Form := Screen.ActiveForm;
Result := (Form &lt;&gt; nil) and (Form.Perform(Msg, 0, Longint(Action)) = 1) or
(MainForm &lt;&gt; Form) and (MainForm &lt;&gt; nil) and
(MainForm.Perform(Msg, 0, Longint(Action)) = 1);
{ Disable action if no "user" handler is available }
if not Result and (Action is TCustomAction) and

TCustomAction(Action).Enabled and
TCustomAction(Action).DisableIfNoHandler then
TCustomAction(Action).Enabled := Assigned(Action.OnExecute);
end;

TCustomForm响应CM_ACTIONEXECUTE的代码
procedure TCustomForm.CMActionExecute(var Message: TMessage);

function ProcessExecute(Control: TControl): Boolean;
begin
Result := (Control &lt;&gt; nil) and
Control.ExecuteAction(TBasicAction(Message.LParam));
end;

function TraverseClients(Container: TWinControl): Boolean;
var
I: Integer;
Control: TControl;
begin
if Container.Showing then
for I := 0 to Container.ControlCount - 1 do
begin
Control := Container.Controls;
if Control.Visible and ProcessExecute(Control) or
(Control is TWinControl) and TraverseClients(TWinControl(Control))

then
begin
Result := True;
Exit;
end;
end;
Result := False;
end;

begin
if (csDesigning in ComponentState) or not Showing then Exit;
{ Find a target for given Command (Message.LParam). }
if ProcessExecute(ActiveControl) or ProcessExecute(Self) or
TraverseClients(Self) then
Message.Result := 1;
end;

这样当点击Button1时,就会执行TraverseClients来巡视Form上的控件,这样当到达
TDBGrid时,执行到TDBGrid.ExecuteAction
function TCustomDBGrid.ExecuteAction(Action: TBasicAction): Boolean;
begin
Result := (DataLink &lt;&gt; nil) and DataLink.ExecuteAction(Action);
end;

function TDataLink.ExecuteAction(Action: TBasicAction): Boolean;
begin
if Action.HandlesTarget(DataSource) then
begin
Action.ExecuteTarget(DataSource);
Result := True;
end
else Result := False;
end;

这样就执行了
procedure TDataSetInsert.ExecuteTarget(Target: TObject);
begin
GetDataSet(Target).Insert;
end;
这个Target即DBGrid1.DataSource;
简单的在
GetDataSet(Target).Insert;设个断点
到此处中断时,看一下Call Stack窗口,就一清二楚了
 
所以要看它的DataSource可以这样
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ActnList, DBActns, DB, DBTables, Grids, DBGrids;

type
TMyDataSetInsert = class(TDataSetInsert)
public
procedure ExecuteTarget(Target: TObject); override;
end;

TMainForm = class(TForm)
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Table1: TTable;
ActionList1: TActionList;
DataSetInsert1: TDataSetInsert;
Button1: TButton;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
MainForm: TMainForm;

implementation

{$R *.dfm}

{ TMyDataSetInsert }

procedure TMyDataSetInsert.ExecuteTarget(Target: TObject);
begin
inherited;
MainForm.Caption := TDataSource(Target).Name;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
Button1.Action := TMyDataSetInsert.Create(Self);
Button1.Caption := 'Insert';
end;

end.


所以
hugshen:
想控制自己输入的形式,需要自己写Action
只要覆盖掉
HandlesTarget
ExecuteTarget就可
然后可以用
RegisterActions
注册为标准的Action;

 
后退
顶部