【问题标题】:Can a secondary TForm notify the MainForm when it is closing?辅助 TForm 可以在关闭时通知 MainForm 吗?
【发布时间】:2019-10-24 23:08:44
【问题描述】:

我正在使用 RAD Studio 10 处理 Windows VCL 应用程序。我有两个表单,Form1Unit1.cpp 中的 MainForm)和一个辅助 Form2Unit2.cpp)。我设法将Form2 嵌入到Form1 中。这只是说明问题的设置。我的真实项目有多个表单。

关闭Form2时,VCL触发Form2::OnClose()事件。知道Form2 是在Form1(主窗体)中动态创建的,是否有Form1 事件会在Form2 关闭时触发?或者Form1 里面的东西知道Form2 正在关闭?

  • 我正在考虑自定义一个像 OnChildFormClose 这样的事件处理程序,但我做不到。
  • Form2 在公共函数中关闭并在Form2::OnClose() 事件中调用时,我尝试将我想在Form1 上执行的代码包装起来,并在一定程度上起作用,但它不是如果您有多个表单,这是一种很好的方法。
//FROM THE unit1.cpp
#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include "Unit2.h"
//-----------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//-----------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//-----------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TForm2 *form2 = new TForm2(this);
form2->ManualDock(container);
form2->Show();
}
//FROM unit2.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
//-----------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//-----------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}
//-----------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
Close();
}
//-----------------------------------------------------------------------

我可以在Form1 中实现类似OtherFormsonClose(*Sender) 事件的Sender,我们可以动态转换以检查它是否是Form2,或者我错了?我将不胜感激。

【问题讨论】:

    标签: windows c++builder vcl rad-studio


    【解决方案1】:

    您可以声明TCloseEvent 类型的通用事件处理程序,例如OtherFormClose(TObject *Sender, TCloseAction &amp;Action);在主窗体中:

    private:    // User declarations
       void __fastcall TForm1::OtherFormClose(TObject *Sender, TCloseAction &Action);
    

    实现

    void __fastcall TForm1::OtherFormClose(TObject *Sender, TCloseAction &Action)
    {
      Action = caFree;
      TForm2 *f2 = dynamic_cast<TForm2 *>(Sender);
      if (f2) {
      ShowMessage(String("Form2 closing")); //Do stuff
      }
    
    }
    

    (或使用Sender查看哪个表单)

    然后当您在代码中创建其他表单时,例如Form2,你指定

      TForm2 *form2 = new TForm2(this);
      form2->OnClose = OtherFormClose;
      // etc
    

    【讨论】:

    • 谢谢,这很好,有了您的解决方案,就不会再出现消息冲突的问题了。完美:)
    【解决方案2】:

    好的,我在阅读 thisthisthisthis 后发现了一些有趣的东西。

    所以基本上,VCL Delphi/C++Builder 应用程序使用 Windows 窗体消息进行通信,我们可以重写虚函数 WndProc 来捕获特定消息,但它必须是一些独特的消息,因为 VCL 使用了很多消息,如果你不小心行事,事情可能会爆炸;这将转换为主窗体上的自定义事件处理程序。

    所以我做的是:

    • 在构造函数中将 MainForm 句柄传递给 Form2,以保存在 Form2 私有 var 中并仅用于消息传递。
    • 生成我用来标记消息以使其突出的特定 ID
    • 覆盖 WndProc 并过滤具有特定 ID 的消息,以便我们知道 Form2 正在关闭。

    测试它并且它有效,也许有人有更好的主意。

    //From unit2.h---------------------------------------------------------
    class TForm2 : public TForm
    {
    __published:    // IDE-managed Components
        TButton *Button1;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    private:    // User declarations
        HWND mfhandle;
    public:     // User declarations
        __fastcall TForm2(TComponent* Owner, HWND mainformhandle);
    
    };
    
    //From unit2.cpp---------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit2.h"
    
    #pragma package(smart_init)
    
    #pragma resource "*.dfm"
    
    TForm2 *Form2;
    const UINT uiMyCopyDataID = RegisterWindowMessage(TEXT("MyCopyDataID"));
    
    __fastcall TForm2::TForm2(TComponent* Owner,HWND mainformhandle)
        : TForm(Owner)
    {
    mfhandle = mainformhandle;
    }
    
    void __fastcall TForm2::Button1Click(TObject *Sender)
    {
    Close();
    }
    
    void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
    {
    //Notify the mainForm and say Hey I am closing now
    PostMessage(mfhandle, uiMyCopyDataID, 0, 0);
    }
    
    //From unit1.h---------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:    // IDE-managed Components
    TPanel *container;
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall FormUnDock(TObject *Sender, TControl *Client, TWinControl *NewTarget,
          bool &Allow);
    private:    // User declarations
    protected:
    void __fastcall TForm1::WndProc(TMessage &Message);  //Added THIS
    public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
    };
    
    //From unit1.cpp-------------------------------------------------------
    const UINT uiMyCopyDataID = RegisterWindowMessage(TEXT("MyCopyDataID"));
    
    void __fastcall TForm1::WndProc(TMessage &Message)
    {
        if (Message.Msg == uiMyCopyDataID)
        {
        //Do SomeThing here
        ShowMessage("Form2 is closing");
    
        }
    
        TForm::WndProc(Message);
    }
    

    好的,到目前为止它可以工作,并且自定义消息必须在 WM_USER (0x0400 - 0x7FFF) 范围内。

    【讨论】:

    • 在这种情况下使用窗口消息太过分了。
    • 嗨 Remy Lebeau 我完全同意,我对 Tom Brunberg 的反应感到非常惊讶。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 2014-02-23
    • 1970-01-01
    相关资源
    最近更新 更多