Prevent event loop blocking in modal dialog - c++

I'm developing an application where a user may parse some binary files. Once he clicks the "parse"-button, he first may select some files, which are parsed afterwards. While the application is processing the files, I'd like to display a modal dialog, which informs the user about the progress (QProgressBar bar) and the already parsed files (QListView list / listModel).
My current approach is to override the exec()-method of a QDialog-sublcass. This way I could just call
parseAssistant.exec()
The current implementation looks like this:
class ParseAssistant : public QDialog { public: int exec(); };
int ParseAssistant::exec()
{
bar->setMaximum(files.size());
this->show();
this->setModal(true);
for (int i = 0; i < files.size(); i++) {
PluginTable* table = parser.parse(files[i]);
// do something with the table
// saveTableintoDB();
// update GUI
// bar->setValue(i);
// listModel->insertRow(0, new QStandardItem(files[i]));
}
this->hide();
return QDialog::Accepted;
}
After this (blocking) method has run, the user either has parsed all files or canceled the progress somewhere. To achieve this I attempted to use QApplication::processEvents in the while-loop (which feels kinda laggy as it's only progressed when a file has finished parsing) or to outsource the heavy calculation(s) to some QConcurrent implementation (::run, ::mapped). Unfortunately, I don't know how to return the program flow back to the exec() method once the QFuture has finished without relying on some CPU-intense loop like:
while (!future.isFinished()) { QApplication::processEvents(); }
Is there a smarter approach to having a modal dialog, which runs a heavy calculation (which may be canceled by the user) without blocking the eventloop?

I wouldn't subclass Qdialog, in the first place, but just use a QFutureWatcher and connect the watcher finished signal to the dialog close slot, this way:
QDialog d;
QFutureWatcher<void> watcher;
QObject::connect(&watcher, &QFutureWatcher<void>::finished, &d, &QDialog::close);
QFuture<void> future = QtConcurrent::run(your_parse_function);
watcher.setFuture(future);
d.exec();
//control returns here when your_parse_function exits
The parse function could be a method in a QObject derived class, like this:
class Parser : public QObject
{
Q_OBJECT
public:
void parse()
{
for (int i = 0; i < files.size(); i++) {
PluginTable* table = parser.parse(files[i]);
emit fileParsed(i, files.size);
// ...
}
}
signals:
void fileParsed(int id, int count);
};
You can connect the fileParsed signal to a slot of choice, and from there set the progress bar value accordingly.

My personal approach would be:
create a separate thread and do the processing there (QThread; std::thread should do the trick as well)
provide a signal that informs about the file currently being processed
possibly another signal informing about progress in %
another signal informs that processing is done, emitted just before the thread ends
provide your dialog with appropriate slots and connect them to the signals (as different threads involved, make sure connection type is Qt::QueuedConnection)

Related

How can I communicate back the result from a std::thread to the Gui main thread in Qt?

In order to learn about threading in Qt and C++ I am creating a small example program.
It has a Gui with a button and a text field:
When the user presses the Calculate button it calculates pi using a sum formula.
In order for the Gui to be responsive during this lengthy operation the calculation will be performed in a separate thread.
First I created a subclass of QThread that does the calculation in its run() method and emits the signal void resultReady(double value); when it is finished.
This signal I connected to the slot void setResult(double value); in my Dialog Gui class.
This approach works fine.
Now I want to do the same thing using std::thread. How do I do this?
I am having problems communicating the result back to the Gui. I tried this:
class StdThreadStrategy : public QObject {
public:
void doTheWork() {
double pi = pi_sum();
QTimer::singleShot(0, this, [=] { dialog->setResult(pi); });
}
// This is called by Dialog when the user presses the Calculate button:
void calculatePi(Dialog* dialog) {
this->dialog = dialog;
std::thread t(&StdThreadStrategy::doTheWork, this);
thread = std::move(t);
}
private:
Dialog* dialog;
std::thread thread;
};
A StdThreadStrategy object is constructed in the constructor of Dialog:
Dialog::Dialog() : QDialog() {
// .. create gui code
calculatePiStrategy = new StdThreadStrategy();
}
// this is the slot I want called from the other thread:
void Dialog::setResult(double value) {
piLineEdit->setText(QString::number(value));
}
// Called by Calculate button:
void Dialog::calculate() {
calculatePiStrategy->calculatePi(this);
}
I was hoping using QTimer::singleShot in the doTheWork() method would allow me to post to the event queue of the Gui from another thread.
Unfortunately I get the error message: QObject::startTimer: Timers can only be used with threads started with QThread.
How can I communicate back the result from a std::thread to the Gui main thread in Qt?
Add a signal to your instance of StdThreadStrategy, and connect that via an explicitly deferred connection to the handler living in the UI thread. That way, you can safely call the signal from any thread, Qt takes care of sending it where it should go.
Also don't forget to join() your thread in the destructor of StdThreadStrategy. You also need to be aware that recycling a single instance like that is going to end up in race conditions. Just go and try what happens when you click the button again before pi had been fully computed.
There is no general answer to this kind of design problems. I give you just some tips here to show that c++11 provides a higher level of abstraction that can ease the manipulation of thread lifetime.
In your main GUI thread, run the async task (here I use std::async what gives you a std::future for further manipulation)
auto fut = std::async(std::launch::async, [=]() {
// do some work
});
Now, your UI is alive, run a Qtimer in the main thread with a callback that will check for the async procedure.
// callback content will be something like this
// checking via the future the state of the async task
if (fut.wait_for(std::chrono::milliseconds(25)) !=
std::future_status::ready) {
// not yet finished
return;
}
// No do what you want with the result
auto res = fut.get();
// emit a signal to refresh the gui etc.
Regards.
You could send a custom QEvent that carries the result from the worker thread to the thread your QObject lives in. See QEvent and QCoreApplication::postEvent()
Create your event class:
class MyEvent : public QEvent
{
public:
MyEvent(double result) : QEvent(QEvent::User), mResult(result) {
}
double result() {
return mResult;
}
private:
double mResult;
};
Post the event to the event loop and override the event() function to catch it:
class StdThreadStrategy : public QObject {
...
void doTheWork() {
double pi = pi_sum();
QCoreApplication::postEvent(this, new MyEvent(pi));
}
...
bool event(QEvent *event) override {
if (event->type() == QEvent::User) {
const auto result = static_cast<MyEvent*>(event)->result();
dialog->setResult(result);
}
return QObject::event(event);
}
...
}

How to prevent GUI from hanging while allowing 2nd operation to be performed alongwith 1st operation in Qt

Here I am explaining my problem statement in detail and the efforts I have put so far
A) Problem Statement : During printing if 'Stop Printing' pushbutton is pressed, the printing should stop at that moment!
B) My Work :
1. StartPrinitng_Pressed :
void MainWindow :: on_StartPrinitng_Pressed()
{QSqlquery studentList;
studentList("SELECT Name, address FROM class WHERE Roll No = some variable")
while(studentList.next())
{
Name=studentList.value(0).toString();
address=studentList.value(1).toString();
QTimer:: singleShot(1000,this,SLOT(StopNow())); //calling stopNow function
if(StopPrintingNow==0)
{ //** I am printing the fetched data (in a string) by setting GPIO pins HIGH **// }
}
}
2. StopPrinting_Pressed :
void MainWindow::on_StopPrinting_Pressed()
{StopPrintingNow=1;}
3. StopNow Function Declaration :
void MainWindow::StopNow()
{
if(StopPrintingNow==1)
{ //** I have reset all serials ports; Break; **// }
else if(StopPrintingNow==0)
{ QTimer::singleShot(1000,this,SLOT(on_startPrinting_pressed())); }
}
C) Flow of program execution : As and when "StartPrinting" pushbutton is pressed, the query shown in my question executes which fetches data from database and perform simultaneous printing.
D)Problem Faced -
1.GUI is getting hanged while printing, hence StopPrinting button doesn't respond.
Qtimer is not calling "StopNow function " while printing (though I have called it at correct position)enter image description here
Handling of timers and button presses is both covered by the Qt event loop -- which is blocked while you are looping over that SQL query. You have two options:
1) Periodically dispatch events in your while loop.
This is as simple as
qApp->processEvents();
But you have to be careful, however: any events you trigger due to user interaction (or a timer) will block and your while loop will not run until the event is finished. In your case especially, you could end up running a second copy of your on_StartPrinitng_Pressed function.
2) Do the printing on a separate thread.
This involves some more code, but the gist of it is that you create a SqlPrinter object with a startPrinting slot and stopPrinting slot. You then create a QThread and change its owner thread to that thread. Slot invocations will happen across the thread boundary and all will be fine.
class SqlPrinter : public QObject {
Q_OBJECT
public:
SqlPrinter(QObject* parent = nullptr) : QObject(parent) {}
public slots:
void startPrinting();
void stopPrinting();
};
In your main code, then do something like this, assuming that you have the two buttons named MainWindow_StartButton and MainWindow_StopButton:
QThread* printerThread = new QThread(qApp);
SqlPrinter* printer = new SqlPrinter;
printer->moveToThread(printerThread);
printerThread->start();
QObject::connect(MainWindow_StartButton, &QPushButton::clicked, printer, &SqlPrinter::StartPrinting);
QObject::connect(MainWindow_StopButton, &QPushButton::clicked, printer, &SqlPrinter::StopPrinting);
Don't forget to clean up SqlPrinter afterwards!

