I'm very confused about using destructors in Qt4 and hope, you guys can help me.
When I have a method like this (with "Des" is a class):
void Widget::create() {
Des *test = new Des;
test->show();
}
how can I make sure that this widget is going to be deleted after it was closed?
And in class "Des" i have this:
Des::Des()
{
QPushButton *push = new QPushButton("neu");
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(push);
setLayout(layout);
}
where and how do I have to delete *push and *layout? what should be in the destructor Des::~Des() ?
Qt uses what they call object trees and it's a bit different from the typical RAII approach.
The QObject class constructor takes a pointer to a parent QObject. When that parent QObject is destructed, its children will be destroyed as well. This is a pretty prevalent pattern throughout Qt's classes and you'll notice a lot of constructors accept a *parent parameter.
If you look at some of the Qt example programs you'll find that they actually construct most Qt objects on the heap and take advantage of this object tree to handle destruction. I personally found this strategy useful as well, as GUI objects can have peculiar lifetimes.
Qt provides no additional guarantees beyond standard C++ if you're not using QObject or a subclass of QObject (such as QWidget).
In your particular example there's no guarantee that anything gets deleted.
You'll want something like this for Des (assuming Des is a subclass of QWidget):
class Des : public QWidget
{
Q_OBJECT
public:
Des(QWidget* parent)
: QWidget(parent)
{
QPushButton* push = new QPushButton("neu");
QHBoxLayout* layout = new QHBoxLayout(this);
layout->addWidget(push); // this re-parents push so layout
// is the parent of push
setLayout(layout);
}
~Des()
{
// empty, since when Des is destroyed, all its children (in Qt terms)
// will be destroyed as well
}
}
And you'd use class Des like so:
int someFunction()
{
// on the heap
Des* test = new Des(parent); // where parent is a QWidget*
test->show();
...
// test will be destroyed when its parent is destroyed
// or on the stack
Des foo(0);
foo.show();
...
// foo will fall out of scope and get deleted
}
Another option to using deleteLater(), or parents, is to use the delete-on-close functionality for widgets. In this case, Qt will delete the widget when it is done being displayed.
Des *test = new Des;
test->setAttribute( Qt::WA_DeleteOnClose );
test->show();
I like to use it with the object tree that Qt keeps, so that I set delete-on-close for the window, and all widgets in the window have a proper parent specified, so they all get deleted as well.
Richardwb's answer is a good one - but the other approach is to use the deleteLater slot, like so:
Des *test = new Des;
test->show();
connect(test, SIGNAL(closed()), test, SLOT(deleteLater()));
Obviously the closed() signal can be replaced with whatever signal you want.
This tutorial suggests you don't need to explicitly delete widgets that have been added to parent widgets. It also says it doesn't hurt to do delete them either.
(I've not tested this, but I guess as long as you explicitly delete them before the parent widget is deleted, this should be OK.)
In most cases you should create widgets on the stack:
QPushButton push("neu");
This way, they get deleted when they become out of scope. If you really want to create them on the heap, then it's your responsibility to call delete on them when they are not needed anymore.
Related
I have just started to learn QT. Can't understand how do theese constructors work. For example:
//Progress.h
#include<QtWidgets>
class QProgressBar;
class Progress:public QWidget{
Q_OBJECT
private:
QProgressBar* m_pprb;
int step;
public:
Progress(QWidget* pobj=0);
public slots:
void slotStep();
void slotReset();
//
//Progress.cpp
#include<QtWidgets>
#include"Progress.h"
Progress::Progress(QWidget* pwgt/*=0*/):QWidget(pwgt)
{
//some buttons
}
So, the question is, what happens in constructors?
What you are creating is a Progressclass which inherits from QWidget.
The QWidget class can take an parentargument, if you look at the documentation:
Constructs a widget which is a child of parent, with widget flags set to f. If parent is nullptr, the new widget becomes a window. If parent is another widget, this widget becomes a child window inside parent. The new widget is deleted when its parent is deleted.
This parentin your code is called pwgt (I would think it stands for parentWidget)
What you do, is creating a default argument for your constructor to be set automatic to 0:
Progress(QWidget* pobj=0);
Cleaner maybe would be (for convenience with Qt standard):
Progress(QWidget* parent=nullptr);
So, why do do you need the constructor to look like this?
It is the same reason, which stands for QWidget:
You can set a parent widget, but you don't have to!
The QWidget class will deal for you with this, either you set a parent or not.
I recently joined a new project, which is full with idiom like: ,
void foo()
{
Widget* temp = new Widget;
connect(temp, &Widget::signalTriggerred,[this, temp ]()
{
do cool staff...
}
}
As you can see no delete nothing, I am afraid even user class "Widget" is inherited QObject, this is still a leak. Does QT do something fancy to prevent leek in case above?
What I am planning to do:
void foo
{
std::shared_ptr<Widget > temp( new Widget () );
connect(temp.get(), &Widget::signalTriggerred,[this, temp] ()
{
do even cooler things...
}
}
Is there a problem with my apporach? (For example I didn't want to use .get() but compiler errors forced me to use it).
Edit : Since there is no parent in my case it is different. Duplicated question seek answer for parent-child cases. I am already aware in that case there will be no leek. In my question I am asking about creating a local QObject based object. And connecting it.
Not quite sure what you're wanting from the question, but if you need to delete the widget and it is derived from QObject, you can delete it in the lambda expression, assuming it's not going to be used after this scope:
void foo()
{
Widget* temp = new Widget;
connect(temp, &Widget::signalTriggerred,[this, temp ]()
{
temp->deleteLater();
}
}
This very much depends on the context.
If the temp widget is actually a visible top-level widget (no parent QWidget), then the widget needs to be kept alive until the user closes it. You can achieve it getting deleted automatically when being closed using:
widget->setAttribute(Qt::WA_DeleteOnClose);
If the temp widget however is inserted into the layout of some parent widget, Qt will automatically insert it into the QObject ownership tree and temp will have the same lifetime as its parent, see QObject::setParent().
The shared_ptr by itself saves nothing because it does not answer the question of intended lifetime of widget.
I am using the constructor QWidget(QWidget *parent). This parent widget contains a lot of child widgets. I need to clear all the child widgets from the parent at runtime. How can I do this?
Previous answer is wrong!! You cannot use findChildren to delete a widget's children, because Qt4's findChildren recursively lists children. Therefore, you will delete children of children, which then may be deleted twice, potentially crashing your app.
More generally, in Qt, taking a list of QObject pointers and deleting them one by one is dangerous, as destroying an object may chain-destroy other objects, due to the parent ownership mechanism, or by connecting a destroyed() signal to a deleteLater() slot. Therefore, destroying the first objects in the list may invalidate the next ones.
You need to list children widgets either by:
Passing the Qt::FindDirectChildrenOnly flag to findChild if you are using Qt5 (which did not exist when the question was asked...)
Using QLayout functions for listing items,
Using QObject::children, and for each test if it is a widget using isWidgetType() or a cast
Using findChild() in a loop and delete the result until it returns a null pointer
To take care of the recursivity problem pointed out by #galinette you can just remove the widgets in a while loop
while ( QWidget* w = findChild<QWidget*>() )
delete w;
Summarizing and supplementing:
For Qt5 in one line:
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
For Qt5 for a lot of children, using setUpdatesEnabled():
parentWidget->setUpdatesEnabled(false);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
parentWidget->setUpdatesEnabled(true);
Note that this is not exception safe! While Qt does not at this time appear to throw exceptions here, the signal destroyed() could be connected to code that does throw, or an overridden Object::childEvent(QChildEvent*) could throw.
Better would be to use a helper class:
class UpdatesEnabledHelper
{
QWidget* m_parentWidget;
public:
UpdatesEnabledHelper(QWidget* parentWidget) : m_parentWidget(parentWidget) { parentWidget->setUpdatesEnabled(false); }
~UpdatesEnabledHelper() { m_parentWidget->setUpdatesEnabled(true); }
};
...
UpdatesEnabledHelper helper(parentWidget);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
For Qt4:
QList<QWidget*> childWidgets = parentWidget->findChildren<QWidget*>();
foreach(QWidget* widget, childWidgets)
if (widget->parentWidget() == parentWidget)
delete widget;
Removing from the QLayout works in both Qt4 and Qt5:
QLayoutItem* child;
while (NULL != (child = layout->takeAt(0))) // or nullptr instead of NULL
delete child;
QObjects (and therefore QWidgets) remove themselves (automagically) from their parent in their (QObject) destructor.
From Qt docs
The following code fragment shows a safe way to remove all items from a layout:
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
...
delete child;
}
You can use the following in your parent widget class:
QList<QWidget *> widgets = findChildren<QWidget *>();
foreach(QWidget * widget, widgets)
{
delete widget;
}
I have the following source code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage *Dialog = new Ui::DialogProcessMessage();
Dialog->setupUi(ProcessMessage); //polymorphy
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
connect(Dialog->pushButtonAbort, SIGNAL(clicked()), &Prozess, SLOT(kill()));
connect(&Prozess6, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(helper()));
connect(&Prozess6, SIGNAL(error(QProcess::ProcessError)), this, SLOT(helper()));
connect(this,SIGNAL(enablePushButton(bool)),Dialog->pushButtonClose, SLOT(setEnabled(bool)));
Prozessmeldung->setModal(true);
ProcessMessage->show();
processmethodONE();
}
How can I delete the heap-object Dialog best when the heap-object ProcessMessage is deleted (which is deleted when closed)? Both objects must be created on the heap. Furthermore the class "Ui::DialogProcessMessage" is directly created by the ui-file and therefore any changes in it will be deleted everytime the ui-file is changed.
You need to subclass QDialog, add field in new class for your sub object assign it when creating and add destructor who will free memory of subojbects when your CustomNewSubclassedQDialog if destroyed.
All instances of QObject emit a destroyed(QObject*) signal when they are deleted. Connect ProcessMessage's signal to some other persistent object's slot, and delete your Dialog heap-object from there.
Ref.: Qt documentation for QObject
You can delete the Dialog object in ProcessMessage's destructor.
You'll have to document this to make it clear that ProcessMessage is responsible for the Dialog. Note that this doesn't seem like a good idea. The best approach here is to manually delete both objects when you're done with them. There's nothing restricting anyone from creating a Dialog in automatic storage, which when attempted to be deleted might cause undefined behavior.
Is Ui::DialogProcessMessage a class of your own? Is it derived from QObject? If so, pass the ProcessMessage pointer to the Dialog constructor as its parent. That way ProcessMessage becomes responsible for deleting Dialog. I.e. your declaration of the Ui::DialogProcessMessage class should look something like this:
namespace Ui
{
class DialogProcessMessage: public QDialog
{
Q_OBJECT
public:
DialogProcessMessage(QObject* parent=0) :
QDialog(parent)
{ /* ... */ }
/*
* more stuff ...
*/
};
}
And then, construct Dialog as follows:
Ui::DialogProcessMessage *Dialog = new Ui::DialogProcessMessage(ProcessMessage);
You might want to refer to the Qt documentation for more information.
I have an application that opens a QDialog for some flow, and when it is closed, the QMainWindow is opened.
In the QDialog I create some objects that I'd like to pass as a pointer (or some other way) to the QMainWindow. For example I create a SysTray object that needs to change its state from the QMainWindow. What is the best way? Singletons?
update .
after implementing the sulotion another question was rises , does the QDialog is cleaned from memory that means , invoked its destructor ? i don't think its the case . i have to do some object cleaning , and there destructor never invoked
One approach is to allocate on the heap with the QMainWindow as a parent. The QObject-hierarchy will take care of freeing the memory and you will access the object for the lifetime of the QMainWindow.
If at any point you know for sure that you don't need the QDialog or the shared object anymore, you can call deleteLater.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QObject* _objToShare;
public:
QObject* objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = new QObject(this); // either use this as the parent
// or free by hand in the destructor
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QObject* ptrToSharedObj; // alternatively you can hold a pointer
// to your MyDialog instance
};
Where you use your QDialog:
MyDialog* d = new MyDialog(this);
d->exec();
ptrToSharedObj = d->objToShare();
// don't delete d explicitly, the QObject hierarchy will take care of that
A better (and likely more memory-friendly) approach is to use a shared pointer implementation. Qt has a variety of smart pointer classes, one of which is QSharedPointer. It is basically a thread-safe, reference-counted pointer which means that if you grab one that points to the shared object of your QDialog, it will not get freed as long as there are any other QSharedPointers pointing to it. Keep in mind that this might cause circular references if you are not careful.
Example:
class MyDialog : public QDialog
{
Q_OBJECT
QSharedPointer<QObject> _objToShare;
// ^ don't delete in the destructor
public:
QSharedPointer<QObject> objToShare() const { return _objToShare; }
MyDialog(QObject* parent = 0) : QDialog(parent)
{
_objToShare = QSharedPointer<QObject>(new QObject);
// no parent to avoid destruction when the dialog is destructed
}
// ...
};
class MyWindow : public QMainWindow
{
Q_OBJECT
// ...
QSharedPointer<QObject> ptrToSharedObj;
};
Where you use your QDialog:
MyDialog d;
d.exec();
ptrToSharedObj = d.objToShare();
From this point on, even if d goes out of scope (i.e. destroyed), you will still have a valid pointer to the shared data (well, of course unless you do something explicitly to invalidate it).
You have a lot of different options. Some of these may not be applicable to your situation:
Case 1: Caller knows best (i.e. procedural programming)
Define a controller that can control the ordering. That control can then act as the intermediary and get the data once the dialog has closed:
void FlowController::displayFlow()
{
MyDialog *dialog = new MyDialog();
YourSharedData *data = NULL;
int result = dialog->exec();
if (result == QDialog::Accepted) {
data = dialog->sharedDataAccessor();
}
MyMainWindow *window = new MyMainWindow();
window->setSharedData(data);
window->exec();
}
Case 2: Message Passing
Create both the dialog and the main window up front. Connect the corresponding signals and slots and let them both be ignorant of one another. This is usually much easier to test and keep decoupled:
void AppLauncher::launch()
{
MyDialog *dialog = new MyDialog();
MyMainWindow *window = new MyMainWindow();
window->connect(
dialog,
SIGNAL(dialogResult(int, const SharedData&)),
SLOT(setDialogResult(int,const SharedData&))
);
}
void MyMainWindow::setDialogResult(int result, const SharedData& sharedData)
{
if (result == Dialog::Accepted) // something domain-specific would be better
{
this->processSharedData(sharedData); // do whatever with it.
}
}
Case 3: Shared State Dependency
Define your shared data up front and make it a dependency for each form. Each form then defines state, acts based on that state, or some combination of both:
void AppLauncher::launch()
{
SharedData *data = this->createSharedData();
MyDialog *dialog = new MyDialog(data);
MyMainWindow *window = new MyMainWindow();
dialog->exec(); // does what it needs with shared data
window->exec(); // checks shared data and acts accordingly
}
Case 4: MVC / MVP / MVVM
You may be able to define your shared state as a model that they both act upon. This may not be much different than case three above.
Case 4: Singleton or global state
It will work, but please don't do it :).
In QDialog you have owner, which is probably QMainWindow. (if not, you may add it there, ore get parent objects until you come to QMainWindow class). You may refer to it when creating new objects...
You can subclass QApplication to have it keep a pointer to your systray object, or other objects which should be available "application wide".
In a Qt application, there is only a single instance of QApplication, available everywhere using the qApp macro.
See this mailing list discussion which also contains an example.