Do I have to delete these pointers? - c++

This is the MainWindow class which I call and use the function show() to make it visible to the user.
class MainWindow : public QMainWindow
{
Q_OBJECT
QWidget *centralWidget;
QGridLayout* gridLayout;
QGridLayout* infoBoxLayout;
QHBoxLayout* buttonGroup;
QHBoxLayout* subCategoryLayout;
//... more widgets
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
void setupUi();
void setupConnections();
private slots:
void add();
void edit();
void remove();
void find();
void clearAll();
void screenshotDesktop();
void screenshotApp();
void currentSubCategoryChanged( const QString& );
void curretCategoryChanged( const int );
void keyPressEvent( QKeyEvent * );
};
I created for each widget (those pointers after the macro Q_OBJECT) a new object on the heap with new. However, I did not delete them anywhere in the program. Does this cause a memory leak in Qt? Or does something from Qt delete them automatically when destroying the class?

If a widget has a parent set, then Qt will handle deleting the widget.
In the case of a MainWindow, when you close it, the MainWindow and its children will be cleaned up, so pass the parent to the widget's constructor: -
QHBoxLayout* buttonGroup = new QHBoxLayout(this); // where this is the parent (MainWindow)
If you create a Widget such as this: -
QHBoxLayout* buttonGroup = new QHBoxLayout;
And haven't passed in the parent, then it will not be cleaned up and you'll have to handle that yourself.

if you add them to the gui hierarchy then they will be cleaned up when the MainWindow is deleted
this is because parents assume ownership over their children (which is set with the various adds of the gui)
so a this->add(centralWidget); will call centralWidget->setParent(this); which will let centralWidget be deleted when MainWindow is deleted
you are free to delete QObjects yourself but beware dangling pointers (QPointer will help here). though I suggest using deleteLater() to ensure no strange behavior when a pointer still lives on the stack.
for more info about the object tree see here

The automatic memory management through parent-child relationships is done by the QObject. QWidget happens to be a QObject, and it so happens that widgets that have parent widgets have the same underlying QObjects as parents.
A QObject with children automatically deletes its children in its destructor.
A QObject or a QWidget may be adopted by another object. For example, adding widgets to a layout will automatically reparent them to the widget the layout is set on. Even if a layout doesn't have a widget set on it yet, the reparenting will be done at the time you add the layout to a widget (or to a layout that has a widget set). It's pretty clever and saves a lot of typing and reduces possibilities for mistakes.
The idiomatic, minimum-typing way of adding widgets to another widget is:
MyWidget() {
QLayout * layout = new QHBoxLayout(this); // set a layout on this widget
layout->addWidget(new QLabel("foo")); // the label is reparented to this
layout->addWidget(new QPushButton("bar")); // the button is reparented to this
}

Related

What are `(QWidget* pobj=0)` and `(QWidget* pwgt/*=0/)` for?

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.

Adding widget to layout only works in constructor of custom class

I have a class MainWindow subclassing QMainWindow. As the central widget I have a QScrollArea with a QWidget inside, as a container for my own custom widgets. I set a QVBoxLayout as the layout for the QWidget container and pass this layout to the constructor of my custom class, which is supposed to dynamically create instances of my custom widget class and add them to the layout.
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = Q_NULLPTR);
virtual ~MainWindow ();
private:
QVBoxLayout mainLayout;
QScrollArea scrollArea;
QWidget container;
NotificationControl control;
};
MainWindow::MainWindow (QWidget *parent) :
QMainWindow(parent),
container(&scrollArea),
control(&mainLayout) {
container.setLayout(&mainLayout);
scrollArea.setWidget(&container);
setCentralWidget(&scrollArea);
}
Now in my NotificationControl class I have a method addNotification:
void NotificationControl::addNotification (Notification notif) {
qDebug() << "NotificationControl addNotification" << notif.get_app_name();
NotificationWidget* widget = new NotificationWidget(notif);
container->addWidget(widget);
}
When this method is called, I get the debug output, but nothing is added to the layout. But if I add this to the end of the constructor of NotificationControl...
NotificationWidget* notif = new NotificationWidget(Notification());
container->addWidget(notif);
...for some reason it works. I'm pretty sure the problem isn't the NotificationWidget class. For testing purposes I made some changes, it doesn't actually use the Notification object that is passed at all.
What could be the problem?
Edit: I just noticed that adding widgets later (not in constructor) makes the widgets added in the constructor disappear.
Any widget added as a child widget must be explicitly shown if the parent widget is already visible. Usually, the child widgets are added before the parent widget is shown, and they then become visible themselves, too. But if you add them later, you must make them explicitly visible.