QT - Mainwindow doesn't update unless it's closed

I'm trying to update the main window by calling updateGUI function in a thread every 500 ms. The window is displayed but not updated with the new values unless I close the window. When I do so, a new window is opened with the new value. I found this question but it didn't answer my question. I knew that (as stated in qt documentation)
QApplication::exec enters the main event loop and waits until
exit() is called.
I tried to use processEvents() but the main window is opened and closed repeatedly and very fast that I can't even see it. Here is my code:
float distanceToObject;
bool objectDetected;
Modes currentMode;
void timerStart(std::function<void(void)> func, unsigned int interval)
{
std::thread([func, interval]()
{
while (true)
{
auto x = std::chrono::steady_clock::now() + std::chrono::milliseconds(interval);
func();
std::this_thread::sleep_until(x);
}
}).detach();
}
int updateGUI(void)
{
int argc = 0;
char **argv = NULL;
QApplication a(argc, argv);
MainWindow w;
// Set text of a label
w.setDistance(QString::number(distanceToObject));
// Also update objectDetected and currentMode values
w.show();
//a.processEvents();
return a.exec();
}
void sendMsg(void)
{
// Send heartbeat signal to another device
}
void receiveMsg(void)
{
// Read messages from the other device and update the variables
// These two values change continuously
objectDetected = true;
distanceToObject = 5.4;
}
void decide(void)
{
// The core function of the program. Takes relatively long time
// Run a decision-making algorithm which makes decisions based on the values received from the other device.
// Update some variables according to the made decisions
currentMode = Auto;
// Execute functions according to the made decisions.
setMode(currentMode);
}
int main(void)
{
timerStart(updateGUI, 500);
timerStart(sendMsg, 1000);
timerStart(receiveMsg, 10);
timerStart(decide, 500);
}
How can I update the main window with the variables' values correctly?
Your thread does not update the MainWindow, but it does create an entirely new QApplication and MainWindow on every iteration. Your thread should be stuck inside QApplication::exec until you quit the application (e.g. by closing the window). Only then should your thread's loop make further progress.
In general, you must be very careful when doing updates from outside the main thread, since typically GUI operations must be performed inside the main thread.
Think about using QThread, which already comes with its own event loop, which you can use to notify/update your window using a respective slot.
Without further details about what you are actually trying to achieve, it is not possible to give you further direction. I, at least, recommend that you create your QApplication and MainWindow inside the main thread (e.g. main). Then it depends what you are trying to 'update'. If you need to progress some data, then you can do that within your second thread and send the results to your MainWindow instance using signal-slot. If you need to draw onto the window, then this either has to be done in the main thread directly, or you might find a way to render into a separate buffer (i.e. QImage) from within your thread and then send this buffer to the main thread for drawing it into the window.
I try to sketch how something like this can be done. Notice, however, that this it neither complete nor compilable, but merely an outline.
First, you have your MainWindow and add to it a signal, that notifies all observers to start doing their work (will become clear in a moment). Furthermore, you add slots that will be invoked whenever one of your values changes. Those slots run in the main thread (and are members of the MainWindow) and thus can update the window however they need to:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
// constructors and stuff
void startWorking()
{
emit startWorkers();
}
public slots:
void onModeChanged(Modes m)
{
// update your window with new mode
}
void onDistanceChanged(float distance)
{
// update your window with new distance
}
signals:
void startWorkers();
};
Next, you build a Worker class, that encapsulates all the 'background work' you like to do (basically what your thread did in your original code):
class Worker : public QObject
{
Q_OBJECT
public:
// constructors and stuff
public slots:
void doWork()
{
while(!done)
{
// do stuff ...
Modes m = // change mode
emit modeModified(m);
// do stuff ...
float distance = // compute distance
emit distanceModified(distance);
// do stuff ...
}
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
};
Note, that Worker must inherit QObject and that your doWork method must be a public slot. Furthermore, you add a signal for each of the values you like your MainWindow to be informed about. No implementation for them is needed, since it is generated by the Qt MOC (Meta Object Compiler). Whenever one of the respective values changes, simply emit the corresponding signal and pass the new value.
Lastly, you put everything together:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow window;
// create a worker object
Worker* worker = new Worker;
// connect signals and slots between worker and main window
QObject::connect(worker, &Worker::modeModified,
&window, &MainWindow::onModeChanged);
QObject::connect(worker, &Worker::distanceModified,
&window, &MainWindow::onDistanceChanged);
QObject::connect(&window, &MainWindow::startWorkers,
worker, &Worker::doWork);
// create a new thread
QThread* thread = new QThread;
// send worker to work inside this new thread
worker->moveToThread(thread);
thread->start();
// show window and start doing work
window.show();
window.startWorking();
// start main loop
int result = app.exec();
// join worker thread and perform cleanup
return result;
}
Alright, let's go through it. First, you create your QApplication and MainWindow inside your main thread. Next, create an instance of your Worker object (could create multiple here). Then you connect the signals of the worker to the slots of the window and vice versa. Once these connections are established, whenever you emit a signal, the connected slot is invoked by Qt (and passed values are transmitted). Notice, that this connection works across thread boundaries. Whenever a signal is emitted from a thread different then the receiving object's thread, Qt will send a message, which is processed in the receiving object's thread.
Then you tell Qt that you want your worker to live inside another thread using QObject::moveToThread. See here for a very detailed explanation of how to correctly use QThread and objects inside it.
The rest is then simple. show your window and start processing. Here different ways are possible. I just call the startWorking method here, which then emits the startWorkers signal, which is connect to the worker's doWork method, such that doWork will start executing after this signal is received by the other thread.
You then call QApplication::exec which runs the main thread's event loop, where all these signals are processed by Qt. Once your application is closed (e.g. by calling quit or closing the main window) the exec method returns and you are back in main. Notice, that you need to correctly close the thread (e.g. by sending an addition signal that stops the while loop) and join it. You also should delete all the allocated objects (worker, thread). I omitted this here for simplicity of the code example.
Answering your Question
I have many functions, e.g., updateClips and mavReceive that should be called periodically and run independently from each other. I should create a different Worker class for each function, as each has different signals, and a QThread object for each of these functions, right? I don't need startTimer() anymore? If yes, how can I control the calling interval for each function (used to be done in startTimer()
from the comment:
The answer greatly depends on what exactly you mean by "should be called periodically". Who is supposed to call them? The user? Or should they just be executed periodically?
So in principle, you can have multiple workers in one thread. However, if they are supposed to do work all the time (spin in a while loop) it does not make sense, since one is running and all others are blocked. In that case you would have one thread for each worker.
If I understand you correctly, you are interested in updating something periodically (e.g. every 500ms). In that case I highly recommend using the QTimer. You can set an interval and then start it. The timer will then periodically emit the timeout signal, which you can connect to whatever function (more precisely slot) you want to have executed.
An updated version of the Worker could look like this:
class Worker : public QObject
{
Q_OBJECT
public:
Worker()
{
QObject::connect(&modeTimer_, &QTimer::timeout,
this, &Worker::onModeTimerTimeout);
QObject::connect(&distanceTimer_, &QTimer::timeout,
this, &Worker::onDistanceTimerTimeout);
modeTimer_.start(500); // emit timeout() every 500ms
distanceTimer_.start(100); // emit timeout() every 100ms
}
public slots:
void onModeTimerTimeout()
{
// recompute mode
Modes m = // ...
emit modeModified(m);
}
void onDistanceTimerTimeout()
{
// recompute distance
float distance = // ...
emit distanceModified(distance);
}
signals:
void modeModified(Modes m);
void distanceModified(float distance);
private:
QTimer modeTimer_;
QTimer distanceTimer_;
};
Notice, the connections established in the constructor. Whenever one of the timers times out, the connected slot is invoked. This slot then may compute whatever it needs to and afterwards send the result back to the MainWindow in the main thread using the same signal as before.
So, as you see, you can have multiple timers / re-computations / update signals within one Worker (and thus, one thread). However, the crucial point for an implementation is, how long the computations take. If they take very long (e.g. nearly as long as the intervals) then you should think about using multiple threads to speed up the computation (meaning: perform one computation in each thread). As I slowly seem to get a clearer picture of what you want to achieve, I am wondering whether it is only about these periodic updates that you 'misused' the thread for in your question. If this is indeed the case, then you do not need that thread and Worker at all. Then simply add the timers to your MainWindow and connect their timeout signal to the respective slot of the MainWindow directly.

