MFC: Deleting dynamically created CWnd objects - c++

Lets say in a dialog, we dynamically create a variable number of CWnds... like creating a and registering a CButton every time the user does something/
Some pseudo-code...
class CMyDlg : public CDialog
{
vector<CWnd *> windows;
void onClick()
{
CButton *pButton = new CButton(...);
//do other stuff like position it here
windows.push_back(pButton);
}
}
Do I need to explicitly delete them or will MFC do it? If I have to, would it be in the destructor as normal, or are there any special things to avoid breaking MFC... making sure I don't delete the objects while the HWNDs are still in use for example?

CButton *pButton = new CButton(...);
These are C++ objects, which needs to be deleted explicitly. (Where as Main frame windows and Views are self destructed).
You can refer the detailed answer ( by me) Destroying Window Objects

Related

Deleting Pointer to widget Qt C++

I am new with Qt and i am very confused about how widgets are deleted. I was reading a video and i wanted to show up a QProgressbar while the video frames are being read and then remove this QProgressbar when the video is loaded.
I have done it with 2 different ways:
Using Pointers
QWidget* wd = new QWidget();
QProgressBar* pB = new QProgressBar(wd);
QLabel* label = new QLabel(wd);
//setting geometry and updating the label and progressbar
wd->deleteLater();
wd->hide();
this code is written inside a class and i was assuming when the destructor of this class is called, the widget will be deleted with all of it's children but that didn't happen and everytime i run this function again a new widget is created without hiding or deleting the previous one (NOTE: i have tried to delete the label and progressbar from the widget assuming that they will disappear from inside the widget but this didn't happen "delete(pB);")
Using Objects
QWidget wd;
QProgressBar pB(&wd);
QLabel label(wd);
//setting geometry and updating the label and progressbar
wd.deleteLater();
wd.hide();
When i have run the same code but using objects instead of pointers , it has run exactly as i have wanted and everytime i run the function, the old widget is destroyed and a new one is created.
NOTE: -Also when i close the main window, in case of pointers, the widget wd still exists and the program doesn't terminate until i close them manually
- In case of Objects, when i close the main window everything is closed and the program is terminated correctly.
I need someone to explain me why is this happening and how if i am having a vector of pointers to widgets to delete all pointers inside that vector without any memory leakage
In typical C++ the rule would be "write one delete for every new". An even more advanced rule would be "probably don't write new or delete and bury that in the RIAA pattern instead". Qt changes the rule in this regard because it introduces its own memory management paradigm. It's based on parent/child relationships. QWidgets that are newed can be given a parentWidget(). When the parentWidget() is destroyed, all of its children will be destroyed. Hence, in Qt it is common practice to allocate objects on the stack with new, give them a parent, and never delete the memory yourself. The rules get more complicated with QLayout and such becomes sometimes Qt objects take ownership of widgets and sometimes they don't.
In your case, you probably don't need the deleteLater call. That posts a message to Qt's internal event loop. The message says, "Delete me when you get a chance!" If you want the class to manage wd just give it a parent of this. Then the whole parent/child tree will get deleted when your class is deleted.
It's all really simple. QObject-derived classes are just like any other C++ class, with one exception: if a QObject has children, it will delete the children in its destructor. Keep in mind that QWidget is-a QObject. If you have an instance allocated usingnew`, you must delete it, or ensure that something (a smart pointer!) does.
Of course, attempting to delete something you didn't dynamically allocate is an error, thus:
If you don't dynamically allocate a QObject, don't deleteLater or delete it.
If you don't dynamically allocate a QObject's children, make sure they are gone before the object gets destructed.
Also, don't hide widgets you're about to destruct. It's pointless.
To manage widget lifetime yourself, you should use smart pointers:
class MyClass {
QScopedPointer<QWidget> m_widget;
public:
MyClass() :
widget{new QWidget};
{
auto wd = m_widget->data();
auto pb = new QProgressBar{wd};
auto label = new QLabel{wd};
}
};
When you destroy MyClass, the scoped pointer's destructor will delete the widget instance, and its QObject::~QObject destructor will delete its children.
Of course, none of this is necessary: you should simply create the objects as direct members of the class:
class MyClass {
// The order of declaration has meaning! Parents must precede children.
QWidget m_widget;
QProgressBar m_bar{&m_widget};
QLabel m_label{&m_widget};
public:
MyClass() {}
};
Normally you'd be using a layout for the child widgets:
class MyClass {
QWidget m_widget;
QVBoxLayout m_layout{&m_widget};
QProgressBar m_bar;
QLabel m_label;
public:
MyClass() {
m_layout.addWidget(&m_bar);
m_layout.addWidget(&m_label);
}
};
When you add widgets to the layout, it reparents them to the widget the layout has been set on.
The compiler-generated destructor looks as below. You can't write such code, since the compiler-generated code will double-destroy the already destroyed objects, but let's pretend you could.
MyClass::~MyClass() {
m_label.~QLabel();
m_bar.~QProgressBar();
m_layout.~QVBoxLayout();
// At this point m_widget has no children and its `~QObject()` destructor
// won't perform any child deletions.
m_widget.~QWidget();
}

Passing CPtrList from a dialog to an MDI Frame

I have an application that builds a grid in an MDI frame from information gathered from a dialog beforehand, however multiple grids are built and I want to be able to select other grids (also built using the information gathered from the dialog) by selecting them from a combo box in the ribbon.
The combo box is populated when the MDI frame is first created, but when I try to select another grid the elements in CPtrList (Created with the dialog) has been deleted; I assume when the dialog is destroyed.
The code in CMainFrame is:
Cdialog dialog;
if (dialog.DoModal() == IDOK)
{
CFrame* pFrame;
BeginWaitCursor();
CMultiDocTemplate *pDoc = GetDocTemplate(10);
if (pDoc){
CBlankDoc* pDocument = (CBlankDoc*)pDoc->CreateNewDocument();
pDocument->SetTitle("Results");
pFrame = (CFrame*)pDoc->CreateNewFrame(pDocument, NULL);
if (pFrame)
{
pDoc->InitialUpdateFrame(pFrame, pDocument);
pFrame->m_plSplits = dialog.GetSplits();
pFrame->m_pParent = this;
pFrame->m_pMainRibbon = GetRibbonBar();
pFrame->MDIMaximize();
}
}
}
dialog.GetSplits();
looks as follows:
CPtrList* CDialog::GetSplits()
{
return &m_plSplits;
}
and
CPtrList* m_plSplits;
You return a pointer to an object that is defined inside the dialog.
If the pointer inside the CPtrList are still valid after the dialog has been destroyed you can create a copy of the pointer list. But in this case you also need to keep a list inside your frame. Currently you also save a just a pointer.
Another idea would be to create the pointer list and assign it to a smart pointer (use shared_ptr). Than you can transfer the smart pointer from the dialog and you can assign it to the frame object m_plSplits (this member must be a smart pointer too).
You have to construct this wisely and you have to determine the lifetime of the inner pointer... CPtrList doesn't destroy anything when the list gets destroyed.
Maybe just another containter would be a solution like std::list. This container can be copied.

MFC :: passing data using structure

So I have this MFC dialog program I am working with. The dialogs are written but now I am having difficulty passing data around from dialog to dialog. I have the following structure _dlgDataHandler set up in a class derived from CWinApp and have have created a "new" statement for a pointer to this type.
//.......SRK.h file
class CSRK_App : public CWinApp
{
public:
CFSB_App();
// added the following data structure for data passing withing the program
typedef struct _dlgDataHandler {
char RepetitionRadio[24];
// another member
// yet another member and so on as necessary
} *dlgDataHandlerPtr;
// extern dlgDataHandlerPtr dlgDataHandler;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSRK_App)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CSRK_App)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//....... SRK.cpp A pointer to a new dataHandler created in this block about 2/3 the way down
// CSRK_App initialization
BOOL CSRK_App::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
//SetRegistryKey(_T("Local AppWizard-Generated Aplications"));
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
//CSRK_Dlg dlg;
CDialogMain dlg("SRK - Beta"); // added 12/27 **
m_pMainWnd = &dlg;
//const char* m_pszHelpFilePath = NULL;
//free((void*)m_pszHelpFilePath);
//m_pszHelpFilePath=_tcsdup(_T("c:\SRKHelp.rtf"));
// the following line added to allocate memory for the structure
dlgDataHandlerPtr dlgDataHandler = new _dlgDataHandler;
dlg.SetWizardMode(); // added 12/27 **
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
In the dialog .cpp files, there are five, I need to be able to get data from the AFX variables "m_" and load them into this dataHandler Structure (or another one like it) so that they can be used in other dialogs and parts of the program, specifically my actual code when all the dialog data collection is done. Someone said to use AfxGetApp() so that I could have a handle on the current instance but I do not understand what they are talking about. And yes I have read about it in many forums, I just don't get it. I further realize this is probably not the best way to do it. I am trying to learn MFC/OOP with what time I have available, but for now, I am just trying to get a handle on the basic process as I can tune it later once I understand how to collect and pass simple data around.
I further don't understand how calling AfxGetApp() will help me get a handle on the members of CSRK_App. It inherited CWinApps public members but AfxGetapp() can't see what CSRK_App has... can it?
First, to explain the AfxGetApp advice you have received. There is some extra hand-waving using 'new' and a pointer, but this is basically using a global variable for the structure that holds your data. This is not the best way to do what you are trying to do. There are many pitfalls.
AfxGetApp() is an MFC call that returns a pointer to your main App class derived from CWinApp.
If you want to use that returned pointer, you need to cast it as a CSRK_App* pointer with:
CSRK_App* pApp = static_cast <CSRK_App*> ( AfxGetApp());
Then you can use pApp->dlgDataHandlerPtr->... to access the variables you need.
Now, for the pitfalls. Someone else may chime in with a reason why the 'new' and the pointer are helpful, but I do not see any advantage to this approach as compared to just having a local variable dlgDataHandler inside your CSRK_App class. That would simplify the code.
The next issue is that all your data is public in a struct. Any dialog class that can call AfxGetApp can read or write any data in that struct. You have no way to control access.
Also, all of your dialog classes must now include SRK_App.h so they know the structure, and have access to all other variables in that App class.
A cleaner, object-oriented approach would be to declare the struct (class) for the data in a separate .h file that could be included in the dialog classes. Then, you would pass a pointer/reference to this data into the constructor of the dialog classes. The dialog class would have no need to know anything about the App class.
For an even higher level of segregation, the dialog classes can be written so they only get a copy of the dlgDataHandler class passed in before calling .DoModal(), and then after the DoModal call returns with IDOK, the App class can have control over which data from the dialog gets updated into the dlgDataHandler class. The advantage of this approach is that it insures that no matter how the dialog class is programed, the user can always "Cancel" the dialog without modifying any data.

Update user dialog in MFC

I want to update a user interface when I clicked a button. However, I'm not using a direct way inside CProjectDlg. I have a CMain class which will handle the operation.
Here is my code:
ProjectDlg.cpp
void CProjectDlg::OnBnClickedButton1()
{
CMain *ptr = new CMain();
ptr->Click();
CString test = m_edit1;
}
Main.cpp
void CMain::Click()
{
CProjecttDlg *ptr = new CProjectDlg();
ptr->m_edit1.SetString(L"This is a test.");
}
In the debug mode, I found the address of m_edit1 is not same. So the function is useless.
I need to pass the same address of m_edit1 to the Click() function. How do I do that?
Thank you.
Each time you click, you create a new dialog.
CProjecttDlg *ptr = new CProjectDlg();
What you must do is to create it just once (maybe at CMain constructor? or the first time click is accessed). To store its value, just make ptr a member of CMain(define in .h, and so on) instead of a local variable.
You have a problem there. You are calling CMain::Click fron a CProjectDlg instance, but create a new instance of CProjectDlg inside CMain::Click, and set the edit box in that new dialog, not in the original one.
I don't know exactly what you are trying to do, but one thing that could work is to pass a pointer to the dialog to the CMain constructor, and then in CMain::Click use it ot set the edit box. Something like this:
//CMain.h
class CMain
{
public:
CMain(CProjectDlg*);
Click();
protected:
CProjecDlg* m_Dlg;
}
// CMain.cpp
CMain::CMain(CProjectDlg* dlg)
{
m_Dlg = dlg;
}
CMain::Click()
{
m_Dlg->m_edit1.SetString(L"This is a test.");
}
Apart from that, I don't know if it would be necessary to create a new instance of CMain every time the user clicks the bottom.
And finally, the possible solution I've provided might work, but it might also not be "correct". Without more details as to what you are trying to do, there's not much more I can help you with, though.

How do i update a control outside of a dialog?

For example, in an MFC program, I have my main application and a 'class'. What should I do if I want to update a control (say, a listbox) that is situated on my main application from that 'class'?
heres an example that worked for me
theApp.m_pMainWnd->GetDlgItem(IDC_BUTTON6)->SetWindowTextW(L"Run Auto Test");
Your class can be designed to trigger an event which your main application can listen for. Then, a listener/event handler/delegate can be called to handle the event and update the listbox. Typically, most event formats pass a reference of the sender, in this case your 'class', as well as an object containing event arguments. These arguments can be used to pass the list of items you want to add to your listbox.
If you have the handle to dialog object in your class, then you can use GetDlgItem(ResourceID) to get list control object.
The easiest approach is to expose the listview from your application form/window to the classes that use it. You can do this either by passing the listview object (or parent window) to the class constructor, or storing it in a static variable that is accessible by the class.
For better encapsulation, you can put a method in the application that the class can call, e.g. "AddItemToListBox()". This allows the application object to remain in control of how you access the listbox. Again you can do this as a static method, or pass the main program object's 'this' pointer into the class constructor.
i.e.
class CApplication
{
CListBox m_ListBox;
public:
static void CApplication::AddItemToListBox(CString itemText)
{
// Add the item as you wish here
}
}
class CMyClass
{
afx_msg void CMyClass::OnMouseDown(...)
{
CApplication::AddItemToListBox("This is a test");
}
}