Delete non-modal form

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Delete non-modal form

Postby HsiaLin » Sun Sep 04, 2016 11:10 am

Is there a way to make a temp spawned non-modal Form delete itself in its own OnClose or Destroy events?
HsiaLin
BCBJ Master
BCBJ Master
 
Posts: 280
Joined: Sun Jul 08, 2007 6:29 pm

Re: Delete non-modal form

Postby theLizard » Sun Sep 04, 2016 3:59 pm

HsiaLin wrote:Is there a way to make a temp spawned non-modal Form delete itself in its own OnClose or Destroy events?


I am not sure what you mean by delete itself but in the OnClose event, I set Action = caFreee to release all memory allocated for the form then set the pointer to the (temp) form to NULL.

In my MDI applications I manage my own forms and do a lot of this using a FormsAgent in combination with my other components. All forms other than the m,ain form are removed from Auto-create forms in options.

Hope this helps.

Code: Select all
void __fastcall TfrmAppOptions::FormClose(TObject *Sender, TCloseAction &Action)
   {
   Action = caFree;
   frmMain->frmAppOptions = NULL;
   }


In this case, frmMain is the application MDI, it creates the temp form frmAppOptions

Code: Select all
      case fAppOptions:
         if(!frmAppOptions)
            frmAgent->LoadForm(new TfrmAppOptions(this), title, true);
         else
            frmAppOptions->BringToFront();
         break;



In frmAgent->LoadForm I have

Code: Select all
TForm* __fastcall TLFormsAgent::LoadForm(TForm* f, UnicodeString title, bool setCaption)
   {
   std::vector<TLFrmClass*>::iterator found = std::find_if(forms.begin(), forms.end(), IsTitle(title));

   if(found != forms.end())
      {
      (*found)->Form->BringToFront();
      return((*found)->Form);
      }
   else
      {
      AddForm(f, title, setCaption);
    found = std::find_if(forms.begin(), forms.end(), IsTitle(title));
      }
   if(found != forms.end())
      return((*found)->Form);
   else
      return(NULL);
   }


Code: Select all
TForm* __fastcall TLFormsAgent::AddForm(TForm* f, UnicodeString title, bool setCaption)
   {
   //insert the form f into forms array
   bool hasAgent = false;
   TLAgent *agent;
   TComponent *ctrl;

   int nextIndex = (int)forms.size();

   //does the form have a TLAgent
   for(int i = 0; i < f->ComponentCount; i++)
      {
      ctrl = f->Components[i];
      //if the form has an agent, set the FormsAgent property to this
      if((agent = dynamic_cast<TLAgent *>(ctrl)) != NULL)
         {
         hasAgent = true;
         agent->CaptionIsTitle = setCaption;
         agent->FormsAgent = this;
         break;
         }
      }

   TLFrmClass *newForm = new TLFrmClass();
   newForm->Form = f;
   if(hasAgent)
      {
      newForm->Agent = agent;
      agent->Title = title;
      newForm->Title = agent->Title;
      newForm->Agent->FormCreated = true;
      if(setCaption)
         newForm->Form->Caption = title;
      }

   newForm->IsSelected = true;
   newForm->indexOf = nextIndex;
   newForm->Title = title;

   forms.push_back(newForm);
   ActiveAgent = agent;

   if(FformsAgentFormAdded)
      FformsAgentFormAdded(this, newForm->Form, forms.size()-1);

   return(newForm->Form);
   }



Forms Agent Code

Code: Select all
#include <vcl.h>
#pragma hdrstop
// ---------------------------------------------------------------------------------
#include "TLFormsAgent.h"
#pragma package(smart_init)
// ---------------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
// ---------------------------------------------------------------------------------
static inline void ValidCtrCheck(TLFormsAgent *)
   {
   new TLFormsAgent(NULL);
   }

//---------------------------------------------------------------------------
struct IsAgent
   {
   TLAgent *AgentToFind;

   IsAgent(TLAgent *agent) : AgentToFind(agent) {}

   bool operator()(TLFrmClass *cls) const
      {
      return (cls->Agent == AgentToFind);
      }
   };
//---------------------------------------------------------------------------
struct IsMenuItem
   {
   TMenuItem *_mnuitem;

   IsMenuItem(TMenuItem *mnuitem) : _mnuitem(mnuitem) {}

   bool operator()(TLFrmClass *cls) const
      {
      return (cls->FmenuItem == _mnuitem);
      }
   };