Signals and slots between objects in different threads in Qt

Basically, I've the next code:
class serverTCP : public QObject
{
// Other methods...
signals:
void newInstructions(QJsonDocument jDoc);
public slots:
void responseObtained(QJsonDocument jDoc);
}
class gatherModbus : public QObject
{
// Other methods...
signals:
void responseReady(QJsonDocument jDoc);
public slots:
void executeInstruction(QJsonDocument jDoc);
void myprocess() {
while(true)
{
// Write and read Serial Port
// Save data in json
}
};
}
void main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int netsNumber = 2; //In reality this is dynamic. It's only a example
serverTCP *server = new serverTCP;
gatherModbus * gather = new gatherModbus[netsNumber];
QThread * threads = new QThread[netsNumber];
// more necessary code...
for(int i = 0; i < netsNumber; i++)
{
gather[i].moveToThread(threads[i]);
QObject::connect(&server, SIGNAL(newInstructions(QJsonDocument)),
&gather[i], SLOT(executeInstruction(QJsonDocument)));
QObject::connect(&gather[i], SIGNAL(responseReady(QJsonDocument)),
&server, SLOT(responseObtained(QJsonDocument)));
QObject::connect(&threads[i], SIGNAL(start()),
&gather[i], SLOT(myprocess()));
// Other signals needed between the objects 'gather' and 'threads'
threads[i].start();
}
a.exec();
}
The problem is that the connections between objects 'server' and 'gather' do not work. The object 'server' is in the same thread as the 'main' function but objects 'gather' have moved to other threads.
What have I to do to make both objects can communicate properly?
My purpose is that the 'server' must be able to send a signal to all objects 'gather' there are. In each of the objects 'gather' must execute the slot and return the 'server' response if any.
If I set up the connection to be the type Qt::DirectConnection slots running on the same thread as the 'main' function and object 'server' and that does not interest me.
Any help or suggestions will be appreciated.
All is in Qt documentation.
First, read that.
Then if you're not satisfied, you can use QCoreApplication::postEvent() (for more informations you need : here)
Both signals/slots (QObject:connect()) and QCoreApplication::postEvent() are thread-safe and can solve your problem.
So events and signal/slots are two parallel mechanisms accomplishing the same things, in general an event will be generated by an outside entity (e.g. Keyboard, Mouswheel) and will be delivered through the event loop in QApplication. In general unless you set up the code you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.
Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more) but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivers immediately or deferred via a queue (if you are using threads) A signal can be generated
Your demo code seems OK. That's how we organize our current project. You'd better provide more detailed codes if necessary to explain your problem.
BTW, after reading your interests, I'd recommend you the QtConcurrent module which seems fitting your interest better.
Huh... Your code is not ok. This is the source of all your trouble
void myprocess() {
while(true)
{
// Write and read Serial Port
// Save data in json
}
};
If you want the slots newInstructions and responseObtained slots to ever run, myprocess should not be an infinite loop. You need to :
Modify myprocess such that once it is done writing and reading currently available data, it completes
Have a mechanism to know that new processing need to be done. For instance, if you are using a QIODevice subclass (socket, input stream, etc...) you have the signal QIODevice::readyRead() which will notify you there is new data to read from the device. I suspect your newInstructions is supposed to do just that.
connect this mechanism to another call to myprocess to allow the processing to start again
Edit : Given your comment, this is a way to modify the infinite while loop without too much modification.
void myprocess() {
make_one_processing_round();
if(should_continue_processing())
{
QMetaObject::invokeMethod(this, &gatherModbus::myprocess, Qt::QueuedConnection);
}
};
QMetaObject::invokeMethod will schedule this method for execution at the back of the thread QEventLoop queue. Which means other slots can execute.
I can solve my problem adding the next line in the end of "myprocess" method:
QCoreApplication::processEvents(QEventLoop::AllEvents);
The final code of this method is this:
void myprocess() {
while(true)
{
// Write and read Serial Port
// Save data in json
// New line:
QCoreApplication::processEvents(QEventLoop::AllEvents);
}
};
With this line I get that events will processed if any. I don't known if it is the best solution, but it works as wanted.
Thanks to all of you for your help and answers.

