Thread and GUI handling - c++

In my App I have some problems with threads and GUI messages like QMessageBox or a new dialog. To reproduce I made a small app to show the problem:
mainwindow.cpp
#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"
void ThreadAddTree::run() {
//mClass->addTreeEx();
bool b = false;
emit addTree(&b);
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString path = "";
mThreadAddTree = new ThreadAddTree(this, path);
connect(mThreadAddTree, SIGNAL(addTree(bool*)), this, SLOT(on_add_tree(bool*)), Qt::BlockingQueuedConnection);
//,Qt::DirectConnection
mThreadAddTree->start();
}
void MainWindow::on_add_tree(bool* newData) {
QMessageBox::information(this, tr("Information"),
tr("Button click!"));
*newData = true;
}
void MainWindow::addTreeEx()
{
QMessageBox::information(this, tr("Information"),
tr("Button click!"));
}
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QThread>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class ThreadAddTree : public QThread
{
Q_OBJECT
public:
ThreadAddTree(class MainWindow *nClass, const QString &path) {
mPath = path;
mClass = nClass;
}
signals:
void addTree(bool*);
protected:
void run();
QString mPath;
class MainWindow *mClass;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
friend class ThreadAddTree;
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void addTreeEx();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
protected:
ThreadAddTree *mThreadAddTree;
protected Q_SLOTS:
void on_add_tree(bool* newData);
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
If I use in Thread the call: mClass->addTreeEx(); the app will crash, in case of non main GUI thread. Understood.
So I uncouple the call with emit a message emit addTree(&b); works well. Messagebox is shown and no crash.
But now it becomes complicated for me. I need to call mClass->addTreeEx(); in my app because it will do a couple of operations. The same function is also used outside an additional thread.
But in one case, the mClass->addTreeEx(); that is running inside the thread need to call the Messagebox.
So my question is here, how to manage, that I can emit the emit addTree(&b); from the function mClass->addTreeEx(); if it was called from the thread and the app will not crash in case of no GUI thread?

Interpreting the code author's intent (to degree) and open to be corrected.
The signal parameter of type bool* in void addTree(bool*); makes not much sense especially for the case with signal sender having the boolean variable on the stack. Either make it void addTree(bool) and send immediate value or just void addTree() and handle the boolean atomic flag on the slot side as std::atomic_bool thread_safe_flag; so checking on that flag will be as actual as possible if (thread_safe_flag). But such handling requires even more to ensure the signal delivered at the right time in sync with the value. This is irrelevant to Qt, though: Why do I need to acquire a lock to modify a shared "atomic" variable before notifying condition_variable and can be done either with or without Qt.
The problem of message box on UI thread preventing the other message box from appearing (this is again an interpretation of the author's problem with the code). We obviously need to have a handle operate the message box, say, dismiss it, in case if it is open already:
QMessageBox* m_msgBoxPtr{nullptr};
std::atomic_bool m_threadSafeFlag;
void UI_Class::mySlotToHandleMsgBox()
{
if (m_msgBoxPtr != nullptr) {
m_msgBoxPtr->close();
m_msgBoxPtr->deleteLater();
m_msgBoxPtr = nullptr;
mySlotToHandleMsgBox();
}
else {
m_msgBoxPtr = new QMessageBox(QMessageBox::Information, title, message);
m_msgBoxPtr->exec(); // assuming we want modal dialog as QMessageBox::information()
// otherwise do m_msgBoxPtr->show()
// if this is set on UI thread only then and no
// "waits" for it on other threads then it being atomic is enough;
// then don't bother with any sync "complications"
m_threadSafeFlag = true;
}
}

mainworker.h
#ifndef MAINWORKER_H
#define MAINWORKER_H
#include <QObject>
class MainWorker : public QObject
{
Q_OBJECT
signals:
void completed(void);
public slots:
void run(void);
};
#endif // MAINWORKER_H
mainworker.cpp
#include "mainworker.h"
#include <QThread>
void MainWorker::run(void)
{
QThread::sleep(1);
emit completed();
}
mainthread.h
#ifndef MAINTHREAD_H
#define MAINTHREAD_H
#include <QThread>
class MainThread : public QThread
{
Q_OBJECT
public:
MainThread(void);
};
#endif // MAINTHREAD_H
mainthread.cpp
#include "mainthread.h"
MainThread::MainThread(void)
: QThread(nullptr)
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(void);
signals:
void runJob(void);
public slots:
void jobCompleted(void);
private:
QPushButton m_runButton;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(void)
: QMainWindow(nullptr),
m_runButton(this)
{
connect(&m_runButton, SIGNAL(released()), this, SIGNAL(runJob()));
m_runButton.setText("RUN!");
setCentralWidget(&m_runButton);
}
void MainWindow::jobCompleted(void)
{
QMessageBox::information(this, tr("Info"), tr("Job completed!"));
}
main.cpp
#include <QApplication>
#include "mainwindow.h"
#include "mainthread.h"
#include "mainworker.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow window;
MainThread thread;
MainWorker worker;
worker.connect(&window, SIGNAL(runJob()), &worker, SLOT(run()));
window.connect(&worker, SIGNAL(completed()), &window, SLOT(jobCompleted()));
worker.moveToThread(&thread);
thread.start();
window.show();
int exitCode = a.exec();
thread.quit();
thread.wait();
return exitCode;
}
Of course you can add args to signals and slots and call jobCompleted() slot any time from GUI thread.

Related

QThreading in QT and update GUI at the same time

Hello Im trying to print my result from a thread to textBrower in qtwidget QT but I cant, either I get error or the program wont compile
is there another way ?? how can I change the textBrowser outside of the class's function??
PS BTW I need to keep looping inside the thread cuz actually im getting some data from uart in final program (in this code i just wanna print "lol" which eventually I wanna change it with some other code which take data ) so I cant come out of the loop
eventually i want use some process from another library and show the resault REAL TIME
bool stop;
out::out(QWidget *parent) :
QWidget(parent),
ui(new Ui::out)
{
ui->setupUi(this);
ui->textBrowser->setText("lol");
}
out::~out()
{
delete ui;
}
///////////////////////////////////////////////
class t : public out, public QThread
{
public:
void run()
{
while(1){
qDebug()<<"hi"<<i;
// ui->textBrowser->setText("lol"); I tried to use this but it didnt worked
if(stop==true){
QThread::exec();
}
}
}
};
void mamad1(void){ //this function get called from another cpp file and its for starting the thread
stop=false;
t *b = new t;
b->start();
}
void out::on_pushButton_clicked() // a push button to stop the thread
{
stop=true;
}
I tried make ui in out.h file a public property and use ui->textBrowser->setText("lol"); but it didn't worked the program freezed and i got this
error : (Parent is QTextDocument(0x208d812a510), parent's thread is QThread(0x208d6816de0), current thread is QThread(0x208dac94e10)
I tried to use connect() also and didn't worked or I didn't use it right
The concept of QT the GUI thread is called the master thread. This thread has an event queue. In general, this event queue is populated by internal and external events. Moreover, the queue between threads is an efficient approach for thread communication. The same is true for the worker threads as well. When you call the start method through the worker threads their signal queue is created and ready to be consumed by the corresponding thread.
Let's come back to your question. The solution is simple. From your worker threads, you can just send a signal to the master thread. The master thread will see this event that modifies the GUI item and forwards this signal/event to the slot that is responsible to take action accordingly. Just define a signal in your worker thread and connect your master thread to this signal with a given slot.
UPDATE FOR SOLUTION
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <MyWorkerThread.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void setWorkerThread(MyWorkerThread* thread);
void connectToSignals();
public slots:
void handleTextBoxSignal(const QString& text);
private:
Ui::MainWindow *ui;
MyWorkerThread* m_worker_thread{nullptr};
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::setWorkerThread(MyWorkerThread* thread)
{
m_worker_thread = thread;
}
void MainWindow::connectToSignals()
{
QObject::connect(m_worker_thread,
SIGNAL(changeTextOnUI(QString)),
this,
SLOT(handleTextBoxSignal(QString)));
}
void MainWindow::handleTextBoxSignal(const QString& text)
{
qDebug() << "Text box change signal received with text: " << text;
auto text_box = findChild<QTextEdit*>("myTxtEdit");
if(text_box != nullptr)
{
text_box->setText(text);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
MyWorkerThread.h
#ifndef MYWORKERTHREAD_H
#define MYWORKERTHREAD_H
#include <QObject>
#include <QThread>
class MyWorkerThread : public QThread
{
Q_OBJECT
public:
MyWorkerThread(QObject* parent = nullptr);
void stopThread();
signals:
void changeTextOnUI(const QString& text);
private:
void run() override;
bool m_exit{false};
};
#endif // MYWORKERTHREAD_H
MyWorkerThread.cpp
#ifndef MYWORKERTHREAD_H
#define MYWORKERTHREAD_H
#include <QObject>
#include <QThread>
class MyWorkerThread : public QThread
{
Q_OBJECT
public:
MyWorkerThread(QObject* parent = nullptr);
void stopThread();
signals:
void changeTextOnUI(const QString& text);
private:
void run() override;
bool m_exit{false};
};
#endif // MYWORKERTHREAD_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
MyWorkerThread* worker_thread = new MyWorkerThread();
w.setWorkerThread(worker_thread);
w.connectToSignals();
worker_thread->start();
w.show();
return a.exec();
}
In the above code, you see the full solution to your problem. In the worker thread, we increment a static counter and concatenate it with a string and send it to the master thread that manages the UI elements. We emit a signal and this signal is landed on the slot. This way the master thread updates the text box on the screen per 5 seconds. The worker thread sleeps for 5 seconds at each iteration.

Trying to connect an emit signal, but nothing appears on the other side

So, I am learning my way around QThread and I understand it to a reasonable extent.
However, I am trying to implement a class derived from QThread to do a basic function, then emit a signal if a value has changed.
Let me post the Header and Source files:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include "mythread.h"
#include <QTextEdit>
#include <QPushButton>
#include <QSpinBox>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
~Dialog();
void setGUI();
void Start_Thread();
void Stop_Thread(); //will be implemented later to stop all threads
public slots:
void Update_O1(int);
private:
MyThread *m_Thread1;
QPushButton *START;
QPushButton *STOP;
QSpinBox *L1Input;
QSpinBox *L2Input; //For when a second Thread is added
QSpinBox *L3Input; //For when a third Thread is added
QTextEdit *L1Out;
QTextEdit *L2Out; //For when a second Thread is added
QTextEdit *L3Out; //For when a third Thread is added
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include <QGridLayout>
Dialog::Dialog(QWidget *parent)
: QDialog(parent), m_Thread1(new MyThread), START(new QPushButton("Start")),
STOP(new QPushButton("Stop")), L1Input(new QSpinBox), L2Input(new QSpinBox),
L3Input(new QSpinBox),L1Out(new QTextEdit),L2Out(new QTextEdit), L3Out(new QTextEdit)
{
setGUI();
connect(START, &QPushButton::clicked, this, &Dialog::Start_Thread);
connect(STOP, &QPushButton::clicked, this, &Dialog::Stop_Thread);
connect(m_Thread1, SIGNAL(NumberChanged(int)), this, SLOT(Update_01(int)));
//I know this is the old Syntax, but I don't know how else to do this...yet.
//I got a similar function to work on a different project using the same format
}
Dialog::~Dialog()
{
}
void Dialog::setGUI()
{
setWindowTitle("Three Threads");
resize(300,300);
START->setMaximumWidth(100);
STOP->setMaximumWidth(100);
L1Input->setRange(1,100);
L2Input->setRange(1,100);
L3Input->setRange(1,100);
L1Out->setReadOnly(true);
L2Out->setReadOnly(true);
L3Out->setReadOnly(true);
QGridLayout *GLout = new QGridLayout;
GLout->addWidget(START,0,1);
GLout->addWidget(STOP,0,2);
GLout->addWidget(L1Input,1,0);
GLout->addWidget(L2Input,1,1);
GLout->addWidget(L3Input,1,2);
GLout->addWidget(L1Out,2,0);
GLout->addWidget(L2Out,2,1);
GLout->addWidget(L3Out,2,2);
setLayout(GLout);
}
void Dialog::Start_Thread()
{
qDebug() << "START works"; //this is just to let me know the Start_Thread function is called properly
m_Thread1->start();
}
void Dialog::Stop_Thread()
{
}
void Dialog::Update_O1(int x)
{
qDebug() << QString::number(x);
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QObject>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
void run();
void setSnum(int); //setter function
bool Stop = false; //will be used later to stop a thread
signals:
void NumberChanged(int);
private:
int Snum = 10; //temporary value. will later implement setter to use value from GUI
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QDebug>
#include <QtCore>
MyThread::MyThread(QObject *parent)
: QThread{parent}
{
}
void MyThread::run()
{
while(!(Snum == 1))
{
QMutex mutex;
mutex.lock();
if(this->Stop) break;
mutex.unlock();
if(Snum % 2 == 0)
{
Snum /= 2;
}else{
Snum *= 3;
Snum += 1;
}
emit this->NumberChanged(Snum);
}
}
void MyThread::setSnum(int startnum)
{
Snum = startnum;
}
Lastely, a very basic main.cpp file
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
The problem I am facing though is that I don't seem to be getting a signal from the emit function in mythread.cpp's run function. I am not getting an output in the qDebug() section of QtCreator.
What am I doing wrong?
I am using Qt 6.3.0.
You have this connection:
connect(m_Thread1, SIGNAL(NumberChanged(int)), this, SLOT(Update_01(int)));
But your method is actually called like this:
void Dialog::Update_O1(int x)
Note Update_01 vs. Update_O1. They are different characters. One is zero and the other is capital 'o'.
So, you should have:
connect(m_Thread1, SIGNAL(NumberChanged(int)), this, SLOT(Update_O1(int)));
However, the best solution is to use the "new" signal-slot syntax.
connect(m_Thread1, &QThread::NumberChanged, this, &QDialog::Update_O1);
Actually, if the slot is short, you could even use a lambda:
connect(m_Thread1, &QThread::NumberChanged, this, [](int x) {qDebug() << QString::number(x);});
The major advantage of the new signal-slot syntax is that this sort of issue would be caught at compilation time rather than runtime. So, you would not potentially release your software with this bug.

QT C++ prevent Runtime Error when close app

I'm writing a QT application and everything is fine with building and working but when i close the app with a thread running, the app closes and shows a message:
[Runtime Error....].
The application output says:
QThread: Destroyed while thread is still running
The program has unexpectedly finished.
The process was ended forcefully.
example crashed.
how to solve that ?
Example:
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QString>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
example = new Thread(this);
connect(example, SIGNAL(print_line(QString)), this, SLOT(print_line2(QString)), Qt::BlockingQueuedConnection);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::print_line2(QString in)
{
ui->textBrowser->append(in);
}
void MainWindow::on_pushButton_clicked()
{
example->start();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <Thread.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Thread *example;
public slots:
void print_line2(QString in);
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Thread.cpp
#include "Thread.h"
#include <windows.h>
using namespace std;
Thread::Thread(QObject *parent):
QThread(parent)
{
}
Thread::~QThread()
{
delete ui;
}
void Thread::print(QString in)
{
print_line(in);
}
void Thread::run()
{
int count = 0;
for(;;) {
Sleep(100);
count += 1;
print(QString::number(count));
}
}
Thread.h
#ifndef READINFO_H
#define READINFO_H
#include <QThread>
class Thread : public QThread
{
Q_OBJECT
public:
explicit Thread(QObject *parent =0);
void print(QString in);
void run();
signals:
void print_line(QString x);
};
#endif
Ready example
The problem is that the thread is still in the running state when your application shuts down.
The code inside Thread::Run() contains an infinite loop -- there is no way for it to terminate by itself. You need to write your thread so that it will exit, or at the very least, you need to forcefully terminate the thread before your app closes.
To forcefully terminate, you could add two lines of code to the MainWindow destructor like so:
MainWindow::~MainWindow()
{
example->terminate();
example->wait();
(...)
}

How do I edit QMainWindow UI Widget From Another Class?

I need to edit a QLabel from MainWindow's UI in another source file. I've tried messing around with singals and slots, but honestly I'm completely lost and the Qt documentation doesn't help me in this exact situation. I understand that this has been asked in the past, but I have not found a solution that works for me. I'm new to Qt, and C++ in general.
I have the following code (greatly simplified):
"mainwindow.h":
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setFoo(char* text);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
"mainwindow.cpp"
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
this->statusBar()->setSizeGripEnabled(false);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::setFoo(char* text) {
ui->fooLabel->setText(text);
}
"secondwindow.h"
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QWidget>
namespace Ui {
class SecondWindow;
}
class SecondWindow: public QWidget {
Q_OBJECT
public:
explicit SecondWindow(QWidget *parent = 0);
~SecondWindow();
private:
Ui::SecondWindow*ui;
}
#endif // SecondWindow_H
"secondwindow.cpp"
#include "secondwinodw.h"
#include "ui_secondwinodw.h"
#include "mainwindow.h"
SecondWindow::SecondWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::SecondWindow) {
ui->setupUi(this);
}
SecondWindow::~SecondWindow() {
delete ui;
}
void SecondWindow::on_fooButton_clicked() {
MainWindow::setFoo("example");//The method is private so this is not possible, but this is my goal
}
When a user clicks on fooButton, I need to access and edit the MainWindow's UI QLabel(or a public method that does this).
The secondwindow is not being created in the main() function
void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_A:
if (event->modifiers()==Qt::ShiftModifier) {
SecondWindow*secwind= new SecondWindow();
secwind->show();
}
break;
}
}
In OOP the ones that interact are the objects, not the classes or the files, that is, the following expression:I need to edit QLabel from MainWindow's UI in another source file It does not make sense, what you should say is that an object of the MainWindow class is modified by another object of the SecondWindow class. The files do not make the program, the interaction between objects do it.
I'm assuming that both objects are created in the main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
SecondWindow w2;
w1.show();
w2.show();
return a.exec();
}
Now if I go to attack the main problem, Qt handles the concept of signals and slots, so we will use it, as the action to a SecondWindow object will cause the information to be sent, I will create a signal that carries that information:
secondwindow.h
#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H
#include <QWidget>
namespace Ui {
class SecondWindow;
}
class SecondWindow: public QWidget {
Q_OBJECT
public:
explicit SecondWindow(QWidget *parent = 0);
~SecondWindow();
signals:
void messageChanged(const QString & message); // <---
private slots:
void void SecondWindow::on_fooButton_clicked();
private:
Ui::SecondWindow*ui;
}
#endif // SecondWindow_H
when the button is pressed, the signal with the information must be emitted
secondwindow.cpp
...
void SecondWindow::on_fooButton_clicked() {
emit messageChanged("example");//The method is private so this is not possible, but this is my goal
}
Now we go to the receiver's side, how will we get a slots, you have done it but do not use char *, that's C, we're using C++ and much better we're using Qt, it's best to use QString:
mainwindow.h
....
void setFoo(const QString & text);
mainwindow.cpp
...
void MainWindow::setFoo(const QString & text) {
ui->fooLabel->setText(text);
}
And finally we make the connections:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w1;
SecondWindow w2;
QObject::connect(&w2, &SecondWindow::messageChanged, &w1, &MainWindow::setFoo);
w1.show();
w2.show();
return a.exec();
}
update:
void MainWindow::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_A:
if (event->modifiers()==Qt::ShiftModifier) {
SecondWindow*secwind= new SecondWindow();
connect(secwind, &SecondWindow::messageChanged, this, &MainWindow::setFoo);
secwind->show();
}
break;
}
}

