Why are QWidgets accessed by pointers? - c++

I am new to Qt5 and I am learning QWidgets to develop an application.
I've noticed in many examples, QWidgets are almost always accessed by pointer. For example:
#include <QApplication>
#include <QWidget>
#include <QFrame>
#include <QGridLayout>
class Cursors : public QWidget {
public:
Cursors(QWidget *parent = 0);
};
Cursors::Cursors(QWidget *parent)
: QWidget(parent) {
QFrame *frame1 = new QFrame(this);
frame1->setFrameStyle(QFrame::Box);
frame1->setCursor(Qt::SizeAllCursor);
QFrame *frame2 = new QFrame(this);
frame2->setFrameStyle(QFrame::Box);
frame2->setCursor(Qt::WaitCursor);
QFrame *frame3 = new QFrame(this);
frame3->setFrameStyle(QFrame::Box);
frame3->setCursor(Qt::PointingHandCursor);
QGridLayout *grid = new QGridLayout(this);
grid->addWidget(frame1, 0, 0);
grid->addWidget(frame2, 0, 1);
grid->addWidget(frame3, 0, 2);
setLayout(grid);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Cursors window;
window.resize(350, 150);
window.setWindowTitle("Cursors");
window.show();
return app.exec();
}
This is taken from the tutorial: http://zetcode.com/gui/qt5/firstprograms/
Yet, on the same page, I see that we can access the QWidget base class by its object itself:
#include <QApplication>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
window.resize(250, 150);
window.setWindowTitle("Simple example");
window.show();
return app.exec();
}
Why is it necessary to access all QWidget derived classes by their pointer? Why isn't it necessary to access QWidget itself by its pointer?

It's all about object's lifetime and shared ownership. If you create an object on stack in function, it will be destroyed when scope ends.
Why isn't it necessary to access QWidget by pointer in your example? Just because when main() 'ends', your program is finished, and widget may be destroyed.
Why is it necessary to access QWidget's children by pointer? Because if you want to ask QWidget to give you access to it's child, it can't give you a value, because it would be just a copy of an object. Moreover, if you pass a large object by value to QWidget, it needs to copy your object.

This is not specific to QWidgets: it is so for every QObjects (Qt fundamental base class, from which everything else is derived).
It is the consequence of a design choice of the Qt framework. Quoting Qt documentation:
QObject has neither a copy constructor nor an assignment operator.
This is by design.
[...]
The main consequence is that you should use
pointers to QObject (or to your QObject subclass) where you might
otherwise be tempted to use your QObject subclass as a value. For
example, without a copy constructor, you can't use a subclass of
QObject as the value to be stored in one of the container classes. You
must store pointers.
Source:
http://doc.qt.io/qt-5.5/qobject.html#no-copy-constructor
The rationale for this choice is explained here:
http://doc.qt.io/qt-5.5/object.html#identity-vs-value

QClasses are larger in size and you don't want to fill up your stack memory by instantiating them in stack memory.
When you instantiate derived class objects it also runs constructor of a base class ( derived class + base class ) memory is required,
On the other hand QWidget only inherits QObject and QPaintDevice as you can see here
So it will be less overhead to create QWidget object on stack memory.
You must be very careful when you are using heap memory, read the answers on memory management
You can study the difference between stack and heap from here

Related

Elegant way to access objects created in qApplication main function