//---------------------------------------------------------------------------
struct IsTitle
   {
   UnicodeString _title;

   IsTitle(UnicodeString title) : _title(title) {}

   bool operator()(TLFrmClass *cls) const
      {
      return (cls->Title == _title);
      }
   };
//---------------------------------------------------------------------------
struct IsFormIndex
   {
   int _index;

   IsFormIndex(int index) : _index(index) {}

   bool operator()(TLFrmClass *cls) const
      {
      return (cls->indexOf == _index);
      }
   };
//---------------------------------------------------------------------------
// -----| TLFormsAgent |----------
// ---------------------------------------------------------------------------------
__fastcall TLFormsAgent::TLFormsAgent(TComponent* Owner)
 : TComponent(Owner)
   {
   if( ComponentState.Contains(csDesigning) )
   {
   //To Do...
   }
   forms.reserve(20);
   Parent = (TForm *)Owner;
   }
// ---------------------------------------------------------------------------------
__fastcall TLFormsAgent::~TLFormsAgent()
   {
   }
// ---------------------------------------------------------------------------------
int __fastcall TLFormsAgent::getDatabaseType()
   {
   return(FdbType);
   }
// ---------------------------------------------------------------------------
void __fastcall TLFormsAgent::setDatabaseType(int value)
   {
   int i;

   for(i=0; i < forms.size(); i++)
      {
      ContainsDBControl(value, i);
      }
   }
// ---------------------------------------------------------------------------------
void __fastcall TLFormsAgent::ContainsDBControl(int dbType, int index)
   {
   int i;
   TForm *f;
   TLOdbcCon* db;

   for(i =0; i < forms[index]->Form->ComponentCount; i++)
      {
      f = static_cast<TForm*>(forms[index]->Form);
      if((db = dynamic_cast<TLOdbcCon*>(f->Components[i])) != NULL)
         db->DbType = dbType;
    }
   }
// ---------------------------------------------------------------------------------
int __fastcall TLFormsAgent::FormIndexOf(TLAgent *agent)
      {
      TLAgent *a = dynamic_cast<TLAgent*>(agent);
      if (a != NULL)
         {
         std::vector<TLFrmClass*>::iterator found = std::find_if(forms.begin(), forms.end(), IsAgent(a));
         if (found != forms.end())
            return std::distance(forms.begin(), found);
         }
      return -1;
      }
