Qt: QMenu seems to not be deleted after deleting MainWindow - c++

In the constructor of MainWindow i have a chunk of code:
QMenu * filemenu = this->menuBar()->addMenu(tr("File"));
QAction * openButton = new QAction(tr("Open"), this);
connect(openButton, SIGNAL(triggered()), this, SLOT(input()));
filemenu->addAction(openButton);
Everything seemed to be fine until I ran a memory check. Valgrind seems to be saying that there is a memory leak here. Shouldn’t the QMenu be automatically deleted right before MainWindow is deleted? I tried remembering the pointer to filemenu and deleting it manually in the MainWindow destructor but it didn't change anything. Does anyone have an idea what am I doing wrong?

Shouldn’t the QMenu be automatically deleted right before MainWindow is deleted?
You could connect a slot to the destroyed() signal of your QMenu instance (filemenu) and print out something there with qDebug(). If that gets printed for the mainwindow destruction that means the destructor is called, i.e. deleted.
...
connect(myMenuPointer, SIGNAL(destroyed()), receiverPointer, SLOT(test()));
...
MyClass::test()
{
qDebug() << "My menu deleted automatically";
}
Sometimes, there is memory leak detected in a Qt application by valgrind if something underneath leaks the memory like glibc and so on. It might be the case, but the answer to your question is that QMenu will be automatically deleted.

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();
}

QDialog flash back after create

I have a QListWidget on my QMainWindow, and I connect the itemDoubleClicked(QListWidgetItem*) signals to a slot like the following code:
connect(listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(popUpMyDialog(QListWidgetItem*)));
My popUpMyDialog(QListWidgetItem*) function is like:
QMyDialog *myDialog = new QMyDialog(this);
myDialog->show();
QMyDialog is a class which I inherent from QDialog, and no operation except ui->setupUi(this); was done.
But when I try to double click on the item of QListWidget, the myDialog flashed and disappear very soon.
So I had tried to write some code to judge if the myDialog is deleted like that:
QMyDialog *myDialog = new QMyDialog(this);
connect(myDialog, SIGNAL(destroyed(QObject*)), this, SLOT(handleQMyDialogClose(QObject*)));
myDialog->show();
and the slots function handleQMyDialogClose(QObject*) just do:
qDebug() << "myDialog is closed";
When I double click on the item of item of QListWidget, the console print myDialog is closed, which means the myDialog object is deleted, but I don't delete the pointer, so I feel confused.
I Googled it and tried to setModal attributes to myDialog , but it take no effect.
I tried to copy the same code to my Mac, the strange thing is that it runs perfect.
I tried to add a for loop in my popUpMyDialog(QListWidgetItem*) like that:
QMyDialog *myDialog = new QMyDialog(this);
connect(myDialog, SIGNAL(destroyed(QObject*)), this, SLOT(handleQMyDialogClose(QObject*)));
myDialog->show();
for(int i = 0; i < 100; ++i) {qDebug() << i;}
to block the thread, and find that the myDialog window work prefect, but if I comment the for loop code, it flash back again.
So, I want to know what error happened to my code, and how I can try to handle it.
My coding environment is:
Windows 10 and Mac OS X 10.10.4 Yosemite, the version of Qt is Qt5.5.0, and on my Windows , the Qt runs with mingw.
So, you have the following method:
void Foo::popUpMyDialog(QListWidgetItem*) {
QMyDialog *myDialog = new QMyDialog(this);
myDialog->show();
}
The only reason why the dialog would get prematurely destroyed is if the instance of Foo, that the dialog is a child of, got destructed.
To troubleshoot the issue, first try to create a parentless dialog:
void Foo::popUpMyDialog(QListWidgetItem*) {
QMyDialog *myDialog = new QMyDialog;
myDialog->show();
}
If that dialog remains visible, then you know that you gave it a wrong, short-lived parent. The solution would be to find another parent. To avoid leaking the dialogs, you can give the dialog a Qt::WA_DeleteOnClose attribute.
QDialog has an exec() function that "blocks" the execution (as you do with your loop), to use instead of show() so your dialog can stay visible. Isn't it what you are looking for?

Is it necessary to delete dialog window pointer in Qt?

