“real time” update a Qt TextView

2019-03-30 23:53发布

问题:

I have a Qt application with an embedded script/jit. Now I'd like to receive the output from the script on an QTextEdit (more specific QPlainTextEdit). For this purpose callbacks are being issued. The problem I'm facing is that whatever I try the output to the TextEdit is either delayed until the script has finished or gets stuck after 2-3 seconds (and is delayed then until the script has finished). I tried to use signals and slots for the update but also direct function calls - neither worked. Also repainting / updating the TextEdit and the parent form as well as even QCoreApplication::flush() did show little/no effect. Seems like I'm doing something fundamentally wrong. Any ideas or examples how to achive the "real time" updates?

Btw, the update routines are being called - debug output to stdout is avaiable in real time.

回答1:

Just to sketch a soluting using threads, which I have used numerous times for logging purposes and which works as desired:

Define your thread class:

class MyThread : public QThread
{
  Q_OBJECT
public:
  MyThread(QObject *parent=0) : QThread(parent) {}
signals:
  void signalLogMessage(const QString &logMessage);

...
};

Whenever you want a log message to be shown in the main thread, just use

emit signalLogMessage("Foo!");

In your main thread:

MyThread *thread = new MyThread(this);
connect(thread, SIGNAL(signalLogMessage(const QString&)), 
        this, SLOT(logMessageFromThread(const QString&)));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
...
thread->start();

where logMessageFromThread does something like myPlainTextEdit->appendPlainText(message). This works without any delay or other problems.

I hope that helps.



回答2:

Please allow me to answer the question myself (in parts). First of all one has to understand that Qt itself is build very much around its own signal and slot concept. Therefore, one cannot expect a "real time" update of a QTextView since adding text to it (might it be by a text cursor or a simple append) just triggers a signal. So whatever you do when you have just one thread, all you do is to trigger the signals for updating your widgets. The corresponding slots will be processed with a much lower priority and therefore after the blocking worker routine finishes. All this can be alleviated by calling QCoreApplication::processEvents() as pointed out in the comments by Idan K. This enforces the sequential processing of all unprocessed events and returns afterwards. Using this function QTextEdit can be used as a "real time" output-console. However, as pointed out by Idan and Greg the best solution uses a separate worker thread, emitting signals to the GUI thread. Since these are separate threads the GUI can process the corresponding slots while the worker continues to run. So the output in theory might be a bit delayed wrt. to the above solution but the whole app will remain responsive.

Also I want to add that my problems using QThread together with mono where solved by creating the global app-domain outside of thethread and using mono_thread_attach() as suggested here. It works well on both Mac OS X and Windows 7.



标签: c++ qt mono qt4