Do Layouts become your children when you use setLayout in Qt

Here's the code:
class MyWidget: public QWidget
{
public:
MyWidget();
~MyWidget();
private:
QHBoxLayout* theLayout;
QVBoxLayout* subLayout1;
QVBoxLayout* subLayout2;
//More subLayouts
}
MyWidget::MyWidget()
{
theLayout = new QHBoxLayout();
subLayout1 = new QVBoxLayout();
subLayout2 = new QVBoxLayout();
//More subLayouts
//-------- Fill subLayouts with widgets using addWidget --------
theLayout->addLayout(subLayout1);
theLayout->addLayout(subLayout2);
//add all subLayouts
setLayout(theLayout);
}
MyWidget::~MyWidget()
{
//Destructor with nothing in it
}
**Note: the layouts are members of the class.
So I know that the widgets filled in the subLayouts are now MyWidget's children (or at least that's what I thought if not please tell me) so I don't need to delete them in the destructor (Qt cleans them up right?), but are the layouts also children of MyWidget or do I need to delete these in the destructor?
As the documentation says the setLayout call will reparent the given layout. So this widget will be it's parent, so you don't need to manually delete it.
I think you should use constructors with the argument if possible. And also you don't need to store the layouts as a members if you just initialize them.

QDialog deletes its QLayout?

I have a Qt4 application, that has numerous dialogs. I am curious to know whether or not a QDialog deletes its Layout. Take for example:
class MyDialog : public QDialog {
public:
MyDialog(QWidget* _parent = 0) : QDialog(_parent) {
//instantiate some widgets
m_layout = new QGridLayout(this);
setLayout(m_layout)
//add some widgets to the layout
}
~MyDialog() {
//Do I need this code? or will the parent delete the layout?
//delete m_layout;
}
private:
QGridLayout* m_layout;
}
So do I need to write my own destructor? or will the QDialog take care of the memory management of m_layout?
The QDialog will delete the QLayout upon destruction. You do not need to delete the layout in the destructor.
See also: http://doc-snapshot.qt-project.org/qt5-stable/qtwidgets/qwidget.html#setLayout

Don't understand why I can't call setCentralWidget in QMainWindow subclass

//clposter.h
class CLPoster : public QMainWindow
{
Q_OBJECT
public:
CLPoster();
private slots:
QWidget createCentralWidget();
void createActions();
void createMenu();
void createStatusBar();
void loadSavedPosts();
};
//clposter.cpp
CLPoster::CLPoster()
{
setWindowTitle("Craigslist Poster");
QWidget mainWidget = createCentralWidget();
setCentralWidget(mainWidget);
// createActions();
// createMenu();
// createStatusBar();
// loadSavedPosts();
// checkForActionsNeeded(); //May want to break up into more functions
}
The error I'm getting is this:
/usr/include/qt4/QtGui/qwidget.h:: In constructor ‘CLPoster::CLPoster()’:
/usr/include/qt4/QtGui/qwidget.h:787: error: ‘QWidget::QWidget(const QWidget&)’ is private
/home/brett/projects/CLPoster/CLPoster-build-desktop/../CLPoster/clposter.cpp:9: error: within this context
/home/brett/projects/CLPoster/CLPoster-build-desktop/../CLPoster/clposter.cpp:10: error: no matching function for call to ‘CLPoster::setCentralWidget(QWidget&)’
/usr/include/qt4/QtGui/qmainwindow.h:141: candidates are: void QMainWindow::setCentralWidget(QWidget*)
I'm having trouble interpreting the error message. It says there is no matching function call, but it should be inheriting it from QMainWindow. It could just be a lack of understanding C++ more so than QT, first time I've used it, but dunno. Thanks for the help.
All QWidget items must be allocated in the free-store (new) since they all have to have "parents". In Qt a parent will delete its children (with delete). This is why any function returning, accepting, whatever a widget is going to do so on a pointer to a widget, not the widget itself; you need to do the same.
The setCentralWidget function expects that you are sending a pointer to a QWidget (QWidget*), whereas you are trying to send the actual object (or a reference to the object, QWidget&, as implied by the compiler error) in your code. If you create your central widget as a pointer (change the member function to QWidget* createCentralWidget()) and pass the pointer to the setCentralWidget function you should be good to go.
e.g.
QWidget* CLPoster::createCentralWidget()
{
QWidget* w = new QWidget;
// Do stuff..
return w;
}
Then in your constructor, you can just call setCentralWidget(createCentralWidget()). The QMainWindow destructor will ensure that your central widget is deleted.
Don't you need to allocate the Widget on the heap and pass a pointer to setCentralWidget()