Qt parent mechanism - c++

There is one QPushButton in a QWidget, click the button should open another QWidget, as coded below:
project.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = untitled
TEMPLATE = app
CONFIG(debug, debug|release) {
DESTDIR = debug
} else {
DESTDIR = release
}
INCLUDEPATH += ..
SOURCES += ../main.cpp\
../widget.cpp \
../secondwidget.cpp
HEADERS += ../widget.h \
../secondwidget.h
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QVBoxLayout>
#include <QPushButton>
#include "secondwidget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(400, 300);
QVBoxLayout *vLayout = new QVBoxLayout(this);
QPushButton *bt = new QPushButton("Open 2nd Widget");
vLayout->addWidget(bt, 1, Qt::AlignRight);
SecondWidget *secondWidget = new SecondWidget();
// SecondWidget *secondWidget = new SecondWidget(this);
connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
}
Widget::~Widget()
{
}
secondwidget.h
#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H
#include <QWidget>
class SecondWidget : public QWidget
{
Q_OBJECT
public:
explicit SecondWidget(QWidget *parent = 0);
signals:
public slots:
};
#endif // SECONDWIDGET_H
secondwidget.cpp
#include "secondwidget.h"
SecondWidget::SecondWidget(QWidget *parent) : QWidget(parent)
{
setAttribute( Qt::WA_QuitOnClose, false );
}
Passing this for the SecondWidget constructor (as in the commented line) will brake my logic at some point. So the SecondWidget doesn't show anymore, when the button is clicked.
What's going on?

