Может ли вторичная TForm уведомлять MainForm, когда она закрывается? - PullRequest
0 голосов
/ 10 июня 2019

Я использую RAD Studio 10 для работы с приложением Windows VCL. У меня есть две формы, Form1 (MainForm в Unit1.cpp) и вторичная Form2Unit2.cpp). Мне удалось вставить Form2 внутрь Form1. Это просто установка, чтобы проиллюстрировать проблему. В моем реальном проекте несколько форм.

При закрытии Form2 VCL запускает событие Form2::OnClose(). Зная, что Form2 был создан динамически в Form1 (MainForm), есть ли событие Form1, которое сработает при закрытии Form2? Или что-то внутри Form1, чтобы знать, что Form2 закрывается?

  • Я думал о настройке обработчика событий, например OnChildFormClose, но не смог сделать это.
  • Я попытался обернуть код, который я хотел выполнить на Form1, когда Form2 закрыт в публичной функции, и вызвать его в событии Form2::OnClose(), и это сработало в некоторой степени, но это не хороший подход, если у вас есть несколько форм.
//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();
}
//-----------------------------------------------------------------------

Могу ли я реализовать что-то вроде OtherFormsonClose(*Sender) события в Form1 с Sender, которое мы можем динамически привести, чтобы проверить, является ли оно Form2, или, возможно, я ошибаюсь? Буду признателен за некоторые рекомендации.

Ответы [ 2 ]

3 голосов
/ 10 июня 2019

Вы можете объявить общий обработчик событий типа TCloseEvent, например, OtherFormClose(TObject *Sender, TCloseAction &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
0 голосов
/ 10 июня 2019

Хорошо. После прочтения это , это , это и это , я нашел кое-что интересное.

Таким образом, в основном приложение VCL Delphi / C ++ Builder использует сообщения форм Windows для сообщения, и мы можем переопределить виртуальную функцию WndProc, чтобы перехватить определенное сообщение, но это должно быть какое-то уникальное сообщение, потому что VCL использует много сообщений, и если вы не будете действовать осторожно, все может взорваться; Это преобразуется в пользовательский обработчик событий в главной форме.

Итак, что я сделал:

  • Передал дескриптор MainForm в Form2 в конструкторе, чтобы сохранить его в закрытой переменной Form2 и использовать только для обмена сообщениями.
  • Создать конкретный идентификатор, который я использую, чтобы пометить сообщение, чтобы оно выделялось
  • переопределяя WndProc и фильтруя сообщения с определенным идентификатором, чтобы мы знали, что 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).

...