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.
Related
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`
};
I was implementing a custom camera controller for Qt3DRender::QCamera and I faced a rather strange behavior of the Qt3DInput::QMouseHandler. Depending on the environment it was created it either responds to mouse events or not. There are two cases: create both the device and the handler in the MainWindow object or create them inside my camera controller class (it only works in the first case).
First case:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto* window = new Qt3DExtras::Qt3DWindow();
auto* window_container = QWidget::createWindowContainer(window, this, Qt::Widget);
setCentralWidget(window_container);
auto* scene = new Qt3DCore::QEntity();
window->setRootEntity(scene);
auto* mouse_device = new Qt3DInput::QMouseDevice(scene);
auto* mouse_handler = new Qt3DInput::QMouseHandler(scene);
mouse_handler->setSourceDevice(mouse_device);
connect(mouse_handler, &Qt3DInput::QMouseHandler::positionChanged,
[](Qt3DInput::QMouseEvent* event)
{
qDebug() << "I am actually printing to console!!!";
});
}
Second case:
class CustomCameraController final : public Qt3DCore::QNode
{
Q_OBJECT
public:
explicit CustomCameraController(Qt3DCore::QNode* parent = nullptr)
: Qt3DCore::QNode(parent),
mouse_device(new Qt3DInput::QMouseDevice(this)),
mouse_handler(new Qt3DInput::QMouseHandler(this))
{
mouse_handler->setSourceDevice(mouse_device);
connect(mouse_handler, &Qt3DInput::QMouseHandler::pressAndHold, this,
&CustomCameraController::MousePositionChanged);
}
public slots:
void MousePositionChanged(Qt3DInput::QMouseEvent* event)
{
qDebug() << "I am not printing anything...";
}
protected:
Qt3DInput::QMouseDevice* mouse_device;
Qt3DInput::QMouseHandler* mouse_handler;
};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto* window = new Qt3DExtras::Qt3DWindow();
auto* window_container = QWidget::createWindowContainer(window, this, Qt::Widget);
setCentralWidget(window_container);
auto* scene = new Qt3DCore::QEntity();
window->setRootEntity(scene);
auto* controller = new CustomCameraController(scene);
}
All the unnecessary code was removed. The main.cpp file was automatically generated by Qt Framework
I searched all through the Qt documentation and found nothing that would help me in this scenario. I also noticed that if the device and the handler are initialized in the constructor with parent as the parameter it does not help. Furthermore, I tried to create the device and the handler in the MainWindow scope and pass them to the controller via some setter function but it does not help neither.
So the questions I want to ask: what is the proper way of using Qt3DInput::QMouseDevice and Qt3DInput::QMouseHandler? Is there a better workaround for implementing input handling for my custom camera controller?
Update 1:
You should add the controller class declaration to the header instead of main window source file. Here are all the includes and the qmake options you are going to need:
#include <Qt3DCore/QNode>
#include <Qt3DInput/QMouseDevice>
#include <Qt3DInput/QMouseHandler>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DCore/QEntity>
3dinput 3dcore 3dextras
Looks like you just connected to different signals.
In first case you are using &Qt3DInput::QMouseHandler::positionChanged which will be sended quite often. In second one - &Qt3DInput::QMouseHandler::pressAndHold which will be sended when a mouse button is pressed and held down.
After fix both logging functions are called.
I need to open a new QMainWindow when i click on a button.I would understand why it works with a pointer and does not work with a reference :
the slot that fires a new window is the following ,it should open two window but only the window created with the new operator shows up:
MyWin win1(this);
win1.show();
MyWin *win2 = new MyWin(this);
win2->show();
the following are MyWin.h and MyWin.ccp
#ifndef MyWin_H
#define MyWin_H
#include <QMainWindow>
namespace Ui {
class FrmManipolo1;
}
Class MyWin : public QMainWindow
Q_OBJECT
public:
explicit MyWin(QMainWindow *parent = 0);
~MyWin();
private:
Ui::MyWin *ui;
};
#endif
MyWin.cpp
include "MyWin.h"
include "ui_MyWin.h"
MyWin::MyWin(QMainWindow *parent) :
QMainWindow(parent),
ui(new Ui::MyWin)
{
ui->setupUi(this);
}
MyWin::~MyWin()
{
delete ui;
}
This doesn't work:
MyWin win1(this);
win1.show();
because it creates the win1 object on the stack, so the win1 object is destroyed at the end of the current scope, before it can actually be drawn.
This works:
MyWin *win2 = new MyWin(this);
win2->show();
because the object is allocated on the heap and it's lifetime doesn't end at the current scope, it ends when you call delete on it's address (the win2 pointer, that only holds the address of the object, not the actual object), or the parent will call delete in your case (because you pass the this pointer as a parent parameter to the constructor).
I'm trying to make a simple test to use an UI object made with "Qt Design" but I'm pretty new to Qt and C++.
I've got a quite simple Ui : 3 LineEdits and 1 PushButton :
IMAGE : the UI window
I've a Client Class which is supposed to control Ui. It connects the QPushButton and it should get the content from QLineEdit.
But the result in QDebug is always the same when I push the Button, even when I change QlineEdit field: "Client connected : "" : 0 "
Moreover, if I use on_pushButton_clicked made with QtDesign, it will display the real values of QlineEdits.
Why the QStrings are always the same ? Am I passing a copy of the initial object ? How to solve that ?
Is it the good way to make a ViewController ? Else, what is the good way?
Client.cpp
#include "client.h"
#include "mainwindow.h"
#include "logwindow.h"
Client::Client()
{
LogWindow* w1 = new LogWindow();
MainWindow* w2 = new MainWindow();
_stack = new QStackedWidget();
_stack->addWidget(w1);
connect(w1->getButton(),SIGNAL(clicked()),this,SLOT(connexion()));
_stack->addWidget(w2);
_stack->show();
}
//When the button is Pushed, gets the content from QlineEdits and prints them
void Client::connexion()
{
QString ip=(LogWindow (_stack->currentWidget())).getIP();
int port=((LogWindow (_stack->currentWidget())).getPort()).toInt();
socket = new QTcpSocket(this);
socket->connectToHost(ip, port);
_stack->setCurrentIndex((_stack->currentIndex()+1)%_stack->count());
qDebug() <<"Client connected : " << ip << ":"<<port;
}
And a class made automatically by Qt :
LogWindow.cpp
#include "logwindow.h"
#include "ui_logwindow.h"
LogWindow::LogWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::LogWindow)
{
ui->setupUi(this);
}
LogWindow::~LogWindow()
{
delete ui;
}
QPushButton* LogWindow::getButton()
{
return ui->pushButton;
}
QString LogWindow::getIP()
{
//LineEdit named "IP_text"
return ui->IP_text->text();
}
QString LogWindow::getPort()
{
//LineEdit named "Port_text"
return ui->Port_text->text();
}
LogWindow.h
namespace Ui {
class LogWindow;
}
class LogWindow : public QWidget
{
Q_OBJECT
public:
explicit LogWindow(QWidget *parent = 0);
~LogWindow();
QPushButton* getButton();
QString getIP();
QString getPort();
private slots:
void on_pushButton_clicked();
private:
Ui::LogWindow *ui;
};
Thuga solved it :
In Client::connexion you are creating a new instance of LogWindow.
Make LogWindow* w1 a member variable of your Client class, if you want
to access it in other Client's member functions as well.
There is not much to complain about, except that _stack is a widget
without a parent, so you must make sure you destroy it when you don't
need it anymore (for example call delete _stack; in the destructor).
Most beginners would have tried to make the ui variable public to get
the data from IP_text, but you did correctly, by making the
LogWindow::getIP function.
If you don't want to expose ui->pushButton outside of your class, you
can make a signal for your LogWindow class, and connect the clicked
signal of ui->pushButton to that signal. You can connect signals to
signals, it doesn't have to be a slot.
I have a school project where I am using Qt to drive my GUI interface. I need to know the best way or the easiest way to transfer a vector of class objects between the different .cpp files for the different forms. I was thinking of including the .h files and making a setPointer and getPointer that points to the vector, but is there a better way?
Thanks for the help
Let's assume that, you are using two forms. formA and formB.
Create a signal and slot in forma.cpp
public slots:
void receiveData(QVectorobjects);
signals:
void sendData(QVector);
Do the same for formb.cpp.
Now connect formA and formB like this.
connect(formA, SIGNAL(sendData(QVector<MyClass>)), formB, SLOT((receiveData(QVector<MyClass>)));
connect(formA, SIGNAL(receiveData(QVector<MyClass>)), formB, SLOT((MyClass(QVector<MyClass>)));
Now formA will share data (set of objects) when you write emit sendData(QVector() << objA << objB); and formB will catch it!
Enjoy the magic of signal and slot. :)
You should use custom signals and slots.
Your main window can connect signal and slot between each form.
In this way, you forms are independent of each other (i.e. doesn't need a pointer).
First of all, Qt container classes are implicitly shared, that means you can pass them by value, and only a shallow copy will occur. If you attempt to modify the container, then a new copy will be created. So there is no need to use pointers in that particular case.
Then, use signals and slot to do the actual data transfer - the common pattern is for the parent widget to manage its child widgets, and it is that parent class that the actual passing of data usually takes place.
The best way to transfer data between Qt-classes is to use signal/slot system.
Pay an attention, that if you want to transfer data with type differ from standard C++ and Qt, you should register it's type with qRegisterMetaType
Depending upon your usage, there can be at least two ways.
First is to create a public variable in your class (form) to which you can assign the current value of the vector (pointer) so that you can access it in that class.
Another option is to create a singleton class in the application and store the vector pointer inside that class. This will allow access to this class throughout the application.
Based on your requirement, if you want the vector to stay alive for the application life, you should opt the second option, otherwise opt the first option.
What about extern keyword? But Qt's signal slot is safe.
Use QVector or QList or any number of Qt's container classes. You can pass an iterator to your forms, or a reference (QList::operator[]) to the form so that you're not copying the data.
If you want to pass the whole vector, pass it as a reference. For example:
//pass the whole vector as for read-write
void doStuffOnMany(QList<MyClass>& listref) {} //declaration
...
QList<MyClass> mylist; //usage
doStuffOnMany(mylist);
//read-only
void doStuffOnMany(const QList<MyClass>& listref) {}
//pass one portion of the vector for read-write
void doStuffOnOne(MyClass& classref) {} //declaration
...
QList<MyClass> mylist; //usage
doStuffOnOne(mylist[0]);
Also, the Qt container classes are implicitly shared, so you don't even necessarily have to pass a reference to the vector if you need good performance.
I ended up using the extern keyword. I looked in to custom signals and slots and I think that it would be the better way to go, but given time and the fact that this is for school I went with the fast and dirty way for now.
Here is a simple explanation:
Take two forms:
Dialog windows
Dashboard and Sensor
on Dashboard:
#ifndef DASHBOARD_H
#define DASHBOARD_H
#include "sensor.h"
#include <QDialog>
namespace Ui {
class dashboard;
}
class dashboard : public QDialog
{
Q_OBJECT
public:
explicit dashboard(QWidget *parent = 0);
QTimer *timer;
~dashboard();
public slots:
void MyTimerSlot();
private slots:
void on_pushButton_clicked();
private:
Ui::dashboard *ui;
double mTotal;
sensor *snsr;
};
#include "dashboard.h"
#include "ui_dashboard.h"
#include <QDebug>
#include <QTimer>
#include <QMessageBox>
dashboard::dashboard(QWidget *parent) :
QDialog(parent),
ui(new Ui::dashboard)
{
ui->setupUi(this);
this->setWindowTitle(QString("dashboard"));
// create a timer
timer = new QTimer(this);
// setup signal and slot
connect(timer, SIGNAL(timeout()),
this, SLOT(MyTimerSlot()));
timer->stop();
mTotal = 0;
snsr = new sensor(this);
// msecx
}
dashboard::~dashboard()
{
delete ui;
}
void dashboard::on_pushButton_clicked()
{
snsr->show();
}
void dashboard::MyTimerSlot()
{
mTotal += 1;
snsr->setValue(mTotal);
ui->sensorlabel->setText(QString::number(mTotal));
}
Now on Sensor: sensor.h
#ifndef SENSOR_H
#define SENSOR_H
#include <QTimer>
#include <QDialog>
namespace Ui {
class sensor;
}
class sensor : public QDialog
{
Q_OBJECT
public:
explicit sensor(QWidget *parent = 0);
~sensor();
public slots:
void setValue(double value);
signals:
void changeLabel();
void valueChanged(double newValue);
private:
Ui::sensor *ui;
double mTotal;
};
#endif // SENSOR_H
sensor.cpp
#include "sensor.h"
#include "ui_sensor.h"
#include "dashboard.h"
sensor::sensor(QWidget *parent) :
QDialog(parent),
ui(new Ui::sensor)
{
ui->setupUi(this);
this->setWindowTitle(QString("sensor"));
connect(this, SIGNAL(valueChanged(double)), this, SLOT(changeLabel()));
}
void sensor::changeLabel()
{
ui->sensorlabel->setText(QString::number(mTotal));
}
void sensor::setValue(double value)
{
if (value != mTotal) {
mTotal = value;
emit changeLabel();
}
}
sensor::~sensor()
{
delete ui;
}