//---------------------------------------------------------------------------
TLAgent * __fastcall TLFormsAgent::getFormAgent()
   {
   return(agent);
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::setFormAgent(TLAgent * value)
   {
   if(agent != value)
      agent = value;
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::PressButton(int index, UnicodeString caption)
   {
   TLAgent *agent = NULL;
   TForm *f;

   if(index != -1)
      {
      if (index != -1)
         {
         TForm *f = GetForm(index);
         for (int i = 0; i < f->ComponentCount; ++i)
            {
            TLAgent *agent = dynamic_cast<TLAgent*>(f->Components[i]);
            if (agent != NULL)
               {
               TButton *btn = (TButton*) f->FindComponent(caption /*"bnAdd"*/);
               if (btn != NULL)
                     btn->Click();

               break;
               }
            }
         }
      }

   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::RemoveForm()
   {

   UnicodeString s;
   if(Menu != NULL)
      {
      for(int i = 0; i < Menu->Items->Count; i++)
         {
         TMenuItem *m = Menu->Items->Items[i];
         if(RemoveMenuItem(m, forms[FormIndexOf(ActiveAgent)]->Title))
            break;
         }
      }

   forms.erase(forms.begin()+ FormIndexOf(ActiveAgent));
   }
//---------------------------------------------------------------------------
bool __fastcall TLFormsAgent::RemoveMenuItem(TMenuItem *m, UnicodeString s)
   {
   bool found = false;

   for(int i = 0; i < m->Count; i++)
      {
      if(!forms[FormIndexOf(ActiveAgent)]->hasMenuItem)
         continue;

      if(StripHotkey(m->Items[i]->Caption) == StripHotkey(forms[FormIndexOf(ActiveAgent)]->MenuItem->Caption))
         {
         delete forms[FormIndexOf(ActiveAgent)]->MenuItem;
         found = true;
         break;
         }
      else
         if(m->Items[i]->Count > 0)
            RemoveMenuItem(m->Items[i], s);
      }
   return(found);
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::RemoveForm(int index)
   {
   forms.erase(forms.begin()+ index);
   }
//---------------------------------------------------------------------------
TForm * __fastcall TLFormsAgent::getForm(int index)
   {
   int size = forms.size();
   if(size != 0 && index < size)
      return(forms[index]->Form);
   return(NULL);

   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::setForm(TForm *f)
   {
   AddForm(f, "Form" + IntToStr((int)forms.size()), true);
   }
//---------------------------------------------------------------------------
TForm* __fastcall TLFormsAgent::AddForm(TForm* f, UnicodeString title, bool setCaption)
   {
   //insert the form f into forms array
   bool hasAgent = false;
   TLAgent *agent;
   TComponent *ctrl;

   int nextIndex = (int)forms.size();

   //does the form have a TLAgent
   for(int i = 0; i < f->ComponentCount; i++)
      {
      ctrl = f->Components[i];
      //if the form has an agent, set the FormsAgent property to this
      if((agent = dynamic_cast<TLAgent *>(ctrl)) != NULL)
         {
         hasAgent = true;
         agent->CaptionIsTitle = setCaption;
         agent->FormsAgent = this;
         break;
         }
      }

   TLFrmClass *newForm = new TLFrmClass();
   newForm->Form = f;
   if(hasAgent)
      {
      newForm->Agent = agent;
      agent->Title = title;
      newForm->Title = agent->Title;
      newForm->Agent->FormCreated = true;
      if(setCaption)
         newForm->Form->Caption = title;
      }

   newForm->IsSelected = true;
   newForm->indexOf = nextIndex;
   newForm->Title = title;

   forms.push_back(newForm);
   ActiveAgent = agent;

   if(FformsAgentFormAdded)
      FformsAgentFormAdded(this, newForm->Form, forms.size()-1);

   return(newForm->Form);
   }
//---------------------------------------------------------------------------
TForm* __fastcall TLFormsAgent::LoadForm(TForm* f, UnicodeString title, bool setCaption)
   {
   std::vector<TLFrmClass*>::iterator found = std::find_if(forms.begin(), forms.end(), IsTitle(title));

   if(found != forms.end())
      {
      (*found)->Form->BringToFront();
      return((*found)->Form);
      }
   else
      {
      AddForm(f, title, setCaption);
    found = std::find_if(forms.begin(), forms.end(), IsTitle(title));
      }
   if(found != forms.end())
      return((*found)->Form);
   else
      return(NULL);
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::SetFormTitle(UnicodeString title)
   {
   TLAgent *agent;
   int index = FormIndexOf(ActiveAgent);
   agent = forms[index]->Agent;
   forms[index]->Title = title;
   agent->Title = title;
   }
//---------------------------------------------------------------------------
int __fastcall TLFormsAgent::IndexOf(UnicodeString title)
   {
   int index = -1;
   std::vector<TLFrmClass*>::iterator found = NULL;
   found = std::find_if(forms.begin(), forms.end(), IsTitle(title));

   if(found != forms.end())
      index = std::distance(forms.begin(), found);

   return(index);
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::Show(int index)
   {
   forms[index]->Form->BringToFront();
   }
//---------------------------------------------------------------------------
int __fastcall TLFormsAgent::ShowForm(int index)
   {
   int i =-1;

   if(forms.size() >= index)
      {
      std::vector<TLFrmClass*>::iterator found = NULL;
      found = std::find_if(forms.begin(), forms.end(), IsTitle(forms[index]->Title));
      if(found != forms.end())
         {
         if(!(*found)->Form->Showing || !(*found)->Form->Active)
            {
            i = std::distance(forms.begin(), found);
            (*found)->Form->BringToFront();

            if((*found)->Form->WindowState == wsMinimized)
               (*found)->Form->WindowState = wsNormal;
            }
         }
      }
    return(i);
   }
//---------------------------------------------------------------------------
int __fastcall TLFormsAgent::ShowForm(UnicodeString caption)
   {

   int i = IndexOf(caption);
   if(i != -1)
      Show(i);

   return(i);
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::ShowForm(TObject* Sender)
   {
   std::vector<TLFrmClass*>::iterator found = NULL;
   found = std::find_if(forms.begin(), forms.end(), IsMenuItem(static_cast<TMenuItem*>(Sender)));

   if(found != forms.end())
      {
      (*found)->Form->BringToFront();
      if((*found)->Form->WindowState == wsMinimized)
         (*found)->Form->WindowState = wsNormal;
      }
   }
//---------------------------------------------------------------------------
UnicodeString __fastcall TLFormsAgent::GetTitle(int index) { return(forms[index]->Title); }
//---------------------------------------------------------------------------
int __fastcall TLFormsAgent::GetRecordId(int index)
   {
   TLAgent *agent;
   TForm *f;
   //get the form from array
   f = forms[index]->Form;

   for(int i = 0; i < f->ComponentCount; i++)
      {
      if(f->Components[i]->ClassName()=="TLAgent")
         {
         //can set new title
         agent = (TLAgent *)f->Components[i];
         break;
         }
      }
   return(agent->RecordId);
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::SetRecordId(int index, int id)
   {
   TLAgent *agent;
   TForm *f;
   TComponent *ctrl;
   //get the form from array
   f = forms[index]->Form;

   for(int i = 0; i < f->ComponentCount; i++)
      {
      if((agent = dynamic_cast<TLAgent *>(ctrl)) != NULL)
         {
         //can set new title
         agent->RecordId = id;
         break;
         }
      }
   }
//---------------------------------------------------------------------------
TForm * __fastcall TLFormsAgent::GetForm(int id, TLAgent *agent)
   {

   std::vector<TLFrmClass*>::iterator found = std::find_if(forms.begin(), forms.end(), IsAgent(dynamic_cast<TLAgent*>(agent)));
   if (found != forms.end() && (*found)->Agent->RecordId == id)
      return((*found)->Form);

   return(NULL);
   }
//---------------------------------------------------------------------------
TForm * __fastcall TLFormsAgent::GetForm(int index)
   {
   return(forms[index]->Form);
   }
//---------------------------------------------------------------------------
TStatusBar * __fastcall TLFormsAgent::getStatusBar() { return(sb); }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::setStatusBar(TStatusBar *value)
   {
   if(sb != value)
         sb = value;
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::Broadcast(int index, bool all)
   {

   }
//---------------------------------------------------------------------------
TForm * __fastcall TLFormsAgent::getParent() { return(parent); }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::setParent(TForm * f)
   {
   if(parent != f)
      parent = f;
   }
//---------------------------------------------------------------------------
TForm * __fastcall TLFormsAgent::LastIndexOfForm()
   {
   std::vector<TLFrmClass*>::iterator index = forms.end();
   return(GetForm(std::distance(forms.begin(), index)-1));
   }
//---------------------------------------------------------------------------
TMainMenu * __fastcall TLFormsAgent::getMenu() {return(menu);   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::setMenu(TMainMenu *value)
   {
   if(menu != value)
      menu = dynamic_cast<TMainMenu*>(value);
   }
//---------------------------------------------------------------------------
int __fastcall TLFormsAgent::FormsCount()
   {
   return(forms.size());
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::AddMenuItem(UnicodeString caption, TMenuItem * menuItem)
   {
   if(Menu)
      {
      std::vector<TLFrmClass*>::iterator found = NULL;
      found = std::find_if(forms.begin(), forms.end(), IsTitle(caption));

      if(found != forms.end())
         {
         mnuItem = new TMenuItem(Menu);
         mnuItem->Caption = caption;
         (*found)->MenuItem = mnuItem;
         (*found)->hasMenuItem = true;

         if(FmenuItemClick)
            mnuItem->OnClick = FmenuItemClick;

         menuItem->Items[0]->Add(mnuItem);
         }
      }
   }
//---------------------------------------------------------------------------
void __fastcall TLFormsAgent::MenuItemCaption(UnicodeString value, int index)
   {
   forms[index]->MenuItemCaption(value);
   }
//---------------------------------------------------------------------------
namespace Tlformsagent
   {
   void __fastcall PACKAGE Register()
   {
   TComponentClass classes[1] = {__classid(TLFormsAgent)};
   RegisterComponents(L"bcbh", classes, 0);
   }
   }

theLizard
BCBJ Master
BCBJ Master
 
Posts: 447
Joined: Wed Mar 18, 2009 2:14 pm

Re: Delete non-modal form

Postby HsiaLin » Sun Sep 04, 2016 4:49 pm

What im doing is i have a ListView on Form1 and i need Form3 to Show()... but not modally, because
i need to be able to interact with Form1 while Form3 is shown. I need to be able to delete Form3
when it closes because it has a lot of init`ing it needs to do when it creates from new.

I have currently been using ...

Form3 = new TForm3(NULL);
Form3->Show();
while(Form3->Visible)
Application->ProcessMessages()
delete Form3;

But that looks like some kind of redneck duct tape hack.
HsiaLin
BCBJ Master
BCBJ Master
 
Posts: 280
Joined: Sun Jul 08, 2007 6:29 pm

Re: Delete non-modal form

Postby theLizard » Mon Sep 05, 2016 1:08 am

HsiaLin wrote:What im doing is i have a ListView on Form1 and i need Form3 to Show()... but not modally, because
i need to be able to interact with Form1 while Form3 is shown. I need to be able to delete Form3
when it closes because it has a lot of init`ing it needs to do when it creates from new.


For MDI applications,

The way I handle this scenario is (others may have a different approach);

In the form that creates the (Form3) I would declare a TForm* frmFrm3 in the header file public: section.

Where you want to create the form, menu item or button or other I do this;


Code: Select all
if(!frmFrm3)
 {
 frmFrm3 = new TForm3(this);
 frmFrm3->Show();
 //frmFrm3->Init();
 }
else
 frmFrm3->BringToFront();
 


In the Form3 code files I declare TForm* frmOwner in it's header file private: or public: section

In the constructor of Form3 I would have

Code: Select all
frmOwner = static_cast<TForm3*>(Owner);



At this point (Form3) you will have access to any public methods and properties of the forms creator, the form that created Form3 will also have access to all public methods and properties so that you can do your Init's or call any other code you wish.

So, from the creator you would do your inits by say calling frmFrm3->Init() after it has been created then Shown.

Because you have direct access to the creator form and visa versa, you will not need to have while(Form3->Visible) or Application->ProcessMessages()

In Form3's OnClose event, Action = caFree followed by frmOwner->frmFrm3 = NULL;

This should work for you,
theLizard
BCBJ Master
BCBJ Master
 
Posts: 447
Joined: Wed Mar 18, 2009 2:14 pm

Re: Delete non-modal form

Postby HsiaLin » Mon Sep 05, 2016 6:17 am

Thanks, caFree does seem to do the trick.
HsiaLin
BCBJ Master
BCBJ Master
 
Posts: 280
Joined: Sun Jul 08, 2007 6:29 pm

Re: Delete non-modal form

Postby rlebeau » Mon Sep 05, 2016 2:29 pm

HsiaLin wrote:I have currently been using ...

Form3 = new TForm3(NULL);
Form3->Show();
while(Form3->Visible)
Application->ProcessMessages()
delete Form3;


This is absolutely the wrong thing to do, never do that! Besides, it is roughly equivilent to (and no better than) using ShowModal():

Code: Select all
Form3 = new TForm3(NULL);
Form3->ShowModal();
delete Form3;


If you want a Form to destroy itself when closed, whether shown modally or not, setting the Action parameter to caFree in the OnClose event is the correct (and documented) solution.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1408
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Delete non-modal form

Postby HsiaLin » Mon Sep 05, 2016 3:56 pm

rlebeau wrote:
HsiaLin wrote:I have currently been using ...

Form3 = new TForm3(NULL);
Form3->Show();
while(Form3->Visible)
Application->ProcessMessages()
delete Form3;


This is absolutely the wrong thing to do, never do that! Besides, it is roughly equivilent to (and no better than) using ShowModal():

Code: Select all
Form3 = new TForm3(NULL);
Form3->ShowModal();
delete Form3;


If you want a Form to destroy itself when closed, whether shown modally or not, setting the Action parameter to caFree in the OnClose event is the correct (and documented) solution.



Yeah i knew it was wrong thing to do but i need to be able to click on both forms at same time. :-)
HsiaLin
BCBJ Master
BCBJ Master
 
Posts: 280
Joined: Sun Jul 08, 2007 6:29 pm


Return to Technical

Who is online

Users browsing this forum: Google [Bot], rlebeau and 3 guests