2009-08-26 55 views
0

我仍在使用我的本地模式对话框(LMD)。有关更多信息,请参阅this question。对于简单的情况,它现在可以正常工作,但是有时在我想要通知调用者的对话框中有结果。由于调用与Show()是异步的,我不能简单地在调用后获得结果。如何将一个或多个值返回给我的事件方法?

所以我的问题是如何返回一个或多个值从方法TLMD_Dialog.btnOkClick方法TModule.myEvent?

我参与这个3个单元: (请注意,TLMD_Dialog从TAttracsForm继承)

// Module.pas 
procedure myEvent(Sender: TObject); 

procedure TModule.btnCallDlg(Sender: TObject); 
begin 
    if Supports(lhaHandle.CurrentBoldObject, IObject, vMyObject) then 
    TModalDialog.Execute(param1, param2, myEvent); 
end; 

procedure TModule.myEvent(Sender: TObject); 
begin 
    // Some code that react on result of the LMD dialog 
end; 

// AttracsForm.pas 
type 
    TAttracsForm = class(TForm) 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    private 
    fCallerForm: TForm;  // May be replaced by check PopupParent but a separate variable may be safer 
    fOnAfterDestruction: TNotifyEvent; 
    published 
    procedure ShowLocalModal(aNotifyAfterClose: TNotifyEvent=nil); 
    end; 

procedure TAttracsForm.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    if Assigned(fCallerForm) then  // fCallerForm not assinged means that ShowLocalModal is not called. The old way to show dialog is used 
    begin 
    ClientMainForm.ViewManager.UnLockCurrentView(fCallerForm as TChildTemplate); 

    if Assigned(OnAfterDestruction) then 
     OnAfterDestruction(Self); 

    Action := caFree; 
    end; 
end; 

{ Call to make a dialog modal per module. 
    Limitation is that the creator of the module must be a TChildtemplate. 
    Several modal dialogs cannot be stacked with this method.} 
procedure TAttracsForm.ShowLocalModal(aNotifyAfterClose: TNotifyEvent); 
begin 
    fCallerForm := ClientMainForm.ViewManager.LockCurrentView; // Lock current module and return it 
    PopupParent := fCallerForm; 
    OnAfterDestruction := aNotifyAfterClose; 
    Show; 
end; 

// LMD_Dialog.pas (inherit from TAttracsForm) 
class procedure Execute(aParam: IBoldObject; aNotifyEvent: TNotifyEvent); 
class procedure TLMD_Dialog.Execute(aParam: IBoldObject; aNotifyEvent: TNotifyEvent); 
begin 
    with Self.Create(nil) do 
    begin 
    // Do preparation 
    ShowLocalModal(aNotifyEvent); 
    end; 
end; 

procedure TLMD_Dialog.btnOkClick(Sender: TObject); 
begin 
    // Do something before close down 
    // Set Result of the dialog 
    Close; 
end; 
+1

您不应该将其称为本地模式对话框,而是窗口模式或表单模式对话框(与系统模式或任务模式对话框)。 – mghie 2009-08-26 06:45:53

+0

嗯,也许我发明了一些自己的词汇,但对我来说,模式对话框通过调用ShowModal来锁定底层GUI。我们的想法是只锁定应用程序的本地部分,在这种情况下是模块。然后表达本地模态。 – 2009-08-26 10:22:49

回答

1

我要做偶尔,就是添加一个事件基类(在你的案件的形式),如:

//untested code, no doubt there are errors in it, it's the idea I want to pass 

type 
    TEventData = class(TObject) 
    public 
    property SomeCommonFieldForAncestorAndDescendants: String; 
    end; 

    TSomeBaseEvent = procedure (ASender: TObject; AEventData: TEventData) of object; 

    TSomeBaseClassOrForm = class(TForm) 
    protected 
    FSomeEventData: TEventData; 

    function GiveSomeDataClass: TClass; virtual; 
    procedure DoOnSomeThing; virtual; 
    public 
    constructor Create; override; 

    property OnSomething: TSomeBaseEvent; 
    end; 

现在你可以让构造函数实例化一个TEventData或后代BIJ调用GiveSomeDataClass.Create;你的后代只需要重写GiveSomeDataClass并返回它想要使用的TEventData的后代。现在,您有一个在祖先中声明的事件,返回一个发件人和一个数据对象,而后者可能会因其包含的数据类型而异。处理程序现在可以使用if(AEventData是TEventSpecialData)并相应地执行操作。在调用DoOnSomething之前,您可以设置FSomeEventData的值,即使在后代中的DoOnSomeThing覆盖中,也是如此。 ;-)

可选:您可以将event-data设置为公共属性,并使用来自常规事件的发件人从处理程序步入此属性。

2

这真的很简单,你不使用TNotifyEvent,但自定义事件类型与信息附加参数你想回来。

用于获取文件名和另一个参数(例如一个ZIP文件的名称和它的压缩级别一个简单的例子:

type 
    TReturnSaveZipFileDataEvent = procedure(Sender: TObject; 
    const AFileName: string; ACompressionLevel: Cardinal) of object; 

现在,而不是宣布你Execute()方法是最后的参数键入TNotifyEvent你声明它有你的特殊事件类型

请注意,恕我直言,更好的方式来实现这样的功能将使用接口。自定义接口传递到对话框,它可以使用它做不止只需回调结果即可。例如,界面可能会有一些问题er方法来检查输入数据的有效性,对话框将在OnCloseQuery处理程序中调用该数据。

+0

感谢您的快速回答! 但这意味着我不能在TAttracsForm中重用我的FormClose方法? 我必须在TLMD_Dialog中重写此内容并使用您描述的自定义事件。 关于我没有经验的接口如何使用它。我必须研究如何使用它们。 – 2009-08-26 07:37:14

+0

好吧,你可以在'TAttracsForm'中制作一个受保护的方法,它执行你当前的处理程序所做的事情,以及你从后代类中的事件处理程序中调用的方法。然后它只是添加一行。基类不需要为处理程序本身提供实现。 – mghie 2009-08-26 07:54:39