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`
};
Related
My GUI class in constructor is creating new object of my database class. It looks like that:
GUI::GUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
Baza *plik = new Baza();
connect(ui.insertBtn, &QPushButton::clicked, this, &GUI::run);
}
I've managed to get user input from QDialog:
void GUI::run() {
DialogInput dialog;
dialog.exec();
site_text = dialog.getSite();
}
How should I pass site_text to function in Baza class? I need to use that object (plik) created in GUI constructor but I can't access it from GUI::run() function.
Add plik to the declaration of GUI:
class GUI : public QWidget {
// ...
Baza* plik;
};
then in the constructor
GUI::GUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
plik = new Baza();
connect(ui.insertBtn, &QPushButton::clicked, this, &GUI::run);
}
As your code stands, plik is leaked as soon as GUI constructor completes.
Clean up plik in the destructor:
GUI::~GUI()
{
// ...
delete plik;
}
Alternatively, use std::unique_ptr to store plik in GUI so you don't need to remember to destruct it. Or, if plik benefits from deriving from QObject (e.g. for signals and slots), you can parent it to the GUI and Qt will handle the destruction. In both cases, this advice assumes plik has the same lifetime as GUI.
When you create a pointer inside the constructor the scope of the object is till the end of the constructor.
You need to create a global private variable to GUI class for that variable to be accessed by all the method in the same class. Baza * pLink;
When you create a pointer in the constructor, do not forget to delete the same pointer in the Destruction.
class GUI : public QWidget{
//...
GUI();
~GUI();
private:
Baza * pLink;
}
GUI::GUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
pLink = new Baza();
connect(ui.insertBtn, &QPushButton::clicked, this, &GUI::run);
}
GUI::~GUI()
{
delete pLink;
}
void GUI::run() {
DialogInput dialog;
dialog.exec();
site_text = dialog.getSite();
/* use the pointer to call the method to pass site_text */
pLink->SomeMethod(site_text);
}
Naming convention would play a big role when you are declaring local variables for the function and the global variables for the class.
So use pLink or consider using m_pLink where m_ would be added to all the global variable and p for pointer type.
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
I am making a C++ application in Qt and want to load a login keyboard (QWidget) whenever I call the constructor of the corresponding ui-class. The constructor is called everytime I switch to my login window. When I leave this window, the destructor is called and everything is destroyed, so i don't leave a single bit in my RAM. i want also just to have one instance the keyboard (singleton) and then hide() and show() whenever needed.
When I call the constructor the first time, i create an instance of my keyboard and add it to my verticalLayout. This works fine. But when i call the constructor for a second time, e.g. when I switch to another window and switch back to my login window, then my static keyboard becomes unreachable. This is what my debugger says...it's unreachable. So i already have an instance of my keyboard and i just want to add it to my verticalLayout again and I don't get it why i can't access it. Maybe it is some property of static variables, i really don't as I am new to C++. So here is my code
#ifndef LOGINKEYBOARD_H
#define LOGINKEYBOARD_H
#include <QWidget>
namespace Ui
{
class LoginKeyboard;
}
class LoginKeyboard : public QWidget
{
Q_OBJECT
public:
explicit LoginKeyboard(QWidget *parent = 0);
~LoginKeyboard();
static LoginKeyboard * instance()
{
if (!loginKeyboard)
{
loginKeyboard = new LoginKeyboard();
}
return loginKeyboard;
}
private:
Ui::LoginKeyboard *ui;
static LoginKeyboard * loginKeyboard;
private slots:
};
#endif // LOGINKEYBOARD_H
#include "headerFiles/loginkeyboard.h"
#include "ui_loginkeyboard.h"
LoginKeyboard *LoginKeyboard::loginKeyboard = 0;
LoginKeyboard::LoginKeyboard(QWidget *parent) : QWidget(parent), ui(new Ui::LoginKeyboard)
{
ui->setupUi(this);
}
LoginKeyboard::~LoginKeyboard()
{
delete ui;
}
#include "headerFiles/support.h"
#include "ui_support.h"
#include "headerFiles/mainwindow.h"
#include "headerFiles/loginkeyboard.h"
Support::Support(QWidget *parent) : QWidget(parent), ui(new Ui::Support)
{
ui->setupUi(this);
MainWindow::setPreviousPage(MainWindow::widgetStack->first());
ui->verticalLayout->addWidget(LoginKeyboard::instance()); //error when it gets called the 2nd time
}
Support::~Support()
{
delete ui;
}
When you add your static instance of LoggingKeyboard it will be deleted by it when the layout is destroyed.
See here
Note: The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it.
So it's not a good idea to have a singleton subclass of QWidget. If you really need the singleton property - you could extract the necessary functionality to a different class (which will not be subclassing QWidget) and use it from LoginKeyboard. However, if you don't really need it - then just don't do it - singletons should be avoided as much as possible because they are just glorified versions of global variables and may cause a wide variety of hard-to-track bugs.
Everywhere only just "before QPaintDevice" questions and nowhere is my error. So, here we go.
I need an extern QWidget to be able to get access to it from outside (because I don't know any other ways to do it). Basically, I need this: Create 2 QWidgets from 1 window, go to first window and from there hide main window and show second window created by main window (although main window is not main(), it is QWidget too).
I added
extern QWidget *widget = new QWidget
everywhere and everyhow in possible ways, and I still got this message. I suppose, it means that I need to create my QApplication (in main.cpp) and only then declare any QWidgets. But then HOW can I access those QWidgets from another QWidgets?
Code is here:
https://github.com/ewancoder/game/tree/QWidget_before_QApp_problem
P.S. The final goal is to be able show and hide both gamewindow.cpp and world.cpp from battle.cpp (just regular class)
And btw, adding Q_OBJECT and #include both don't work.
Anyway, if I cannot use functions from one window to another, than what's the point? I can have one window in another, and then another in that one, and then one in that another... but I can't do anything from the last to the previous. After years on Delphi that seems strange to me.
Don't use extern or otherwise static variables which lead to creation of the widget before the QApplication is created in main. The QApplication must exist before the constructor of the QWidget is executed.
Instead of sharing the variable via extern, either make the other windows members of the main window, and then make the windows known to each other by passing around pointers, or keep them private in MainWindow and request the actions from the subwindows e.g. via signal/slots. As a generic rule, don't use global variables but class members.
In the following FirstWindow (which is supposed hide main window and secondWindow) gets the main window and the second window passed via pointers and then just calls show/hide on them directly.
int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
In main window, have two members for the two other windows, say FirstWindow and SecondWindow:
class MainWindow : public QMainWindow {
...
private:
FirstWindow *m_firstWindow;
SecondWindow *m_secondWindow;
};
MainWindow::MainWindow(QWidget *parent) {
m_firstWindow = new FirstWindow; //not pass this as parent as you want to hide the main window while the others are visible)
m_secondWindow = new SecondWindow;
m_firstWindow->setMainWindow(this);
m_firstWindow->setSecond(m_secondWindow);
m_firstWindow->show(); //Show first window immediately, leave second window hidden
}
MainWindow::~MainWindow() {
//Manual deletion is necessary as no parent is passed. Alternatively, use QScopedPointer
delete m_firstWindow;
delete m_secondWindow;
}
FirstWindow, inline for brevity:
class FirstWindow : public QWidget {
Q_OBJECT
public:
explicit FirstWindow(QWidget *parent = 0) : QWidget(parent) {}
void setMainWindow(MainWindow *mainWindow) { m_mainWindow = mainWindow); }
void setSecondWindow(SecondWindow *secondWindow) { m_secondWindow = secondWindow; }
private Q_SLOTS:
void somethingHappened() { //e.g. some button was clicked
m_mainWindow->hide();
m_secondWindow->show();
}
private:
MainWindow* m_mainWindow;
SecondWindow* m_secondWindow;
};
Maybe not helping the former author, but others facing the problem.
I simply got this error by mistaking a debug-library with a release one. So check your linker settings, if you are sure the implementation is done right (first instancing application and then using widgets).
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();
}