In addition to the problems with your destructor and constructor (and the memory leak you have because of the second), and the project file here are a few things that you may want to know in order to understand the whole parent situation:
You don't need to pass this. The purpose of assigning a parent is to be able to simplify the cleanup procedure for QObject instances (including all classes inheriting from the QObject class). Qt parent-child model follows the C++ standard that is destructors are invoked in the reversed order of their constructors. In simple terms this means the following:
Imagine you create widget A, B and C. Using the parent property you assign B and C to be children of A. So here we have the order of creation:
A (parent)
B,C (children)
Now at some point you want to destroy your widgets (example: closing the application). The standard C++ way is to destroy them in the following (reversed to the construction) order:
B, C (children)
A (parent)
And this is indeed what happens if we go for the parent first. However we are dealing with Qt here so we have to consider one additional feature the library provides - slots and signals.
Whenever a QObject gets destroyed it emits a signal. Based on the role the object plays in the parent-child relationship the outcome is one of the following:
only the QObject that is destroyed gets destroyed - this is what happens when a child gets destroyed before we destroy its parent
all children of that QObject get destroyed first followed by the destruction of the QObject itself - this is what happens when a parent gets destroyed. The emitted signal is caught by all its children which in return also get eliminated.
However assigning a parent is not mandatory. You can do the cleanup manually yourself. Read more about the parent-child model in the Qt documentation.
In addition to all that ownership transfer (a widget becomes a child of another widget) often happens automatically so it is not necessary to explicitly specify a widget's parent. Again taking things out of the Qt documentation an exception is made here. If you add a widget to a layout, the ownership is NOT transferred to the layout itself but to the QWidget it is part of.
Finally there is one important case when not assigning a parent makes things very, very different. Here I shall quote the Qt documentation on QObject:
Setting parent to 0 constructs an object with no parent. If the object is a widget, it will become a top-level window.
So if you have a QWidget and don't add it to some layout (and indirectly to the QWidget that has that layout) for example it will automatically become a separate window.
EDIT:
Check your constructor and in particular the way you work with your secondWidget object. As I've mentioned above in case you don't want to assign it to a parent widget you need to take care of the cleaning.
You dynamically allocate the memory for it
SecondWidget *secondWidget = new SecondWidget();
and even connect it to your button
connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
however you never release the allocated memory using delete or assigning it to a parent widget, which will take care of it automatically. Hence you create a memory leak. Connecting a QObject via signals and slots doesn't have anything to do with transfer of ownership.
I personally assume that you actually want a secondWidget to be an extra window shown on the screen. In this case you need to create a class member of type SecondWidget
SecondWidget *secondWidget;
then allocate it inside your constructor and connect whichever slots and signals you want
Widget::Widget(QWidget *parent) : QWidget(parent)
{
//...
secondWidget = new SecondWidget();
connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
}
and finally release the memory inside your constructor:
Widget::~Widget()
{
delete secondWidget;
}
Otherwise as I said you are basically creating a reference to a memory block and right after you leave your constructor that reference gets destroyed since it runs out of scope.
EDIT 2:
Here is a small example how to do it if you want secondWidget as a child to your main widget:
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.hpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "secondwidget.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
SecondWidget *secondWidget = new SecondWidget(this); # secondWidget is now officially adopted by Widget
# If you skip the parent assignment inside SecondWidget you can call secondWidget->setParent(this) here
connect(ui->pushButton, SIGNAL(clicked(bool)), secondWidget, SLOT(show()));
}
Widget::~Widget()
{
delete ui;
}
secondwidget.hpp
#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H
#include <QObject>
#include <QDialog>
class SecondWidget : public QDialog
{
Q_OBJECT
public:
explicit SecondWidget(QWidget *parent = 0);
~SecondWidget();
};
#endif // SECONDWIDGET_H
secondwidget.cpp
#include "secondwidget.h"
#include <QFormLayout>
#include <QLabel>
SecondWidget::SecondWidget(QWidget *parent) : QDialog(parent)
{
# If you don't call the constructor of your superclass you can still assign a parent by invoking setParent(parent) here
QFormLayout *layout = new QFormLayout();
QLabel *label = new QLabel("SecondWidget here");
layout->addWidget(label); # Transfer ownership of label to SecondWidget
setLayout(layout);
}
SecondWidget::~SecondWidget()
{
}
Note the setParent(parent) inside the SecondWidget's constructor. You either have to invoke the superclass constructor (as you have done) or manually call setParent(parent). If you don't do that yoursecondWidgetwill not be assigned as a child to your main widget where you create it and thus you will produce a memory leak. You can also invokesecondWidget->setParent(this)` from within the constructor of your main widget in order to set the parent.
Here is how you can check if the parent-child hierarchy is okay:
To each QObject that you have (QWidget, QLayout etc. are all subclasses of QObject) assign an object name using QObject::setObjectName("some name")
At the end of both of your constructors add:
for(int i = 0; i < this->children().count(); i++)
std::cout << this->children()[i]->objectName().toStdString() << std::endl; // Add #include <iostream> to get the output
which basically traverses all the children of this (Widget or SecondWidget) and displays its children. In my case I got
label // Printing out children of SecondWidget
formLayout // Printing out children of SecondWidget
gridLayout // Printing out children of Widget
pushButton // Printing out children of Widget
main second widget // Printing out children of Widget
once I launched my application.
EDIT 3: Ah, I didn't notice that you are calling the QWidget(parent) in you SecondWidget constructor. This also does the trick so you don't need setParent(parent). I have altered my second EDIT.

This usually happens if
classes are linked
destructor calls aren't properly being called
Makefile needs some changes.

Actual Error?
Makefile needs to be remade using the cmd prompt or Terminal
Make sure that your destructor doesn't call itself so this change the remedy of execution.

Related

Qt custom SLOT of subclass not recognised by CONNECT

Background
I am writing a media player application in Qt. I have subclassed QMediaPlayer and created a new SLOT which is capable of interpreting an int and passing it as qint64 to QMediaPlayer::SetPosition(qint64).
QMediaPlayer::PositionChanged fires a signal to the cslider slider_playback (a horizontal slider subclass). This makes the slider move as a song is playedback. There are also some subclassed labels (clabel) which receive signals regarding the song duration and song playback position.
Problem
The problem i have occurs when I build & run, I receive the following error:
Starting /home/daniel/DeveloperProjects/build-Player-Desktop_Qt_5_9_1_GCC_64bit-Debug/Player...
QObject::connect: No such slot QMediaPlayer::set_playback_position(int) in ../Player/mainwindow.cpp:23
QObject::connect: (sender name: 'slider_playback')
The slider should be able to control the position of the playback. The offending line of code is preceeded by a '// Player seek' comment in the file.
I think the error indicates that the base class is being referred to for the SLOT, whereas the slots is actually part ofthe derived class.
Why is this error occuring and what action would resolve the issue? The slots in my clabel and cslider classes work without issue. The difference is that those classes have constructors and destructors. I have not implemented a constructor in the QMediaPlayer subclass as I do not want to override the base class constructor.
cmediaplayer.h (full file)
#ifndef CMEDIAPLAYER_H
#define CMEDIAPLAYER_H
#include <QMediaPlayer>
//#include <QObject>
class cmediaplayer : public QMediaPlayer
{
Q_OBJECT
public slots:
void set_playback_position(int);
};
#endif // CMEDIAPLAYER_H
cmediaplayer.cpp (full file)
#include "cmediaplayer.h"
void cmediaplayer::set_playback_position(int v) {
this->setPosition( (qint64)v );
}
mainwindow.h (full file)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMediaPlayer>
#include "cmediaplayer.h"
#include "clabel.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QPalette m_pal;
QString media_file_str="/usr/share/example-content/Ubuntu_Free_Culture_Showcase/Jenyfa Duncan - Australia.ogg";
//QMediaPlayer * player ;
cmediaplayer * player; // My custom type
private slots:
void on_pushButton_pressed();
void on_pushButton_released();
void on_button_playback_clicked();
};
mainwindow.cpp (full file)
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
//player = new QMediaPlayer;
player = new cmediaplayer; // My custom type
// set max time on playback slider
connect(player, SIGNAL(durationChanged(qint64)), ui->slider_playback, SLOT(set_qint64_max(qint64)));
// st max time on playback label
connect(player, SIGNAL(durationChanged(qint64)), ui->label_track_length, SLOT(setIntText(qint64)));
// set slider playback position
connect(player, SIGNAL(positionChanged(qint64)), ui->label_track_position, SLOT(setIntText(qint64)));
// Player seek
connect(ui->slider_playback,
SIGNAL(valueChanged(int)),
player,
SLOT(set_playback_position(int)));
// Player volume
connect(ui->slider_volume,SIGNAL(valueChanged(int)),player,SLOT(setVolume(int)));
ui->slider_volume->setValue(50); // set player initial value
}
MainWindow::~MainWindow() {
delete ui;
delete player;
//delete playlist;
}
void MainWindow::on_pushButton_pressed() {
m_pal=this->palette().color(QPalette::Background);
QPalette pal=palette();
pal.setColor(QPalette::Background,Qt::gray);
this->setAutoFillBackground(true);
this->setPalette(pal);
player->setMedia(QUrl::fromLocalFile(media_file_str));
player->setPlaybackRate(1);
player->play();
}
void MainWindow::on_pushButton_released() {
QPalette pal=m_pal;
this->setAutoFillBackground(true);
this->setPalette(pal);
//player->stop();
}
void MainWindow::on_button_playback_clicked()
{
//player->play();
}
Qt creates a new class that implements the actual connection between the slots and the signals but many times this one is not updated. The classes they refer to have a name similar to moc_xxx.cpp and these are created in the build folder.
To force them to update we must click on the make clean submenu that is located in the Menu Build of QtCreator, and then run qmake in the same menu.
Or you can manually remove the build folder and compile it back
Perhaps, it could help somebody. I had a similar issue when trying to use a SLOT function in the connect call. Even though the slot was declared and defined in the subclass, the connect function not recognize it, issuing a message which says that the slot function is not part of the base class.
In my case, the problem was that I didn't place the Q_OBJECT in the beginning of the class declaration. After that, I had to clean (otherwise, various errors occur in compilation step) and build the project again to had the slot function working properly.

Initializing a Ui pointer From a QMainWindow class to a QDialog Class

I'm really stuck on one problem that I want to solve. the problem is that I have a Class for QMainWindow which holds the Ui variable for that form. Now I want to be able to edit that Form using the Ui variable in that class on a QDialog cpp file. I probably sound really stupid and I really have no idea how I should explain this, but I have code which maybe can help.
MainWindow.h:
#include "ui_mainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
Ui::MainWindow *ui;
}
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
Dialog *dialog;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
dialog->show();
}
QDialog.cpp:
#include "ui_mainwindow.h"
#include "mainwindow.h"
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
Ui::MainWindow *mainui;
void Dialog::on_pushbutton_clicked(){
mainui->label->setText("test");
}
So as you can see from the above code, it shows that I have a pointer to the Ui variable however its uninitialised, therefore it would lead to a SIGSEGV error, so how to do Initialize this pointer? any help here is highly appreciated, and even though this is probably really simple I just don't know what to do. (I have looked at other questions but I couldn't quite grasp what to do, so please explain what I am to do before linking me to a similar question. Also, I have left out the Dialog.h file as I didn't think it was needed, please tell me if I need to show it, thanks!).
Generally in C++ you should practice what is called encapsulation - keep data inside a class hidden from others that don't need to know about it. It's not good to have multiple pointers to the UI object as now all those other objects have to know how the main window UI is implemented.
In this case, what I would recommend is to use Qt's signals and slots mechanism to allow the dialog to tell the main window what you need it to do. That has the advantage that if you add more dialogs, or change how things are implemented in the main window, you don't need to alter the signal slot mechanism, and the details are hidden cleanly.
So - for your dialog, add a signal like this in the header file
class Dialog : QDialog
{
Q_OBJECT
signals:
void setTextSignal(QString text);
}
and in your main window header, add a slot.
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void setTextSlot(const QString &text);
}
now in your method where the button is pressed,
void Dialog::on_pushbutton_clicked()
{
emit setTextSignal("test");
}
and in your main window
void MainWindow::setTextSlot(const QString &text)
{
mainUi->label->setText(text);
}
The final part is to connect the signal and slot together, which you would do in your main window function where you create the dialog:
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
connect(dialog, SIGNAL(setTextSignal(QString)), this, SLOT(setTextSlot(QString)));
dialog->show();
}
You can see there are many advantages to this; the Dialog no longer needs a pointer to the main window UI, and it makes your code much more flexible (you can have other objects connected to the signals and slots as well).
Short answere - your can't! If you want to create a new instance of the ui, you would have to do:
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(this);
However, the this-pointer for a UI created for a QMainWindow based class must inherit QMainWindow - thus, you can't.
In general, it is possible if you create your Ui based on a QWidget instead of a QMainWindow, since both inherit QWidget.
Alternativly, you could try the following:
QMainWindow *subWindow = new QMainWindow(this);
subWindow->setWindowFlags(Qt::Widget);
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(subWindow );
//... add the mainwindow as a widget to some layout
But I would guess the result will look weird and may not even work in the first place.

How to get the member object for SLOT in connect()?

I Started learning Qt (5.5) a couple of days ago, and I recently got stuck on something when working with the connect function, specifically the SLOT parameter. I'm calling a member function from the same class that the connect function is called in, but when the SLOT function is triggered it acts like it's creating a new class object. It worked initially when I kept everything in the same class, but this problem popped up when I tried implementing a hierarchy. I wrote a short program to demonstrate my problem.
Main.cpp
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow QtWindow;
QtWindow.show();
return app.exec();
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QGridLayout>
#include "TopWidget.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow *parent = 0);
private:
QWidget *mainWidget;
QGridLayout *mainLayout;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QMainWindow *parent) : QMainWindow(parent){
mainWidget = new QWidget(this);
mainLayout = new QGridLayout(mainWidget);
setCentralWidget(mainWidget);
TopWidget tWidget(this);
mainLayout->addWidget(tWidget.topWidget, 0, 0);
}
TopWidget.h
#ifndef TOPWIDGET_H
#define TOPWIDGET_H
#include <stdlib.h>
#include <QWidget>
#include <QPushButton>
#include <QGridLayout>
#include <QDebug>
#include <QErrorMessage>
class TopWidget : public QWidget
{
Q_OBJECT
public:
TopWidget(QWidget *parent);
QWidget *topWidget;
private:
QGridLayout *wLayout;
QPushButton *Button;
int memVar1;
int memVar2;
private slots:
void testConnect();
//void SlotWithParams(int a, int b);
};
#endif // TOPWIDGET_H
TopWidget.cpp
#include "TopWidget.h"
TopWidget::TopWidget(QWidget *parent) : QWidget(parent){
topWidget = new QWidget(parent);
wLayout = new QGridLayout(topWidget);
memVar1 = 123;
memVar2 = 321;
Button = new QPushButton("Click Me", topWidget);
connect(Button, &QPushButton::clicked, [=](){ TopWidget::testConnect(); });
}
void TopWidget::testConnect(){
qDebug("Button worked");
if(memVar1 != 123 || memVar2 != 321){
qDebug("Linking failed");
}else{
qDebug("Linking success");
}
}
Since I just started with Qt, I don't have a good feel for what's "proper" Qt code, and what I should avoid, so tips in that direction are also appreciated. The following is the qmake file, if that's important.
CONFIG += c++11
CONFIG += debug
CONFIG += console
QT += widgets
QT += testlib
SOURCES += main.cpp
SOURCES += MainWindow.cpp
SOURCES += TopWidget.cpp
HEADERS += MainWindow.h
HEADERS += TopWidget.h
Release:DESTDIR = bin/Release
Release:OBJECTS_DIR = obj/Release
Release:MOC_DIR = extra/Release
Release:RCC_DIR = extra/Release
Release:UI_DIR = extra/Release
Debug:DESTDIR = bin/Debug
Debug:OBJECTS_DIR = obj/Debug
Debug:MOC_DIR = extra/Debug
Debug:RCC_DIR = extra/Debug
Debug:UI_DIR = extra/Debug
When I run the program in debug mode and press the button, it outputs "Button worked" indicating the link to the function was successful, but then outputs "Linking failed" indicating that a new object was created rather than taking the old one. My knowledge of C++ is patchy, since I only pick up what I need to, and I spent hours yesterday trying to fix this, so forgive me if the fix is something ridiculously easy, but I've mentally exhausted myself over this.
The problem comes from this line:
TopWidget tWidget(this);
You are allocating tWidget on the stack, and it gets destroyed just at the end of the MainWindow constructor.
Replace by:
TopWidget * tWidget = new TopWidget(this);
Also, you should replace your connect line by this one
connect(Button, &QPushButton::clicked, this, &TopWidget::testConnect);
It appears that your slot is called even after the TopWidget is destroyed. Qt normally disconnects connections when sender or receiver are destructed, but it's not able to do that when you connect to a lambda.
And finally, you are doing something weird. What is the purpose of your TopWidget class besides just creating another widget and receiving signals on its slot? You never add the TopWidget to any layout, but just its child. TopWidget is never shown, so it should rather derive from QObject only.

Qt window wont close using "this->close()" from other class

I will start off by explaining my main goal. I have a main window with 7 buttons on it(amongst other things), when you hit each button, it closes out the current window and opens up a new window. All the windows will have the same 7 buttons, so you can go between each window. With all windows having the exact same 7 buttons, I wanted to set up a function that each class can call to set up each button and connect to a slot() in my mainwindow.cpp(called setupSubsystemButtons in example below). However, I can't seem to get the window to close using the standard "this->close()"...it works when I go from the main window to another window(the main window closes) but when I go from a different window to say the home window, the different window doesn't close. Suggestions would be greatly appreciated. My guess is that my understanding of "this" when it comes to calling slots in another class is wrong.
mainwindow.cpp( the parts that are relevant)
void MainWindow::ECSgeneralScreen()
{
ECSgeneralCommand *ECSgeneral = new ECSgeneralCommand;
this->close();
ECSgeneral->show();
//opens up the ECS screen
}
void MainWindow::homeScreen()
{
MainWindow *home = new MainWindow;
this->close();
home->show();
//opens up the ECS screen
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupSubsystemButtons(QGridLayout *layout)
{
//Push Button Layout
homeScreenButton = new QPushButton("Home");
layout->addWidget(homeScreenButton, 3, 11);
connect(homeScreenButton, SIGNAL(clicked()), this, SLOT(homeScreen()));
ECSgeneralScreenButton = new QPushButton("General");
layout->addWidget(ECSgeneralScreenButton,5,11);
connect(ECSgeneralScreenButton, SIGNAL(clicked()), this, SLOT(ECSgeneralScreen()));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QDialog
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
QWidget *window;
void setupSubsystemButtons(QGridLayout *layout);
~MainWindow();
private slots:
public slots:
void ECSgeneralScreen();
void homeScreen();
};
#endif // MAINWINDOW_H
ecsgeneralcommandWindow
include "ecsgeneralcommand.h"
#include "mainwindow.h"
#include <QtWidgets>
#include <QtCore>
ECSgeneralCommand::ECSgeneralCommand(MainWindow *parent) : QDialog(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
QWidget::setFixedWidth(650);
...
//Setup Subsystem Buttons
test.setupSubsystemButtons(layout);
setLayout(layout);
}
ecsgeneralcommandWindow header
#ifndef ECSGENERALCOMMAND_H
#define ECSGENERALCOMMAND_H
#include <QDialog>
#include <QMainWindow>
#include <QtWidgets>
#include <QObject>
#include "mainwindow.h"
class ECSgeneralCommand : public QDialog
{
Q_OBJECT
public:
explicit ECSgeneralCommand(MainWindow *parent = 0);
private:
MainWindow test;
public slots:
};
#endif // ECSGENERALCOMMAND_H
Slots are just normal functions. When Qt invokes a slot, it ends up calling the appropriate receiver's method. In other words, this equals to the value of the 3rd argument of your connect statements. You passed this there, so the receiver is MainWindow object. E.g. MainWindow::homeScreen method always tries to close MainWindow. If it is already hidden, this action takes no effect.
You should either have a slot in each window class and connect buttons to appropriate receivers, or use a pointer to the currently active window instead of this when calling close(). But your architecture is strange in the first place. Why would you need to create these buttons for each window? It is reasonable to create them once and use in all windows. Also hiding and showing windows is not necessary. You can create one main window with buttons and a QStackedWidget that will contain the content of all other windows. Maybe you can even use QTabWidget instead of these buttons.

(Qt Creator - Cpp Based Application) Q<Objects> VS using Pointers?

here is my code:
//MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QTextEdit *textEdit;
};
#endif // MAINWINDOW_H
// MainWindow.cpp
#include "mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
{
textEdit = new QTextEdit();
}
MainWindow::~MainWindow()
{
delete textEdit;
}
//main.cpp
#include <QtGui>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Is it more efficient (here's the "Q[Objects] VS using Pointers?" part of the question) to:
1) Use pointers as I am actually doing or
2) Use objects (removing * + delete statement)
Thank you!
MainWindow::MainWindow(QWidget *parent)
{
textEdit = new QTextEdit(this);
}
MainWindow::~MainWindow()
{
}
For QObject members as pointers, you shouldn't use delete, the QTextEdit will probably be a child of MainWindow, so it will be deleted automatically.
It would, of course, be theoretically faster to use non-pointer QObject members, with one less level of indirection. Like this (for those who didn't understand the question):
class MainWindow : public QMainWindow {
...
private:
QTextEdit textEdit;
};
and there is also less code to type, because you don't have to retype the class name of the members to initialize them in the constructor.
But since QObject are themselves already heavily using indirection (with their d-pointer), the gain will probably be negligible. And the extra code you type with pointer members allows you to have a lower coupling between your header files and Qt, because you can use forward declarations instead of header inclusion, which means faster compilations (especially if you are not using precompiled headers yet) and recompilations.
Also,
manually deleting QObject pointer members, or
declaring QObject as non-pointers members
can causes double deletion, if you don't respectively delete/declare them in the right order (children then parents for deletion, or parents then children for declaration).
For example:
class MainWindow : public QMainWindow {
...
private:
QTextEdit textEdit;
QScrollArea scrollArea;
};
MainWindow::MainWindow() {
setCentralWidget(&scrollArea);
QWidget *scrolledWidget = new QWidget(&scrollArea);
QVBoxLayout *lay = new QVBoxLayout(scrolledWidget);
lay->addWidget(...);
lay->addWidget(&textEdit); // textEdit becomes a grand-child of scrollArea
scrollArea.setWidget(scrolledWidget);
}
When MainWindow is deleted, its non-static class members are deleted in the reverse order of their declaration in the class. So scrollArea is destroyed first then textEdit, but scrollArea also destroys its children including textEdit, so textEdit is effectively destroyed twice causing a crash.
So it is less error prone to use QObject members as pointers, and to not delete the QObject which have a parent yourself.
Try creating QLineEdit on the stack and then put it into layout... Quit your application... What do you see? HINT: launch your application in debugger.
ksming is right about reading documentation. It is not language specific issue. If you are asking what is faster: heap or stack allocation then form your question properly.