How to show paginated text from a QTextDocument in QML? - c++

I currently have a C++ class inheriting from QQuickPaintedItem. I use it to paint layouted, paginated richtext from a QTextDocument via QTextDocument::drawContents (or by directly calling its QTextDocumenLayout's draw method).
However, as stated in QQuickPaintedItems documentation, there are threading issues to be aware of:
Warning: Extreme caution must be used when creating QObjects, emitting signals, starting timers and similar inside this function as these will have affinity to the rendering thread.
Specifically, in this case, QTextDocumentLayoutPrivate has timers which get started/stopped when QTextDocumenLayout::draw is called. Unfortunately, the QTextDocument and thus the timers lives in the qml main thread, while paint is called in the render thread, leading to messages like
QBasicTimer::start: Timers cannot be started from another thread
While this doesn't affect the functionality of my application (so far), this is probably not a good thing™.
Therefore, my question is whether there is a better way to show the paginated text in QML (not necessarily involving QQuickPaintedItem).

For now I'm still using the QQuickPaintedItem and when paint is called I do the following:
First check whether the QTextDocument has its affinity set to its current thread. If yes, I'll proceed as normal.
Otherwise QMetaObject::invokeMethod is used to call a method which moves the document to the rendering thread, and calls update to trigger a repaint, which now works as the thread affinity is correct. At the end of paint, the QTextDocument's thread affinity is set back to the original thread.
This works as far as I can tell (as in, no more warnings), but feels conceptually rather wrong.

Related

What is the correct way to display widgets without calling QApplication::exec()?

For test purposes I'd like to create and display a widget. For now I only need the widget to render correctly but in the future I may want to extend this so I simulate various events to see how the widget behaves.
From various sources it would appear that the following should work:
QApplication app;
QPushButton button("Hello");
button.show();
// Might also be necessary:
QApplication::processEvents();
But for me the widget does not render correctly. A window is created to display the widget, however it is entirely black.
I can get the widget to render correctly by adding the following lines:
std::this_thread::sleep_for(std::chrono::milliseconds(10));
QApplication::processEvents();
With 10 milliseconds being about the smallest time necessary to get the widget to render correctly.
Does anyone know how to get this to work without the time delay, or know why the delay is necessary?
To test Qt GUI application you need at least QApplication instance and event loop being processed. The fastest way is just use QTEST_MAIN macro, this answer explains in a nice way what it does exactly. However, to have more flexibility (e.g. to use GTest, GMock) you can also simply create QAplication instance in your tests main (no need to call exec).
Then, to have the events processed, you should invoke QTest::qWait. This will process your events for the specified amount of time. It is a good practice to use qWaitFor which accepts a predicate - this way you avoid race conditions in your tests.
In the particular scenario, when you expect some signal to be emitted, you can also use similar functionality of QSignalSpy::wait.
Small example when we want to wait until some parameters are passed from one item to another:
QSignalSpy spy(&widget1, &Widget1::settingsChanged);
widget2->applySettings();
ASSERT_TRUE(spy.wait(5000));
// do some further tests based on the content of passed settings
Why don't you want to have the application run exec ? The process of displaying a widget is not "static". You don't "draw" the widget on the screen, but rather you have an application that listen for various events and receives draw events from the windowing manager. The application can only draw the widget when the windowing manager asks it to.
The reason your second code works is that you wait sufficiently long for the windowing manager to have sent the "draw" request in your conditions. This does not guarantee it will always work.
If you want to guarantee the display of the widget, you need to start a loop and wait until you have received at least one draw event, but even that isn't foolproof.
As expertly described by Vincent Fourmond, widgets are not a one-off deal. The GUI is non-blocking and for this, it needs to run in an event loop.
The exec() method starts this event loop which you mimicked by polling.
While it is possible to combine Qt's event loop with other event loops, I would recommend you a simpler solution:
Proceed your program within the event loop by calling a method when it starts. Find an excellent answer here on how to do this: https://stackoverflow.com/a/8877968/21974
As you mentioned unit testing, there is also a signal you can use for doing checks at the end of the lifecycle (before widgets are destroyed): QApplication::aboutToQuit. This will happen when the last window is closed (programmatically or by the user).

How to stop QComboBox/QSpinBox to emit signals when enabling/disabling them?

I have a small Qt plotting application and I am enabling/disabling widgets (combo/spin boxes) based on a "master" combo box. For example, say the master is combo1, which changes the entries in combo2, based on currentIndex(), enables/disables spin1, and sets a value for spin1 if a certain entry in combo1 is selected. There are more widgets than only these, though.
After the small discussion in the chat (and onwards), I used Qt::QueuedConnection with every connect(), but this didn't stop the re-enabled widgets to emit signals when re-enabled. This caused my many connect() to all be executed for all the re-enabled widgets, resulting in multiple plottings, which I want to avoid. As they are right now, (almost) all the widgets use plot() inside a connect(), so it's multiple signals to one slot.
My question: is there a way to prevent emitting the signals when the widgets are re-enabled? I could make plot() use some bool to check whether the plot has been executed and prevent further actions of the same type, but that would still cause the widgets to emit the signal and run plot(), even if the check will prevent the actual plotting, but that doesn't seem like the way to go. I would also prefer to avoid running installEventFilter(), or similar, as that would, most probably, slow down even more than the previous fix.
Another option, already mentioned in a comment, is to use QObject::blockSignals:
combo1->blockSignals(true);
// do what ever you need
combo1->blockSignals(false);
I find it easier to use and read. Also, there are many situations where you simply don't know / handle the connections.
Update
Since Qt 5.3 you also have QSignalBlocker, an exception-safe wrapper for blockSignals (internally it uses RAII to block signals in the constructor and restore them to their previous state on destruction):
{
QSignalBlocker blocker{combo1}
// do what ever you need
}
Use disconnect before every connect to prevent multiple connections. Disconnecting a not connected slot is always allowed.
disconnect(spinbox1,...);
connect(spinbox1,...);
Blocking signals is also possible but I think you want the first solution.
From QtDocumentation:
bool QObject::blockSignals(bool block)
If block is true, signals emitted by this object are blocked (i.e., emitting a signal will not invoke anything connected to it). If block is false, no such blocking will occur.

qt - setText outside of paint events not ok?

Under Qt 4.7.1, Qt Creator 2.1.0, OS X 10.6.8:
I have a QLabel in the mainwindow ui, which uses Courier New / 13, with room for four lines of text.
I create four lines of text, considerably shorter than the label is horizontally, of the general format:
"my text\r\n"
I filter the text before sending it along. The only characters in the cstring will be 0x0D, 0x0A, 0x20 (space) and from there up to lower case z (0x7A') and of course the terminating zero. No other control characters - if they are received from the source, I replace them with '*'
I send the four lines of text to the QLabel as a single zero-terminated cstring via setText()
I sometimes do this at a fairly high rate, several times a second at least -- this is RDBS data from an FM station so it changes in real time:
qDebug() << rbl; // data keeps coming to console
ui->fourLineLabel->setText(rbl); // add this, display soon stops updating
This works. For a while. Then the display stops updating. This is the area at issue:
(source: fyngyrz.com)
If I leave everything else in, but take out the setText(), the problem does not occur.
I know that for some things, Qt wants painting to be done within a paint event. Is this also true of a setText() ?
Reading the docs on qt widgets, it says that widgets do their own painting within their own paint event... but the behavior here is very similar to the kind of malfappery that goes on when one actually tries to use a painter outside of a paint event. And it's definitely related to that setText(), so... mumble.
As I write this, the application has been running for hours without any display lockup, outputting the same text to the console via qDebug(). It takes about 5 minutes for the problem to occur if I uncomment the setText(). It's 100% repeatable.
Is there something I should be doing that I'm not doing, paint-wise or similar?
Thanks for any assistance.
In general you should not update Qt controls from non UI thread, only a small amount of things is allowed to do regarding a painting in non UI thread - http://doc.qt.io/qt-4.8/threads-modules.html
If you need to update UI from non UI thread - use signals and slots (QueuedConnection or BlockingQueuedConnection connections, though make sure to not create deadlock with BlockingQueuedConnection). Or if you don't want to create additional signals and slots for some easy update - use invokeMethod (it can even return value and if you use it with BlockingQueuedConnection connection type, your thread will wait until UI is updated).
And a general advice - if you have a possibility - make one call for bulk of updates to UI instead of few small calls.
It is always advised that the GUI thread interfaces with all other objects through the signal-slot mechanism. In fact, no direct calls from and to the main thread are to be made. In that manner the GUI will be responsive, and we don't end up waiting for it to come back. Certainly polling solutions are not ideal, and should be avoided as they end up using cup resources without reason.
If one is using only QThread type threads then updating the GUI should be done by using the signal-slot mechanism. When events of data presented need to be serialized using the Qt::QueuedConnection is sufficient. In your case that is true.
If not using that , then signals may not be processed in the sequence emitted. Qt::BlockingQueuedConnection should be used only when we want to restrict the caller continue from processing before the slot on the receiver has completed. This is very rarely the case for processing that happens on the GUI thread.
Special care has to be taken when we want to connect from a non-qt thread, e.g. An std thread, because the objects created e.g. in a native thread will not be known on the receiver end.
One way to update the ui from a non-ui thread is to serialize and copy your messages. Do the following (works even for non-QThreads e.g. boost::thread ):
Setup a singleton QObject that provides public methods to force-emit
signals containing the data that you want to send ,e.g. a singleton
Setup slots in objects that only accept arguments by value
Connect the signals to the slots in an object within the ui-thread
Connections must be Qt::QueuedConnection
class timer : public QObject
{
Q_OBJECT
//... write a singleton here
std::mutex mut;
public signals:
signal_tic(QString const );
public:
void force_emit_tic(QString const s )
{
std::lock_guard<std::mutex> l(mut);
emit signal_tic(s);
}
timer & ref()
{
static timer This;
return This;
}
private:
timer(){}
};
// in a main thread object setup this connection
connect(&timer::ref(),SIGNAL(signal_tic(Qstring
const)),this,SLOT(slot_accept_tic(QString const ), Qt::QueuedConnection)
// In any other thread
timer::ref()::force_emit_tic( string_when_this_happened )
Calling directly the singleton force-emit method results in the desired behaviour. (ofcourse objects must be properly copiable for this to work)
The reason for sending by value is that if you pass a const reference to temporary residing in another thread it's lifetime is not guaranteed. Furthermore, you need to take care of serializing the messages to the ui-thread before they actually arrive or you will eventually receive one of either incosistent data or a SIGSEGV. Qt::QueuedConnection guarantees that connections are serialized only within the memory space known to QThreads.

Events pool in qt

I'm working on a Qt app, and at some point I have a class (I name it here "engine") that is governing the program: it has a signal with a timeout which makes the class to draw, and evolve the app logic. Morevoer, it receives events that are caught from a QGraphicsScene.
Each engine "tick", the update() is called on the Scene, updating the drawing according to the app evolution.
Naturally, I want the drawing to be synchronized with the reactions of the events, otherwise, a drawing of some object could be made while the reaction of a event was destroying that same object, causing a SegFault.
I've tried using a queue on the engine such that I would only make the engine to react to those events on a specific place of a update, thus not interfering with the drawing part.
Two problems rised:
I cannot make a copy of a QGraphicsEvent. Apparently the copy operator is private (which I assume is for a good reason anyway).
When the class is processing the events, before the drawing, it can also happen that a new event appears, which can be "bad" because of non-synchronization of it
Taking into account this situation, is there any approach that can solve this situation? Is there any standard procedure in Qt for this? I mean, how do I ensure the drawing is not potentially desynchronized with the events' reactions of the application?

When to use QThread::exec()

I've checked a satisfying explanation but could not find. Usually docs mention that in order to use signals/slots between threads, we need to use event loops and start them by calling exec.
However I can see that w/o using exec(), I can still send signals and handle them across threads.
What's the exact use of it?
Use QThread::exec() when you want to run the event loop Qt provides for you in the QThread class. If you don't call exec(), you need to create your own event loop that processes Qt events (that is, if you want signals / slots to work). This is almost certainly more work than it's worth, unless you have very specific needs.
You say you can still send signals / slots? My guess is that you're not actually running anything on a different thread. This is a very common issue when using QThread. Put a breakpoint inside the code you think is running on a different thread and have a look at the stack trace - you may be in for a shock!
A rough example.
Suppose you have a text box. On each letter user types on the text box you want to perform some background task. You can setup a QThread for that. Emit something whenever the contents of text box changes. Assign a slot from your QThread that handles the background task. Emit something from QThread when the task finished. Handle this signal from main thread. Connect them. Start the thread when the text box is created (or any appropriate time). If you call exec() from your QThread::run() then you don't need to start() the thread multiple times.
If you don't use this mechanism, you may need to create (and/or start()) a QThread each time the content of text box changes, perform the background task and get result. This time you can still use signal/slot between main thread and this thread, but you need to start() the thread multiple times.