How to force Qt to update GUI from not main thread

I'm fighing since last week with problem caused by update of QPlainTextEdit. I'm trying to create separate from QMainWindow Dialog window with QPlainTextEdit inside. The problem begins when I try to use appendHtml signal (also tried with appendText), text that is placed is not visible unless marked by by mouse. Repainting or updating cause in program crash or no visible action.
Simplified code of QDialog with QPlainTextEdit header:
namespace Ui {
class LogWindow;
}
class LogWriter: public QDialog
{
Q_OBJECT
QMutex print_lock;
public:
class Log{
Q_OBJECT
const static int MAX_SIZE = 100;
bool to_terminal;
QString color;
QMutex *print_lock;
QPlainTextEdit *text_place;
QVector< QPair<QString,time_t> > history;
LogWriter * obj;
public:
bool print;
Log(bool _print,QString _color,LogWriter *obj_ = NULL)
{print = _print; color = _color; obj = obj_;}
void setLock(QMutex *print_lock_){print_lock = print_lock_;}
void setTextField(QPlainTextEdit *_text) {text_place = _text;}
Log& operator<<(QString &a);
Log& operator<<(const char* a);
};
static LogWriter* getInstance()
{
static LogWriter instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return &instance;
}
~LogWriter();
Log LOW,MEDIUM,HIGH;
Ui::LogWindow *ui;
signals:
void signalLogAppend(QString);
};
Simplified code of methods definitions:
LogWriter::LogWriter(QWidget * parent): QDialog(parent) {
ui = new Ui::LogWindow;
ui->setupUi(this);
LOW.setLock(&print_lock);
MEDIUM.setLock(&print_lock);
HIGH.setLock(&print_lock);
connect(this,SIGNAL(signalLogAppend(QString)),ui->plainTextEdit,
SLOT(appendHtml(QString)),Qt::DirectConnection);
}
LogWriter::Log& LogWriter::Log::operator<< (QString &s){
history.push_front(qMakePair(s,time(NULL)));
if(history.size() > MAX_SIZE) history.pop_back();
if(print){
//print_lock->lock();
QString text = "<font color=\"";
text += color + "\">";
text += s + "</font>";
//cout << text.toStdString() << endl;
//text_place->appendHtml(text);
//text_place->repaint();
emit (obj)->signalLogAppend(text);
//print_lock->unlock();
}
return *this;
}
I have two separate ui files (first for main window, second for log window).
I have to use log window all across my program (something about 10 threads), and I stucked on this issue. My question is - is it possible to force GUI update without using main thread and if not - what else possibilities I have. If possible I would rather avoid reconstructing all my code - it would take me some time to do it. Right now logging is super easy - I ony need:
LogWindow *log = LogWindow::getInstance();
log->MEDIUM << "something";
As additional info I add QTCreator warning:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
If I understand your code correctly, you're trying to log from a background thread and are using a direct connection to pass the signal to the GUI thread? That's not going to work, you have to send the signal via the default connection so Qt can figure out that it's a cross-thread signal and pass it across threads accordingly (ie, via the message loop on the foreground thread).
In Qt, any GUI interaction has to happen in the Main/foreground thread otherwise bad things happen as you discovered. You can certainly send a signal from a background thread to trigger a GUI update - I do this all the time - but you need to ensure that you're using the correct connection for it. The direct connection results in a direct function call and is not going to work for you in this case.
In your code, the problem is the call to connect() - you explicitly specify the connection mode for the signal to slot connection when you should just use the default setting. If you set the connection explicitly to Qt::DirectConnection, the underlying code will execute a direct call to the specified slot, which means that you end up calling the slot in the thread context of the signal. You don't want that because the signal is triggered in a background thread.
You can't pass arbitrary types/classes to signals and slots. The list is limited and not all Qt classes are in the list. To add types/classes to the list of those that can be passed to a signal/slot, you must call qRegisterMetaType for that class. I recommend calling it in the constructor of the class you're trying to pass to a signal like this:
MyClass::MyClass() : MyParentClass()
{
static int reg = qRegisterMetaType<MyClass>("MyClass");
}
The static int ensures the registration is only called once and before any instance of MyClass could ever be used.