1
votes

I am using C++Builder with a VCL Forms Application. I am trying to close a VCL Form that is docked on a TPageControl. My Close button is on a toolbar on the program's main form. My approach to do this is the three steps below: I can step through all this code but when it is done nothing happens, the form is not closed. What am I doing wrong here?

  1. When a docked form is clicked I save the form name to global variable.
  2. When the CloseButton is clicked, I use Screen->Forms[] to loop through all forms and find the correct form. Then I call the event form->OnCloseQuery.
  3. In the FormCloseQuery event I call the FormClose event.

.

void __fastcall TAboutForm::FormClick(TObject *Sender)
{
  MainForm1->LastSelectedFormName = AboutForm->Name;
}

void __fastcall TMainForm1::CloseButtonClick(TObject *Sender)
{ //Identify The Form to Delete by Name
  bool q=true;
  UnicodeString FormName="";

  int cnt = Screen->FormCount;
  for(int i=0; i<cnt; i++ )
  {
    TForm* form = Screen->Forms[i];
    FormName = form->Name;
    if(CompareText(FormName, LastSelectedFormName)==0){
      form->OnCloseQuery(form, q);  //close this form
      break;
    }
  }
}

void __fastcall TAboutForm::FormCloseQuery(TObject *Sender, bool &CanClose)
{
  int Code = Application->MessageBox(L"Close Form", L"Close Form", MB_YESNO|MB_ICONINFORMATION);

  if(Code ==IDYES){
    TCloseAction Action = caFree;
    FormClose(Sender, Action);
  }
}

void __fastcall TAboutForm::FormClose(TObject *Sender, TCloseAction &Action)
{
  Action = caFree;
}

Below is an edit after reading the answer from Spektre

Calling form->OnClose(form, MyAction); will not trigger the FormCloseQuery event. I have to call FormCloseQuery manually. The only way I could get the docked form to close is by adding, delete Sender; to the FormCloseQuery.

This does not look like a correct solution. I am very surprised Embarcadero does not have a recommended way to close a docked form. This seems like a very common action. I read the doc-wiki and can not find any solution to close a docked form.

void __fastcall TMainForm1::CloseButtonClick(TObject *Sender)
{ //Identify The Form to Delete by Name
  bool MyCanClose=true;
  UnicodeString FormName="";
  TCloseAction MyAction = caFree;
  int cnt = Screen->FormCount;

  for(int i=0; i<cnt; i++ )
  {
    TForm* form = Screen->Forms[i];
    FormName = form->Name;
    if(CompareText(FormName, LastSelectedFormName)==0){
//    form->OnClose(form,      MyAction);
      form->OnCloseQuery(form, MyCanClose);
      break;
    }
  }
}

void __fastcall TAboutForm::FormCloseQuery(TObject *Sender, bool &CanClose)
{
  int Code = Application->MessageBox(L"Close Form", L"Close Form", MB_YESNO|MB_ICONINFORMATION);

  if(Code ==IDYES){
    delete Sender;
    Sender = NULL;
  }
}
1

1 Answers

4
votes

You need to call Form->Close() instead of the Form->OnCloseQuerty() but leave the event code as is (as you want the close confirmation dialog)

  1. Form->OnCloseQuerty()

    is called by VCL you should not call it on yourself !!! It has different meaning it does not force the Form to close but it can reject the Close event if CanClose is set to false.

  2. Form->Close()

    This one force the Form to Close. But first the VCL will call the Form->OnCloseQuerty() and according to its result it either ignore the Close or proceed with it.

There are also another alternatives to do what you want. In case you just want to hide your Form you can also set its Visible property to false instead. And when want to use it again just use Show() or even ShowModal() or set its Visible to True again (it depends on if your App is MDI or not).

Another way is to create and delete the Form dynamically using new,delete. The delete of the form is forcing the Form to close regardless of Form->OnCloseQuery() result.

I sometimes combine these two methods ... And set the Visible=false and CanClose=false in OnCloseQuery() and before the App destruction delete all dynamical Forms ...