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;
}
Related
the runnable project is here:
enter link description here
I sincerely glad to have your detail answers to solve this, but I am still confusing on this issue:
case 1: changing socket_session as a member variable of mainwindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
SocketThread* socket_session;
private:
...
But this is not the solution to access setFlag, even after I change the `Form1::on_qpushButton__set_white_level_0_clicked()' function like this:
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
Still it doesn't make sense because form1 instance doesn't have "the" instance of socket_thread which has been instantiated from mainwindow.
There's a solution I think is making another class that includes all instances that I want to use from inside of mainwindow but I don't think that is a good one because I am using thread and accessing a global big instance class that includes all of them to be "shared" is not a good idea for someone like me.
#include <form1.h>
#include <ui_form1.h>
#include "socketthread.h"
Form1::Form1(QWidget *parent) :
QWidget(parent),
ui(new Ui::Form1) {
ui->setupUi(this);
}
Form1::~Form1() {
delete ui;
}
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
socket_session->setThreadFlag(true);
}
enter image description here
I know I am lack of understanding about this but, do I wanna make something nobody does...? I think everyone wants to separate all objects and their methods clearly and communicate via signals or calling functions from delivered object instances...
case 2: ... let me try how you suggested make possible first...
I can read C++ code and overall structure, but I don't know why I have to struggle with this, so please help me, dear Guru.
On socketthread.h :
class SocketThread : public QThread {
Q_OBJECT
public:
QTcpSocket *socket_session;
SocketThread();
~SocketThread(){}
bool connectToServer(QString, int);
void sendData(const char*, int, int);
void run(void);
private:
QString message;
volatile bool threadFlag;
signals:
void changedThreadFlag(void);
void changedMessageStr(void);
void setThreadFlag(bool);
void setMessageStr(QString);
private slots:
void setStr(QString);
void setFlag(bool);
void socketError(QAbstractSocket::SocketError);
};
And its implementation is...
SocketThread::SocketThread() {
socket_session = NULL;
threadFlag = false;
message = "NULL";
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
}
...
void SocketThread::setStr(QString str) {
message = str;
}
void SocketThread::setFlag(bool flag) {
threadFlag = flag;
}
void SocketThread::run() {
while(true) {
if(threadFlag) {
QThread::msleep(100);
qDebug() << message;
} else
break;
}
qDebug() << "loop ended";
}
And I have one form which has a button, and I put a clicked() slot of it like this...
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
--how can I emit the signal of the one of socketthread from here??
}
Now, the mainwindow is like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
QString addr_server = "223.194.32.106";
int port = 11000;
SocketThread* socket_session = new SocketThread();
socket_session->connectToServer(addr_server, port);
ui->setupUi(this);
Form1* form1;
form1 = new Form1();
ui->stackedWidget_mainwindow->addWidget(form1);
ui->stackedWidget_mainwindow->setCurrentWidget(form1);
socket_session->run();
...
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
Once the socket_session->run() started, I need to change the threadFlag by clicking the button by emitting setThreadFlag() of one's from the running thread. And I just stuck in here.
Does it possible even?
Or am I doing this all wrong from the beginning?
As mentioned in this post:
"Emitting a signal" == "calling a function"
So all you really have to do is call the signal function, and all connected slots should be called.
This of course means that the Form1 object needs a pointer to the thread object, i.e. it needs a copy of socket_session. Then you can simply call the signal on the object
socket_session->setThreadFlag(your_flag);
Of course, if the Form1 have a copy of the socket_session pointer, it might as well call setFlag directly, if it was public.
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
No signal is needed – just call the function.
void Form1::on_qpushButton__set_white_level_0_clicked() {
qDebug() <<"clicked()";
// --how can I emit the signal of the one of socketthread from here??
// E.g. this way:
socket_session->setThreadFlag(true);
}
To make this possible, another fix is needed:
socket_session is a local variable in OP's exposed code.
To make it "persistent", it has to become e.g. a member variable.
So, the constructor MainWindow::MainWindow() has to be changed:
// Nope: SocketThread* socket_session = new SocketThread();
// Instead:
socket_session = new SocketThread();
and SocketThread* socket_session; has to be added to member variables of class MainWindow.
To make it accessible in Form1, it has to be passed to Form1 as well.
This could be done e.g. by making it a member variable in Form1 also which is initialized with a constructor argument (or set from MainWindow afterwards).
(I must admit that I never have used the Qt UI builder QtDesigner but build all my UIs by C++ code exclusively.)
But, now, another fix is necessary:
volatile doesn't make a variable suitable for interthread communication.
(This was used in ancient times before multi-threading started to be supported by C++11.)
However, this is wrong: Is volatile useful with threads?
An appropriate fix would be to use std::atomic instead:
// Wrong for interthread-com.
//volatile bool threadFlag;
// Correct:
std::atomic<bool> threadFlag; // #include <atomic> needed
FYI: SO: Multithreading program stuck in optimized mode but runs normally in -O0
And, finally, in SocketThread::SocketThread():
connect(this, SIGNAL(setThreadFlag(bool)), this, SLOT(setFlag(bool)));
is not necessary in this case.
SocketThread::setThreadFlag() could call SocketThread::setFlag() directly, or even write threadFlag itself:
void setThreadFlag(bool flag) { threadFlag = flag; }
As I (recommended to) make threadFlag atomic, it can be accessed from any thread without causing a data race.
Update:
After OP has updated the question:
I just simply want to emit the signal setThreadFlag of the socketthread from inside of QPushbutton_clicked() slot.
The button (created from UI Form1) can be connected in the MainWindow as well (without using any method of Form1):
QObject::connect(form1->button1, &QPushButton::clicked,
socket_session, &SocketThread::setThreadFlag,
Qt::QueuedConnection);
Notes:
About form1->button1, I'm not quite sure.
I noticed that widgets in UI generated forms can be accessed this way but I don't know the exact details (as I never used the Qt UI builder on my own).
I used the Qt5 style of QObject::connect().
This is what I would recommend in any case.
The Qt5 style is verified at compile time. –
Wrong connections are detected by the C++ type checking.
Additionally, any function with matching signature can be used – no explicit exposure of slots is anymore necessary.
Even conversion of non-matching signature or adding additional parameters becomes possible by using C++ lambdas which are supported as well.
Qt: Differences between String-Based and Functor-Based Connections
It is possible to connect signals and slots of distinct threads.
I used Qt::QueuedConnection to remark this as interthread communication.
(However, I roughly remember that Qt might be able to detect it itself.
See the doc. for Qt::AutoConnection which is the default.
Further reading: Qt: Signals & Slots
Btw. using the Qt signals for inter-thread communication would exclude the necissity to make SocketThread::threadFlag() atomic. It could become a simple plain bool threadFlag; instead. The slot SocketThread::setThreadFlag() is called in the Qt event loop of QThread, in this case.
I want to enable a pushbutton in a callback function. I have tried to do the following but I have got:
Runtime received SIGSEGV (address: 0x28 reason: address not mapped to object)
class MyWindow: public QDialog
{
Q_OBJECT
public:
QPushButton *Btn;
void Scan();
....
};
extern void StartScan(pfcallback);
void MyWindow::Scan()
{
Btn->setEnabled(false);
StartScan(Scanfinished);
}
void static Scanfinished()
{
Btn->setEnabled(true);
}
How to access the button in the callback function Scanfinished() ?
You're attempting to manually manage memory. As you can see, it's very easy to use a dangling pointer or commit other blunders. Instead, let the compiler do it for you.
You use static incorrectly.
If I were to do it, I'd do as follows. The destructor is generated by the compiler and will correctly release all resources and reset m_instance to a null value.
class MyWindow : public QDialog
{
Q_OBJECT
static QPointer<MyWindow> m_instance;
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
Q_ASSERT(! m_instance);
m_instance = this;
m_layout.addWidget(&m_button);
}
void Scan();
static void ScanFinished();
};
QPointer<MyWindow> MyWindow::m_instance;
void StartScan(void(*callback)());
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinished);
}
void MyWindow::ScanFinished()
{
m_instance->m_button.setEnabled(true);
}
At this point it's rather obvious that the API of StartScan is horribly broken, and this brokenness forces the use of a singleton MyWindow. When doing any kind of callbacks, you never use a sole C function pointer. You must accept both a function pointer that takes a void* and a void* that will be used to carry the data the function needs to work. This is an idiom. If you use C-style callbacks, you cannot not use the idiom without severely crippling the usability of your API.
Thus, this is a complete example and works in both Qt 4 and Qt 5. You should have posted something like it - a self-contained test case - in your question. It compiles and it works and you can even get the complete Qt Creator project from github. It will compile and run on all platforms supported by current Qt. It's not supposed to be hard: that's why you're using Qt, after all. Getting in the habit of creating such concise test cases to demonstrate your issues will make you a better developer, and make your questions much easier to answer.
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-callback-43094825
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#include <QtConcurrent>
#endif
class MyWindow: public QDialog
{
Q_OBJECT
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
Q_SIGNAL void ScanFinished();
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
m_layout.addWidget(&m_button);
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(Scan()));
connect(this, SIGNAL(ScanFinished()), this, SLOT(OnScanFinished()));
}
Q_SLOT void Scan();
static void ScanFinishedCallback(void* w);
Q_SLOT void OnScanFinished();
};
void StartScan(void(*callback)(void*), void* data) {
// Mockup of the scanning process: invoke the callback after a delay from
// a worker thread.
QtConcurrent::run([=]{
struct Helper : QThread { using QThread::sleep; };
Helper::sleep(2);
callback(data);
});
}
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinishedCallback, static_cast<void*>(this));
}
void MyWindow::ScanFinishedCallback(void* data)
{
emit static_cast<MyWindow*>(data)->ScanFinished();
}
void MyWindow::OnScanFinished()
{
m_button.setEnabled(true);
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MyWindow w;
w.show();
return app.exec();
}
#include "main.moc"
Of course StartScan cannot do the work in the thread it was called from: it'd block the GUI thread and make your application unresponsive. That's the prime source of bad user experience. Instead, it should spawn a concurrent job that will notify the caller when the scanning is done.
Since the callback will be called from that concurrent thread, it's not safe to use MyWindow's non-thread-safe methods. The only thread-safe methods are signals - thus we can emit a signal that Qt will the safely forward to MyWindow's thread and invoke OnScanFinished from the right thread.
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.
I want to pass a string from a form that is opened by the first form to the first form.
I am new to C++.
Here is my code.
Form1.h // main form
#include "dialog.h"
namespace Ui {
class Form1;
}
class Form1 : public QMainWindow
{
Q_OBJECT
public:
explicit Form1(QWidget *parent = 0);
~Form1();
void refresh(QString str_local);
private slots:
void on_pushButton_clicked();
private:
Ui::Form1 *ui;
Dialog *dialog1;
};
// form1.cpp
void Form1::on_pushButton_clicked()
{
dialog1= new Dialog; //Create new form with other class
dialog1->show();
QObject::connect(dialog1, SIGNAL(change(str_remote)), this, SLOT(refresh(str_local))); //Connect when is emit signal cambia in the child form and pass the string to local function
}
void Form1::refresh(QString str_local)
{
qDebug() << "Back to main" << str_local;
ui->label->setText(str_local);
}
// dialog.h the second form that should pass the value to main form
...
class Dialog : public QDialog
{
Q_OBJECT
signals:
void change(QString s);
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void on_pushButton_clicked();
private:
Ui::Dialog *ui;
};
// dialog.cpp
...
void Dialog::on_pushButton_clicked()
{
QString name;
name = ui->lineEdit->text();
emit change(name);
this->close();
}
I get the error:
No such signal Dialog::change(str_remote) in ../Format/form1.cpp:22 .
You have some strange code in here:
QObject::connect(dialog1, SIGNAL(change(str_remote)), this, SLOT(refresh(str_local)));
Since your class already inherits QObject indirectly, you can simply drop the scope specifier.
You probably aim for using the new compilation-time syntax signal-slot mechanism.
You have not marked your slot as slot in the header file.
You are trying to use the old signal/slot syntax with variable names for the signal and slot as opposed to the types.
Your signal is not using the good practice of const T& (i.e. constant reference).
You are specifying this explicitly, whereas it can be dropped. This is just admittedly personal taste.
You do not follow the Qt signal/slot naming convention, e.g. your signal is a verb rather adjective. It is also too generic, rather than "fooChanged" as the good practice goes.
There are other issues in your code as well, but this time I only focused on that one line. I would use this line with modern Qt and C++ programming principles in mind:
connect(dialog1, &Dialog::changed, (=)[const auto &myString] {
ui->label->setText(myString);
});
However, since this requires CONFIG += c++14, if your compiler does not support that (e.g. VS2010), you can go for this:
connect(dialog1, SIGNAL(change(const QString&)), this, SLOT(refresh(const QString&)));
I would like to write a simple application that tells me when a file has been modified.
Does the <QFileSystemWatcher> class only monitor changes when the program is running?
If so, are there any other classes that I can use for file integrity monitoring?
You could run md5sum, etc. with QProcess initially and then for the changed signals and compare.
The alternative is to read all the file in or mmap and create your hash with QCryptoGraphicHash.
Either way, you would do this initially and then in the signal handlers, a.k.a. slots once the connection is properly made in your QObject subclass.
#include <QObject>
#include <QFileSystemWatcher>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = Q_NULLPTR)
: QObject(parent)
{
// ...
connect(m_fileSystemWatcher, SIGNAL(fileChanged(const QString&)), SLOT(checkIntegrity(const QString&)));
// ...
}
public slots:
void checkIntegrity(const QString &path)
{
// 1a. Use QProcess with an application like md5sum/sha1sum
// OR
// 1b. Use QFile with readAll() QCryptoGraphicsHash
// 2. Compare with the previous
// 3. Set the current to the new
}
private:
QFileSystemWatcher m_fileSystemWatcher;
};
Disclaimer: This is obviously not in any way tested, whatsoever, but I hope it demonstrates the concept.