I want to create a window application with Qt framework and C++, in which an object is created to operate hardware, and should be accessible to MainWindow and all its members and methods. I do not have very much experience of doing things like this.
int main(int argc, char *argv[]) {
QApplication qApp(argc, argv);
CoolHardware *CoolHardware500 = new CoolHardware; // Object that connects to hardware.
CoolHardware500.Connect();
// Show main window here.
MainWindow qApp_Win(CoolHardware500); // This is the only elegant way I could think.
qApp_Win.show();
return qApp.exec();
// Deconstructor.
CoolHardware500>~CoolHardware();
}
In the methods of MainWindow, is not accessible. How to solve this?
void MainWindow::CoolHardwareDoSomething() {
CoolHardware500->DoSomehing(); // Here CoolHardware500 is shown as not defined.
}
Questions:
Is it an elegant way to create an hardware-operating object in the main() function? How to make it accessible to the members/methods of the MainWindow?
Is it better to create objects in the constructor of the MainWindow and deconstruct objects in the MainWindow deconstructor? In this way, accessing object is easy.
If this two ways are both not elegant ways of doing things, what is the elegant way of doing that?
Thank you very much.
MainWindow is subclassing QMainWindow, but it's a regular C++ class, so just store either an instance directly, or a pointer, as a member variable on it.
In MainWindow.h (or .hpp):
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
// Either this:
CoolHardware500* m_coolHardwarePtr;
// Or that:
CoolHardware500 m_coolHardware;
};
In the constuctor MainWindow::MainWindow you can pass arguments to the CoolHardware500 ctor as needed, or use a new if you use a pointer.
If using a pointer, you also want to have the destructor MainWindow::~MainWindow do a delete m_coolHardwarePtr;.
You could also use a smart pointer (like std::unique_ptr) to avoid to remember to do that delete yourself.
Mainwindow.cpp, assuming you have a Ctor CoolHardware500::CoolHardware500(int):
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),
m_coolHardware(1),
m_coolHardwarePtr(new CoolHardware500(1))
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
delete m_coolHardwarePtr;
}
Here's how:
struct MainWindow : QMainWindow {
private:
CoolHardware hardware;
// ...
public:
MainWindow() {
hardware.connect();
// ...
}
// use `hardware`
};

QMainWindow with member QWidget and QLayout crashes on exit, how to fix that?

