I have an infinity loop whithin the run-method of my QThread subclass. This thread should exist till the application is closed. The Code looks something like this.
loopThread.h:
class loopThread : public QThread
{
Q_OBJECT
public:
loopThread();
~loopThread();
protected:
void run() override;
signals:
void resultReady();
};
The implementation of the subclass is as follows:
loopThread.cpp:
void loopThread::run()
{ while(!this->isInterruptionRequested()){
std::cout << "loop active" << std::endl; //checking if it executes the loop or not
}
}
the run()-method executes a infinity loop until requesInterruption() is called in the mainWindow class.
MainWindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void closeEvent(QCloseEvent *event);
private:
Ui::MainWindow *ui;
loopThread *loopThread = nullptr;
public slots:
void handleResult();
};
The Implementation for this class says
MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
loopThread = new loopThread();
connect(loopThread, &loopThread::noButtonClicked, this, &loopThread::NoButton);
connect(loopThread, &loopThread::finished, loopThread, &loopThread::deleteLater);
loopThread->start();
}
MainWindow::~MainWindow()
{
loopThread->quit();
loopThread->wait();
delete ui;
}
void MainWindow::closeEvent(QCloseEvent *event)
{
loopThread->requestInterruption();
}
So I would suggest that when I close the application by clicking in the "X" in the window the loop should end and the program should stop. The problem is even after closing the window the Console gives me the message "loop active" so it the loop still goes on. Where's my mistake. Is there a way to let a loop end when the program is closed?
The solution with moving a QObject to a Thread produces the same problem.
Thanks for the help guys!
I managed to solve this problem. AS said the infinite loop in the run()-method just send the message to the console. I have avoided this by just let the loop run without any task.
in my case i needed to check the serialcommunication so with the signal readyRead() i can now read this serial message. The loop is therfore executed until i stop the app. hopefulle that doesnt confuse too much. I will post my code when i have time.
Related
I am making a simple game and want to send a signal from my Game class to my MainWindow. My signal and slot share the same parameter but I can't connect them. I have tried sending very simple signals with a dummy variable but failed to connect. The code is as follows.
game.h
class Game : public QObject
{
Q_OBJECT
public:
Game();
signals:
void test(int l);
MainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void testSlot(int l);
game.cpp
void someFunction(){
emit test(2);
}
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),
g{new Game()}
{
ui->setupUi(this);
g->gameLoop();
connect(g,&Game::test,this,&MainWindow::testSlot);
}
How can I get the signals and slots to connect properly? Thank you in advance.
I think the problem may be in the fact that you have g->gameLoop(); BEFORE the connect. If your someFunction is called from the gameLoop, then the connect is performed only after the game has finished and after the execution returns from the gameLoop(). But of course it's just guessing. I wouldn't expect to see 'gameLoop' called from the Window's constructor so.. it looks odd as well. Other than that, it looks fine, so if my guess is not correct, then probably the problem lies elsewhere in the code we don't see.
Playing with QMetaObject::invokeMethod method :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setText( int value)
{
QString s = QString::number(value);
ui->textEdit->setText(s);
}
void MainWindow::on_pushButton_clicked()
{
QGenericArgument genericArg = Q_ARG(int, 321);
bool inv = QMetaObject::invokeMethod( this,"setText",Qt::BlockingQueuedConnection, genericArg);
qDebug("inv = %d\n", inv);
}
QMetaObject::invokeMethod returns false.
I'm not sure regarding slot "setText". I took it from function name and I suppose it might be related. Where I can find list of slots at all? Should I create special slot for "setText"?
Maybe it is related to fact I run it from the same thread?
UPD:
I have added public slot instead of public method:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//void setText( int value);
private slots:
void on_pushButton_clicked();
public slots:
void setText(int value);
private:
Ui::MainWindow *ui;
};
And this helped, but why I'm getting 0 in setText value ?
Your button-event is handled by the event loop that owns the MainWindow object and this same object also contains the method you wish to invoke (setText()). That means that caller and callee (or signal and slot) in your case live on the same thread, and you must not use Qt::BlockingQueuedConnection! To quote the manual: Using this connection type to communicate between objects in the same thread will lead to deadlocks.
If you intent to do processing in your on_pushButton_clicked() after the setText() method has finished, use a Qt::DirectConnection instead, then your setText() will be called as if it was a simple function, and control returns to your clicked() function after setText() finished.
If you intent to finish processing all code in your on_pushButton_clicked() before processing of the setText() function starts, use a Qt::QueuedConnection.
If you wish to execute setText() in parallel to on_pushButton_clicked(), then move your setText() method to another object (which is owned by another thread). Only in this scenario a Qt::BlockingQueuedConnection makes sense.
What I'm trying to do is to call an time consuming operation (MockClamWrapper::loadDatabase()) in a separate thread at the moment of creation of my window and then to update my window once the operation is completed. Here is the code that I have.
MockClamWrapper.h
class MockClamWrapper : QObject
{
Q_OBJECT
public:
MockClamWrapper();
~MockClamWrapper();
bool loadDatabase(unsigned int *signatureCount=NULL);
Q_SIGNALS:
void databaseLoaded();
};
MockClamWrapper.cpp
bool MockClamWrapper::loadDatabase(unsigned int *signatureCount){
QThread::currentThread()->sleep(10);
databaseLoaded();
return true;
}
MainWindow.h
#include <QMainWindow>
#include <QFileDialog>
#include "mockclamwrapper.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void enableWindow();
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
MockClamWrapper *clam;
void initWindow();
};
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect((QObject*)clam, SIGNAL(databaseLoaded()),(QObject*)this,SLOT(enableWindow()));
QFuture<void> fut = QtConcurrent::run(this,&MainWindow::initWindow);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initWindow(){
clam->loadDatabase(NULL);
}
void MainWindow::enableWindow(){
ui->checkFileButton->setEnabled(true);
}
The program compiles, but it crashes right after start. I assume that I do something wrong with slots and signals, but can't find my mistake.
The reason for crash is that you are not making any instance of the class MockClamWrapper. In the connect statement, you are referencing a pointer that points to nothing. Make a new object and then connect :
clam = new MockClamWrapper();
connect(clam, SIGNAL(databaseLoaded()), this, SLOT(enableWindow()));
I'm connecting a signal/slot but the slot is called multiple times (1, 2, 3...) every time I trigger the option, here are my classes:
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Dialog *dialog;
signals:
void s1(QString s);
private slots:
void on_actionTooo_triggered();
};
#endif // MAINWINDOW_H
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionTooo_triggered()
{
dialog = new Dialog(this);
QString s = "hello";
qDebug() << "CONNECT: " << connect(this, SIGNAL(s1(QString)),
dialog, SLOT(s1(QString)), Qt::UniqueConnection);
emit s1(s);
dialog->show();
}
dialog.h:
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
void s1(QString str);
private:
Ui::Dialog *ui;
};
dialog.cpp:
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::s1(QString str)
{
qDebug() << str << endl;
}
Every time the option is triggered in the main window, I connect the signal (just once), to the new dialog, but when I run, for example two times, it prints two "hello". If I put a disconnect(this, 0, 0, 0); before I connect the signals it works.
It seems odd to me that it maintains the connect even when the object is destroyed. It binds the connect to the same object created before. Is this the expected behavior?
You are creating a new Dialog everytime you call on_actionTooo_triggered(). This Dialog isn't deleted at the end of your function. Therefore with the next call the signal MainWindow::s1(QString) is emitted to the two different Dialogs which results in multiple ouptuts in qDebug.
void MainWindow::on_actionTooo_triggered()
{
dialog = new Dialog(this);
QString s = "hello";
qDebug() << "CONNECT: " << connect(this, SIGNAL(s1(QString)),
dialog, SLOT(s1(QString)), Qt::UniqueConnection);
emit s1(s);
dialog->show();
}
This code creates a new dialog each time it's triggered and sets up a connection between the newly created dialog and the MainWindow. While the connection is specified as "Unique", a new dialog is created each time, so the connection is not unique as the dialog instance is different.
Your code does not show that the dialog is being deleted and even if you close its window, the instance still remains in memory, so multiple objects are receiving the same signal.
Your Dialog is never destroyed in this code. It's not even leaked as you pass this as a parent in the Dialog's constructor, which makes the MainWindow responsible for this Dialog memory.
Thus you permanently create additional Dialog which slot will be triggered, and thus explaining why you see an incrementally increasing repetition of the output.
What I simply want to do is connect a signal inside a thread to a slot in the main thread to handle UI changes.
This is basically the current state of my thread, nothing fancy but it's just for testing purposes atm:
// synchronizer.h
class Synchronizer : public QObject
{
Q_OBJECT
public:
Synchronizer();
signals:
void newConnection(std::wstring id);
private:
QTimer timer;
private slots:
void synchronize();
}
// synchronizer.cpp
Synchronizer::Synchronizer()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(synchronize()));
timer.start();
}
void Synchronizer::synchronize()
{
emit newConnection(L"test");
}
And here's how my MainWindow looks:
// mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Synchronizer synchronizer;
private slots:
void addConnection(std::wstring id);
}
// mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&synchronizer, SIGNAL(newConnection(std::wstring)),
this, SLOT(addConnection(std::wstring)));
QThread *thread = new QThread;
// The problems starts here?
synchronizer.moveToThread(thread);
thread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::addConnection(std::wstring id)
{
// Add a new connection to QListWidget
ui->connectionList(QString::fromStdWString(id));
}
If I remove there lines:
synchronizer.moveToThread(thread);
thread->start();
everything seems to work as expected, that is a new item is added every second to a QListWidget but as soon as I move the synchronizer object to thread it simply stops working. I'd presume it has something to do with the connect context but I'm not really sure how something like this should be achieved as I'm quite new to Qt.
It seems that the in this case was simply the fact that I am using std::wstring as an argument in the signal without registering the type first and after adding the following line qRegisterMetaType<std::wstring>("std::wstring"); to the code, everything worked as expected.
If I would have read the output console more carefully I would have solved the problem without too much hassle as it was clearly stated that:
QObject::connect: Cannot queue arguments of type 'std::wstring'
So simply speaking, read the compiler output and don't be stupid like me :)