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

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.

Related

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.

Cannot create a Qt dialog inside another

This code generates two separate dialogs, while I would like one to be inside the other:
class MyTree : public QWidget {
QTreeView *view;
...
}
//class MyTree : public QDialog {...} // same result
QApplication testApp(argc, argv);
QDialog *topWidget = new QDialog;
MyTree *pjrTree = MyTree::Build();
pjrTree->setParent(topWidget);
topWidget->show();
testApp.exec();
Both the dialog and the tree appear correctly. I just cannot enforce the containment relation.
You're doing it completely incorrectly. You have to create a layout, which contains your elements.
Look at this example:
http://qt-project.org/doc/qt-5.0/qtwidgets/dialogs-findfiles.html
Your solution set only parent of pjrTree but don't add it to QDialog layout. You can simply inherent class MyTree from QDialog, which directly inherent QWidget. It would be more clear and correct.
Deriving the class MyTree from QTreeView, instead of having a pointer to QTreeView as a member variable, fixed my problem.

Do I have to delete these pointers?

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
}

Adding custom QWidget during runtime

I'm trying to implement a custom widget hierarchy:
QMainWindow -> QFrame -> MyWidget -> QFrame -> MySubWidget
Here is how MyWidget class looks like:
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget *parent = 0, ...);
...
public slots:
void SlotFunction(int i);
...
private:
MySubWidget *sub_w;
QFrame *sub_frame;
...
}
If I try to create an MySubWidget during MyWidget constructor, then all MySubWidget elements are shown as intended:
MyWidget::MyWidget (...) : QWidget(parent) {
...
sub_frame = new QFrame(this);
...
sub_w = new MySubWidget(sub_frame); // commented out on a runtime test
}
But if I try to add subwidget during runtime, sub_frame remains blank. I.e. signal reaction:
void MyWidget::SlotFunction(int i) {
sub_w = new MySubWidget(sub_frame); // update, repaint, show and hide methods aren't helphul
}
I know this is an old question, but I was having a very similar issue and it turned out to be a lack of call to the QWidget::show(). Perhaps that was your problem as well?
My question here: Dynamically add instance inherited from QWidget
Cheers.
Are you reaching your function?
At the top of your function before making a new instance of MySubWidget put:
qDebug() << Q_FUNC_INFO;
Is the slot connected properly?
Qt will let you know if it is unable to connect a slot using a runtime warning. Look at the debug output that shows up in Qt Creator and it may mention a reason why the slot was never reached.
Is subframe visible?
If the parent of your object isn't visible, then showing or hiding the child object will only affect it when the parent is shown.
Hope that helps. Good luck.

destructors in Qt4

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.