I use this code:
MyDialog *md = new MyDialog();
md -> show();
to open a dialog window in Qt. Will md be deleted automatically when the dialog window is closed or do I need to run delete md when the window is finished?
In your little piece of code you need to delete it, because it doesn't have a parent, if you set a parent, the parent will delete it's children and you only need to delete the "main-window" (the window that doesn't have a parent).
Also for QWidget derived classes you can use the: Qt::WA_DeleteOnClose flag and then the memory will be deallocated when the widget closes, see the documentation here
Then code will become:
MyDialog *md = new MyDialog();
md->setAttribute(Qt::WA_DeleteOnClose);
md->show();
Yes. Unless you pass this while this is a QWidget or any other QWidget:
MyDialog *md = new MyDialog(this);
md->show();
you need to:
delete md;
at some point in order to release its memory. Also you need to make sure in this case that the object tree is well linked. What you can also do is call setAttribute(Qt::WA_DeleteOnClose); on md so that when you close the dialog, its memory will also be released as Zlatomir said. However if you need md to live after it was closed setAttribute(Qt::WA_DeleteOnClose); is not an option. This is also dangerous and could lead to access violation/segmentation fault if you are not careful.

New window doesn't show

I have a button, when it is clicked a new window show with a QLineEdit, and a QLabel on it, my connection between the button and the function works fine, but the new window doesn't show.
void windowManager::addQuestionDialog(){
QWidget window(&parent);
QLineEdit question;
QLabel label;
QVBoxLayout layout;
layout.addWidget(&question);
layout.addWidget(&label);
window.setLayout(&layout);
window.resize(200,200);
window.setWindowTitle(QObject::trUtf8("Kérdés bevitele..."));
window.show();
}
You need to create class tag variables for the new window and the stuff you want to put into it, than create the objects themselves with the new keyword in the function, because if you create all of these simply in a function, than they will created in the stack, and you should know that after a function returns/finishes, the stack to that function is deleted (with your new window and the stuff on it too).
Include the headers for the classes you want to use in your windowManager header file:
#include <QDialog>
#include <QLineEdit>
#include <QLabel>
#include <QVBoxLayout>
Then add the tag variables to the private part:
private:
QDialog *window;
QLineEdit *question;
QLabel *label;
QVBoxLayout *layout;
In your button's click event set the tag variables, and create the UI setup:
void windowManager::addQuestionDialog()
{
window = new QDialog();
question = new QLineEdit();
label = new QLabel();
layout = new QVBoxLayout();
layout->addWidget(question);
layout->addWidget(label);
window->setLayout(layout);
window->resize(200,200);
window->setWindowTitle(QObject::trUtf8("Kérdés bevitele..."));
window->show();
}
Also don't forget that you should use -> instead of . for calling functions here, because these tag variables are pointers. Also that's the reason why you don't need to use the & operator to get their address.
Also keep in mind that you should delete these objects, because C++ doesn't delete these automatically for you. You should delete everything you new. A good place to do this is in the destructor in your windowManager class. Just check if the tag variables are not NULL (if there is an object) before you try to delete them, otherwise errors may occur.
A better solution is to pass a parent pointer as the constructor's parameter, so this way Qt will delete them as they are closed, because if the parent is destroyed, the children will be destroyed too.
As an extra, you don't have to set manually where does the objects are go, because Qt will now it from the hierarchy (in some cases).
In this case your button's click event function would look like this:
void windowManager::addQuestionDialog()
{
window = new QDialog(this);
question = new QLineEdit(window);
label = new QLabel(window);
layout = new QVBoxLayout(window);
//The following two lines are optional, but if you don't add them, the dialog will look different.
layout->addWidget(question);
layout->addWidget(label);
window->resize(200,200);
window->setWindowTitle(QObject::trUtf8("Kérdés bevitele..."));
window->show();
}
You create the window QWidget object on the stack. Therefore, this object will be deleted when the call to the function addQuestionDialog finishes. Change the code to create the new window widget using "new", and arrange it to be deleted after it was closed. Some possible solutions are presented here:
destructors in Qt4

Qt memory management

Consider the following snippet code:
1: QPushButton *p_Button = new QPushButton(this);
2: QPushButton myButton(this);
Line 1: this is referred to QWidget, so p_Button is child of QWidget in my example: when QWidget dies (goes out the scope??) his destructor deletes p_Button from the heap and calls the destructor of p_Button.
Line 2: Same as Line 1, but does the destructor of QWidget delete myButton since its child is also myButton?
Please correct me if I stated something wrong and reply to my questions.
Yes and yes. If a QObject is not created by new, it must be destroyed before its parent. Otherwise, the parent will delete the child and the program may crash.
Qt has some good documentation on object trees and ownership that explains this.