The following is a single-file QWidget program.
//main.cpp
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QLabel>
class MainWindow:public QMainWindow{
QLabel lb;
QWidget wgt;
QVBoxLayout lout{&wgt};
public:
MainWindow(){
lout.addWidget(&lb);//line A
setCentralWidget(&wgt);
}
};
int main(int argc, char *argv[]){
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The program crashes on exit. The function-call trace on crash is
system calls
QObjectPrivate::deleteChildren()
QWidget::~QWidget()
QMainWindow::~MainWindow
main
If line A is removed then there is no crash.
I want to figure out what causes the crash, and how to use member QWidget and QLayout without having a crash. Thanks in advance.
While the problem is due to an attempt to free memory that wasn't allocated on the heap I don't think the QMainWindow destructor or a 'double-delete' is the culprit (as suggested elsewhere).
As well as deleting its children the QObject destructor will also remove itself from any parent's object hierarchy. In the code shown wgt is a data member of MainWindow meaning wgt's dtor will be invoked before that of the MainWindow instance. Hence, by the time ~MainWindow is invoked wgt is no longer a child and no attempt will be made to free it at that point. So that's not the issue.
Instead the real problem is the order in which the data members lb, lout and wgt are declared in the MainWindow class...
class MainWindow: public QMainWindow {
QLabel lb;
QWidget wgt;
QVBoxLayout lout{&wgt};
The widget hierarchy is...
wgt
\_lb
and the implicit construction order...
lb
lout
wgt
meaning the order in which the dtors is invoked is...
wgt
lout
lb
Thus, when wgt destructor is called lb is still a child and wgt will attempt to free it. That's the cause of the problem in this particular case. While it can be solved by allocating the various QObjects on the heap, an alternative solution would be to simply re-order the member declarations within MainWindow to ensure the correct order of construction and destruction...
class MainWindow: public QMainWindow {
QWidget wgt;
QVBoxLayout lout{&wgt};
QLabel lb;

Are destructors necessary in QDialogs?

I am following Qt examples (like TabDialog) and I notice that all the UI items are created as pointers - yet I see no delete and no destructor.
Is that right ? Will that not lead to memory leak ?
I am trying to add destructors
~TabDialog()
{
delete tabWidget;
delete buttonBox;
}
and on caller
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
But the program crashes when I close the dialog.
Are the destructors, and delete all pointer items, unnecessary or am I doing it wrong ?
I think that you are confused because of these lines:
tabWidget = new QTabWidget;//and so on
You don't see explicit parent (like new QTabWidget(this);), but it is not necessary here. Take a look here:
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(tabWidget);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setLayout will reparent your QVBoxLayout and QVBoxLayout will reparent all widgets inside it, so now your widgets has a parent and they will be destroyed after your dialog.
As doc said:
When you use a layout, you do not need to pass a parent when
constructing the child widgets. The layout will automatically reparent
the widgets (using QWidget::setParent()) so that they are children of
the widget on which the layout is installed.
Note: Widgets in a layout are children of the widget on which the
layout is installed, not of the layout itself. Widgets can only have
other widgets as parent, not layouts.
I'm sorry, but this just doesn't reproduce. The test case is below. You'd probably need to add some extra code to make it reproduce.
Qt's memory management will take care of everything, since all of the widgets end up having parents. Namely:
Tabs are parented as soon as they are passed to addTab.
tabWidget and buttonBox are parented as soon as they are added to the layout.
Since you delete the tabWidget and buttonBox before Qt attempts to delete them, everything is fine. As soon as you delete them, QObject's memory management is informed and they are removed from the TabDialog's child list. I've made this point explicit in the destructor code.
The meaning of Q_ASSERT is: "At this point during runtime, the following must be true". If we're wrong, the debug build will abort. Since it doesn't, the assertions are correct. Thus, before delete tabWidget, the dialog has both QTabWidget and QDialogButtonBox children. After delete tabWidget, the dialog should not have any QTabWidget children anymore. And so on.
#include <QApplication>
#include <QDialog>
#include <QTabWidget>
#include <QDialogButtonBox>
#include <QVBoxLayout>
class TabDialog : public QDialog
{
QTabWidget *tabWidget;
QDialogButtonBox *buttonBox;
public:
TabDialog() :
tabWidget(new QTabWidget),
buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel))
{
tabWidget->addTab(new QWidget, tr("General"));
tabWidget->addTab(new QWidget, tr("Permissions"));
tabWidget->addTab(new QWidget, tr("Applications"));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(tabWidget);
layout->addWidget(buttonBox);
setLayout(layout);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
~TabDialog() {
Q_ASSERT(findChild<QTabWidget*>());
Q_ASSERT(findChild<QDialogButtonBox*>());
delete tabWidget;
Q_ASSERT(! findChild<QTabWidget*>());
Q_ASSERT(findChild<QDialogButtonBox*>());
delete buttonBox;
Q_ASSERT(! findChild<QTabWidget*>());
Q_ASSERT(! findChild<QDialogButtonBox*>());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
return 0;
}
The only way it'd crash is if you tried the following:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
// At this point `tabDialog` is a dangling pointer.
delete tabDialog; // crash
return 0;
}
Unfortunately, Qt examples are a case of pointless premature pessimization. Qt's classes utilize the PIMPL idiom extensively. Thus the size of, say a QTabWidget is not much larger than that of QObject (48 vs. 16 bytes on my 64 bit platform). By allocating the fixed members of your class on the heap, you're performing two heap allocations: a small one for the QObject-derived class, and then another one for its PIMPL. You're doubling the number of allocations for no good reason.
Here's how to avoid this pessimization:
#include <QApplication>
#include <QDialog>
#include <QTabWidget>
#include <QDialogButtonBox>
#include <QVBoxLayout>
class TabDialog : public QDialog
{
QVBoxLayout m_layout;
QTabWidget m_tabWidget;
QDialogButtonBox m_buttonBox;
QWidget m_generalTab, m_permissionsTab, m_applicationsTab;
public:
TabDialog() :
m_layout(this),
m_buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
{
m_tabWidget.addTab(&m_generalTab, tr("General"));
m_tabWidget.addTab(&m_permissionsTab, tr("Permissions"));
m_tabWidget.addTab(&m_applicationsTab, tr("Applications"));
m_layout.addWidget(&m_tabWidget);
m_layout.addWidget(&m_buttonBox);
connect(&m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(&m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
auto tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->show(); // NOT tabDialog->exec()!!
return app.exec();
}
The less explicit heap allocations, the better. This way you can't even be tempted to delete anything in the destructor, since there are no pointers involved. The compiler generates necessary destructor calls for you automatically.
Furthermore, if you're showing only one window in main, there's no point to explicit heap allocation either:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TabDialog tabDialog;
tabDialog.show();
return app.exec();
}
Memory handling on Qt
Qt handles the widgets as a tree, every widget has a parent and every parent has
the obligation to free the children memory, if a widget has no parent you should delete it manually with the operator delete.

Qt: How to put collection of GUI-Elements into independent SubClass (with seperate *.ui file)

I'm trying to collect an often used subset of GUI-Elements together into one Subclass, which can be "included" into the real GUIs later without rewriting the given functionality (don't ask why, I wanna learn it for later use). The Subclass should use it's own *.ui-File and should be put into an QWidget resding in the real GUI. After this, it would be nice to access some methods of the Subclass from the real GUI -- like the state of a button or so.
But how do I do this right?
In the moment, my Subclass works and is instantiated in main, but cannot be accessed from the real GUI because its only declared in main.
My Subclass Header-File:
class logger : public QWidget, private Ui::loggerWidget {
Q_OBJECT
public:
logger(QWidget *parent = 0);
virtual ~logger();
// some more stuff...
}
The corresponding constructor. I had to run setupUI with "parent" instead of "this", but I'm not sure that this is correct -- anyways, it works... otherwise, the subelements from the subclass are not shown in the main-window of the real GUI.
logger::logger(QWidget *parent) : QWidget(parent){
setupUi(parent);
//ctor
}
Inside the main.cpp the main-window is constructed, which uses it's own *.ui-File (containing one widget "widget_loggerArea") aswell. Doing so, I can not access methods of "logger" from within "loggerTest":
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
loggerTest window;
logger myLog(window.widget_loggerArea);
window.show();
return app.exec();
}
I can't put the constructor of "logger" into the constructor of the main-window "loggerTest", since it will be destroyed immidiately and never enters the event-loop.
I'm sure I'm missing some concept of object-oriented programming, or the way qt handles its stuff... I would be gratefull if someone could put my nose to this ;-)
I was so stupid... using a pointer with new and delete does the job... this is so silly, I can't believe it! I'm more used to VHDL recently, this weakens my C++-karma...
So, the answer is in the real GUI class. The Constructor:
testLogger::testLogger(QMainWindow *parent) : QMainWindow(parent){
setupUi(this);
myLog = new logger(widget_loggerArea);
}
In main.cpp:
QApplication app(argc, argv);
testLogger window;
window.show();
And in constructor of logger, setupUi works with "this":
dfkiLogger::dfkiLogger(QWidget *parent) : QWidget(parent){
setupUi(this);
}
Yes, thats it... Just for completebility, maybe someone needs a similar "push in the right direction"...
EDIT: In the header of the SubClass the scope of the ui-Elements has to be updated to "public", too:
class logger : public QWidget, public Ui::loggerWidget {
Q_OBJECT
public:
logger(QWidget *parent = 0);
virtual ~logger();
}

qt example from the book

I have this snippet of the code:
#include <QApplication>
#include <QFont>
#include <QPushButton>
#include <QWidget>
class MyWidget : public QWidget
{
public:
MyWidget(QWidget *parent = 0);
};
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(200, 120);
QPushButton *quit = new QPushButton(tr("Quit"), this);
quit->setGeometry(62, 40, 75, 30);
quit->setFont(QFont("Times", 18, QFont::Bold));
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyWidget widget;
widget.show();
return app.exec();
}
can somebody please explain what exactly is going on in this line
MyWidget(QWidget *parent = 0);
a little bit difficult understand what is this parent, thanks in advance
That is an argument to the constructor with a default argument (NULL since NULL is defined as 0 as per the c++ standard). Default meaning passing no parameter is the same as passing NULL.
Since Qt's widgets are arranged in a hierarchal system (parent -> child relationships) parent is the widget which is the "owner" or "container" of the current one (NULL means no parent aka a root widget of sorts). For GUI items a widget will often have the widget it is contained in as its parent.
This is advantageous since when a parent is deleted, it will delete any children is has automatically removing the need for much of the memory management that comes with c++.
The parent argument is for giving parents to new widgets. When given, it is useful for Qt to manage the object tree. (To automatically delete child objects.) It also has the concrete visible effect of "attaching" a new widget to another widget (ie, the parent). In your code however, the parent argument is not ever given, causing the widget to appear as a top level window and not to be deleted by Qt automatically. (It would not require deletion by Qt anyway in that code though.)
Its a 0 pointer (think NULL without the type), or in Qt terms, "no parent".