Qt make modification of MainWindow from another class

I would like to make some modifications of the main window from another file.
I created another ui file Form1Window (which open when a button is cliked in the MainWindow).
I want to call from the class Form1Window a function named test() of the MainWindow class
I succeed in calling function test() but I can't execute the whole content of the function (I can display a message but can't execute the part where I want to clear an edittext)
MainWindow.h
#include "form1window.h"
public slots:
void nettoyer();
private slots:
void openFrom1();
private:
Ui::MainWindow *ui;
From1Window *uiFrom1;
};
MainWindow.cpp
void MainWindow::openFrom1()
{
uiFrom1 = new From1Window(this);
uiFrom1->show();
}
void MainWindow::nettoyer(){
QMessageBox msgBox;
msgBox.setText("test");
msgBox.setIcon(QMessageBox::Information);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
ui->auteur->clear();
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
}
form1window.cpp
#include "mainwindow.h"
#include "ui_form1window.h"
void From1Window::on_supprimer_clicked()
{
MainWindow *a=new MainWindow ();
a->test();
close();
}
I've read about the role of the pointer of MainWindow class (C++ /Qt Proper way to access ui from another class in qt //Edited) and I've also tried connect()
Thank for your help
//THIS LINE HAS NO EFFECT WHEN CALLED FROM THE OTHER CLASS
this->ui->auteur->clear();
The line will never executed unless you dismiss QMessageBox. This is because you triggered QMessageBox with exec() function. This function has its own event queue and does not return until finishes. You may set QMessageBox as modal and display it with show() method. In that case QMessageBox will not block execution of the the flow.
This problem can also happen with QDialog(s) if you display them with exec().
I provide you a simple two window signal/slot example:
main.cpp
#include "mainwindow.h"
#include "form.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Form f;
f.show();
return a.exec();
}
form.h
#ifndef FORM_H
#define FORM_H
#include <QWidget>
#include <QPushButton>
class Form : public QWidget
{
Q_OBJECT
public:
explicit Form(QWidget *parent = 0);
~Form();
private:
QPushButton *pb;
};
#endif // FORM_H
form.cpp
#include "form.h"
#include "mainwindow.h"
#include <QDebug>
Form::Form(QWidget *parent) : QWidget(parent)
{
MainWindow *mw = new MainWindow();
pb = new QPushButton("clickME", this);
QObject::connect(pb, SIGNAL(clicked()), mw, SLOT(test()));
mw->show();
}
Form::~Form()
{
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
QLabel *l;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
l = new QLabel("test", this);
}
MainWindow::~MainWindow()
{
}
void MainWindow::test() {
qDebug() << "test called!" << endl;
l->setText("text changed");
}
This works for me.
output