but how to trigger that signal?
Declare the signal in your QObject
-inherited class' interface. Insert Q_OBJECT
macro in the class declaration. Read Singals and Slots in Qt.
Example. Subclass QThread
in your case (QThread
inherits QObject
). Read Threading Basics in Qt and QThread docs.
Header
#include <QThread>
class OtherThread : public QThread
{
Q_OBJECT
public:
OtherThread(QObject *parent);
~OtherThread();
signals:
void debug(QString);
// You have to override run(). Don't try to call it anywhere.
// There is start() method to start a thread
protected:
void run() override;
};
emit the signal from the place you need:
Source file
#include "OtherThread.h"
OtherThread::OtherThread(QObject *parent)
: QThread(parent)
{ }
OtherThread::~OtherThread()
{
if(isRunning())
{
// Stop our loop
requestInterruption();
// Waits until return from run()
wait();
}
}
void OtherThread::run()
{
int it = 0;
while(!isInterruptionRequested())
{
// the line below will enqueue some call to the GUI thread
// no event loop in the sender thread is needed
emit debug(QString::number(it++));
msleep(500);
}
}
GUI class header file
#include <QtWidgets/QMainWindow>
class MainWin : public QMainWindow
{
Q_OBJECT
public:
MainWin(QWidget *parent = Q_NULLPTR);
};
GUI class source file
#include "MainWin.h"
#include "OtherThread.h"
#include <QTextEdit>
#include <QTimer>
MainWin::MainWin(QWidget *parent)
: QMainWindow(parent)
{
auto textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
auto otherThread = new OtherThread(this);
/*
No need to specify the connection type.
Qt::AutoConnection will be used by default.
In case of an automatic connection, Qt looks at the thread that invoked the signal
and compares it with the thread the receiver is living in to determine
which connection type it has to use.
*/
connect(otherThread, &OtherThread::debug,
textEdit, &QTextEdit::append);
// Attention: call start(), not run()!
otherThread->start();
// For example you want to stop the thread after 5 seconds
QTimer::singleShot(5000, [=]() { otherThread->requestInterruption(); });
}
Do the same using High-Level QtConcurrent API:
#include "MainWin.h"
#include <QtConcurrent/QtConcurrent>
#include <QThread> // for msleep
#include <atomic>
#include <QTextEdit>
#include <QTimer>
// Thread-safe flag to stop the thread. No mutex protection is needed
std::atomic<bool> gStop = false;
MainWin::MainWin(QWidget *parent)
: QMainWindow(parent)
{
auto textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
// Run the code in another thread using High-Level QtConcurrent API
QtConcurrent::run([=]()
{
int it = 0;
while(!gStop)
{
QString text = QString::number(it++);
// No need to explicitly specify Qt::QueuedConnection,
// Qt::AutoConnection will be used
QMetaObject::invokeMethod(textEdit, "append",
Q_ARG(QString, text));
QThread::msleep(500);
}
});
// Timer to stop the thread after 5 seconds
QTimer::singleShot(5000, [=]() { gStop = true; });
}
MainWin::~MainWin()
{
// Stop the loop if we exit the program earlier than after 5 seconds,
// to avoid undefined behaviour in that case
gStop = true;
}
Please also note that Qt provides unified place to control all the debug, warning, error and other types of messages:
Qt Debuggin Techniques for c++
qInstallMessageHandler()
Now, you can install the event handler once and then all messages will go to one place where you can output them where necessary, not using custom connections.
Please note that Qt provides several global macros for writing out warning and debug text:
qDebug()
is used for writing custom debug output.
qInfo()
is used for informational messages.
qWarning()
is used to report warnings and
recoverable errors in your application.
qCritical()
is used for
writing critical error messages and reporting system errors.
qFatal()
is used for writing fatal error messages shortly before exiting.
.
Also, I make some logging with QDebug
, but also some output to
std::cerr
. Can I mix these outputs?
Seems no, I recommend to rewrite the code where you are using std::cerr <<
and replace it by "qDebug() <<"
, qWarning() <<
, etc.
Another question about using QMutex
. Basically, I am just reading the
values set by the other thread, and starting/stopping the thread. Do I
need to use QMutex
in such simple case?
This question may be not so simple. For the simplest cases volatile
may be enough. Read Synchronizing Threads.
(I mean I know why to use a mutex; my question is about that when
using Qt, the internal mechanisms of GUI handling and thread handling
may make it a need)
Qt doesn't affect to such programming basics. But please note that all GUI elements in Qt can be accessed only from the GUI thread. See Threading Basics in Qt:
As mentioned, each program has one thread when it is started. This thread is called the "main thread"
(also known as the "GUI thread" in Qt applications). The Qt GUI must
run in this thread. All widgets and several related classes, for
example QPixmap
, don't work in secondary threads. A secondary thread
is commonly referred to as a "worker thread" because it is used to
offload processing work from the main thread.
So you cannot access GUI elements directly from another thread.
textEdit->append("some text"); // may be directly called from a GUI thread only
Use Singal-Slot mechanism to access GUI elements from another threads. Read also Qt5 New Signal Slot Syntax.
You can also invoke methods using Qt::QueuedConnection
without first connecting using QMetaObject::invokeMethod:
QMetaObject::invokeMethod(textEdit, "append",
Qt::QueuedConnection,
Q_ARG(QString, "some text"));
Read also:
Multithreading Technologies in Qt:
Qt offers many classes and functions for working with threads. Below
are four different approaches that Qt programmers can use to implement
multithreaded applications...
Edit. Enhanced useful list of articles.
Signals and Slots
Singals and Slots in Qt
Qt5 New Signal Slot Syntax
QMetaObject::invokeMethod
How Qt Signals and Slots Work
Debugging
Qt Debuggin Techniques for c++
Threading
Threading Basics in Qt
Multithreading Technologies in Qt
Synchronizing Threads
Threads and Objects
The Missing Article About Qt Multithreading in C++
Threads Events QObjects