Qt show change immediately - qt

I get continuous answers from a server with a delay from 1 sec. I append() this answers to an QTextEdit field. But the changes first displayed when the method call has finished.
How can I displayed the changes immediately?
I have tryed update() but it doesent work..
void ClientWidget::setAnswer(ValueStream *resultStream){
std::vector<std::string> answer;
for(int i = 0; i < 15; i++){
value tmpResultValue;
if(resultStream->get(tmpResultValue)){
this->client.parseResult(tmpResultValue, answer);
std::vector<QString> qAnswer = vectorStringToVectorQstring(answer);
for (unsigned int n = 0; n < qAnswer.size(); n++){
this->answerTextEdit->append(qAnswer[n]);
}
this->answerTextEdit->update();
}
answer.clear();
}
resultStream->close();
delete resultStream;
}
after this->answerTextEdit->append(qAnswer[n]); the changes should displayed but they dont displayed immediately

When you set the TextEdit widget's text, a signal is emitted that it has changed, in order for the widget to update what you see. That signal is placed in a queue of messages that are processed as events in the Qt event loop.
While you're processing the incoming data, Qt's event loop cannot continue until you finish. An easy, but not the best way of handling this is to call QApplication::processEvents to allow the event loop to run; this can be very inefficient as all events in the queue are processed.
A better way to handle time-consuming processing is to move it onto a new thread, which is reasonably easy to do with QThread. That way, you can process the incoming requests from the server and emit a signal from your thread to the main thread, which can then update the TextEdit widget.
To understand how to use QThread, I suggest reading this article. It really isn't difficult to do and I recommend you try it, rather than adding a call to QApplication::processEvents.

You can call
QApplication::processEvents();
after calling your method.

if you can change ValueStream to emit a signal each time a new value is available with the value as a parameter, then it will become much easier. just connect a slot to it where you append the answer to the answerTextEdit

Related

Forking with QT

using QtCreator to make a loftier interface to a sofware.
There is basically a set of buttons to tune and inputs, a start and stop job
buttons, my problem comes from an infinite loop that freezes the display so I came up with using fork() so that the loop have to compete with the main program instead of eating up the whole resources (no multithreading), but the program crashes spiting:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not
been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion
`!xcb_xlib_threads_sequence_lost' failed.
the fonction calling the loop is called 'ON', 'OFF' is supposed to exit the forked process.
//in button 'ON' func
ps = fork();
if(getpid() == ps)
{
while(1)
{
strcpy(word, charset(minlength, maxlength, N));
ui->pass->setText(word);//operation on the display
....SNIP
}
}
//In button 'OFF' func
if(getpid() == ps)
exit(0);
I'm really asking what is the correct way of starting a while(1) and be able to break, exit, or return from it while not freezing the window using QT, thanks.
You crash probably here:
ui->pass->setText(word);//operation on the display
as in Qt, you can not change UI from non UI threads directly. Only from signals and slots mechanism.
The proper way to not freeze UI is obviously to compute lengthy operations in another thread.
You can achieve this in several ways:
One is by sub-classing QObject class to create 'worker object' which would perform all heavy operations. You create new QThread object that should live as long as you need your object. And use QObject::moveToThread method to move created object to new thread. To control your worker object you should send signals from object and call it's slots also via signal-slot mechanism. If you call them directly - they will be executed in caller thread (so do not perform stuff like worker->startHeavyJob(); in UI thread). Instead emit signal in UI (emit sigStartHeavyStuff();) and connect it to slot of your worker object (slotDoHeavyStuff();)
if you do not want to bother with this (if operation is pretty small)
- you can use QApplication::processEvents() to process events in UI event loop while going in your infinite while loop.
Another way is to use QtConcurrentRun framework to run function in separate thread which manages itself. Threads are taken from thread pool and are managed by Qt. This approach looks like something you want to do. Though you still will be able to access UI objects only through signals and slots.
I see one big issue in the presented code that is causing your freeze: You never let Qt process anything while you are in the loop. You need to allow Qt to run it's event loop. The easiest way is to use QApplication::processEvents() inside the loop.
I'm also not a fan of a while(1) loop for a couple of reasons. The first of which is that it can eat machine cycles waiting for things to happen. I doubt you really need to run the code as fast as possible, you could probably get away with some sleeping in your loop.
The other issue is that it is hard to break out. A cleaner approach would be something like this
void MyClass::on_pushButton_ON_clicked()
{
MyClass::done = false; // this is a class attribute
while (!MyClass::done) {
QApplication::processEvents();
//...
}
}
void MyClass::on_pushButton_OFF_clicked()
{
MyClass::done = true;
}

Qt crash when drawing, even though in GUI thread

I think I'm having a problem similar to the one in Qt crash when redrawing Widget, and switching to Qt::QueuedConnection fixed the problem. However, in my case, both the signal emitter and received are always in the same thread (the main thread).
I have a QAbstractItemModel with entry rows, and a QSortFilterProxyModel for filtering. Since the model can be very large, I wanted to make a progress bar when filtering. Updating the filter basically does this in a slot that is connected to a QAction::toggled signal:
m_ProgressBar = new QProgressBar(); // Put into status bar etc.
auto connection = connect(m_filteredModel, SIGNAL(filterProgressChanged(int)), m_ProgressBar, SLOT(setValue(int)), Qt::QueuedConnection);
m_filteredModel->UpdateFilter();
delete m_ProgressBar;
disconnect(connection);
UpdateFilter basically does some housekeeping and then calls invalidate, making the filter model requery filterAcceptsRow for every row.
The filter model then emits the filterProgressChanged(int) signal within filterAcceptsRow (works by incrementing a counter and dividing by the source model's row count, and is only emitted when the actual int progress value changes).
UpdateFilter returns when the filtering is complete. The progress bar is not deleted until then (verified), so it should work in my opinion. Not deleting the progress bar leads to getting a new one every call, but the crash is still the same.
Everything is done in the main thread: Creating the progress bar, calling UpdateFilter, emitting the filterProgressChanged signal. However, when the connection is created as Qt::AutoConnection, i.e. direct, it crashes (only when disabling the filter, for some reason) within repainting the progress bar. The same happens when I call setValue directly in my own event handler, which is what I did prior to switching to the current code.
Now I have a solution that works, but I don't understand why the original code does not work. I thought that a DirectConnection would only make an actual difference when sender and receiver of the signal are in different threads, but they're not. You can easily see in the stack trace that everything happens within the same thread, and that is even true with the queued connection.
So, what's going wrong in the original code? Is there something I just missed? Is there any way to get more information out of the actual crash?
I only found out that in void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op), state() returns 0, and the code assumes it never returns 0, which is the immediate crash reason, but likely not the reason. And the stack trace points to painting as the problem area, that's all I saw when debugging this.
I'm on Windows with Qt 5.4.2 (also tried 5.7), and with MSVC 2013, if any of that matters.
Edit: As requested by code_fodder, I added the UpdateFilter and emit code (actualFilterFunction performs the actual filtering, but has nothing to do with signals or GUI or anything).
void MyModel::UpdateFilter() {
m_filterCounter = 0;
m_lastReportedProgress = -1;
invalidate();
}
bool MyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
m_filterCounter++;
int progress = (100 * m_filterCounter) / m_sourceModel->rowCount();
if (progress != m_lastReportedProgress) {
emit filterProgressChanged(m_lastReportedProgress = progress);
}
return actualFilterFunction();
}

Reliably showing a "please wait" dialog while doing a lengthy blocking operation in the main Qt event loop

I've got a Qt app that needs to call an expensive non-Qt function (e.g. to unzip a ~200MB zip file), and since I'm calling that function from the main/GUI thread, the Qt GUI freezes up until the operation completes (i.e. sometimes for 5-10 seconds).
I know that one way to avoid that problem would be to call the expensive function from a separate thread, but since there isn't much the user can do until the unzip completes anyway, that seems like overkill. I can't add processEvents() calls into the expensive function itself, since that function is part of a non-Qt-aware codebase and I don't want to add a Qt dependency to it.
The only thing I want to change, then, is to have a little "Please wait" type message appear during the time that the GUI is blocked, so that the user doesn't think that his mouse click was ignored.
I currently do that like this:
BusySplashWidget * splash = new BusySplashWidget("Please wait…", this);
splash->show();
qApp->processEvents(); // make sure that the splash is actually visible at this point?
ReadGiantZipFile(); // this can take a long time to return
delete splash;
This works 95% of the time, but occasionally the splash widget doesn't appear, or it appears only as a grey rectangle and the "Please wait" text is not visible.
My question is, is there some other call besides qApp->processEvents() that I should also do to guarantee that the splash widget becomes fully visible before the lengthy operation commences? (I suppose I could call qApp->processEvents() over and over again for 100mS, or something, to convince Qt that I'm really serious about this, but I'd like to avoid voodoo-based programming if possible ;))
In case it matters, here is how I implemented my BusySplashWidget constructor:
BusySplashWidget :: BusySplashWidget(const QString & t, QWidget * parent) : QSplashScreen(parent)
{
const int margin = 5;
QFontMetrics fm = fontMetrics();
QRect r(0,0,margin+fm.width(t)+margin, margin+fm.ascent()+fm.descent()+1+margin);
QPixmap pm(r.width(), r.height());
pm.fill(white);
// these braces ensure that ~QPainter() executes before setPixmap()
{
QPainter p(&pm);
p.setPen(black);
p.drawText(r, Qt::AlignCenter, t);
p.drawRect(QRect(0,0,r.width()-1,r.height()-1));
}
setPixmap(pm);
}
Moving to another thread is the correct way to go but for simple operations, there's a much less complicated way to accomplish this without the pain of managing threads.
BusySplashWidget splash("Please wait…", this);
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()), &splash, SLOT(quit()));
QFuture<void> future = QtConcurrent::run(ReadGiantZipFile);
watcher.setFuture(future);
splash.exec(); // use exec() instead of show() to open the dialog modally
See the documentation about the QtConcurrent framework for more information.

QT5.0.2 on Win7 -- Update widgets independently and simultaneously

Using 5.0.2 on Win 7
I have 2 “ImageLoop” classes [which extend QWidget] where each take up half the screen, split vertically. Each contains a QLabel for displaying a list of jpg files. So, inside a for loop, I give each widget their list of images, and emit a “listfull” signal which I have connected to a slot – “playList” – in each of the two widgets. Unfortunately, it appears that only the first widget’s signal ever gets emitted as only the first widget is ever updated.
I am new to Qt programming and maybe I am misunderstanding the slot/signal system. I thought the pseudocode below would, for each instance, fill the list, emit the signal, and each instance would go off on their merry way — basically each widget simultaneously and independently showing images. So, question is what am I missing? Or am I going to have to spawn each of these in their own thread?
Thanks!
Pseudocode
for(int i=0; i<2; i++){
Create ImageLoop instance
connect(instance, SIGNAL(listfull()), instance, SLOT(playList()));
instance->FillList(arrayOfImageFileNames);
}
//inside of ImageLoop class
void FillList(arrayOfImageFileNames) {
//adds all files to an internal list
//when finished
emit listfull();
}
//inside of ImageLoop class
void playList() {
//code to loop through each image and show it
}
for(int i=0; i<2; i++){
Create ImageLoop instance
connect(instance, SIGNAL(listfull()), instance, SLOT(playList()));
instance->FillList(arrayOfImageFileNames);
}
You are expecting this pseudo-code to asynchronously call playList() on both imageLoop instances. What's happening instead is Qt is connecting listFull to playList directly, making this pseudo-code equivalent to:
for(int i=0; i<2; i++){
Create ImageLoop instance
instance->FillList(arrayOfImageFileNames);
instance->playList();
}
My guess is playList is also synchronous, which means it will finish, and only then will the for loop continue to the second ImageLoop instance.
Qt doesn't allow you to have multiple GUI threads, nor can you update the GUI from multiple threads, so you need to show and image then send a signal asynchronously to show the next image.
Chances are, what you really want is to start a timer when fillList() is done that calls a slot showNextImage() after a certain delay.

How to combine own message loop and Qt event loop?

I have a class derived from QThread: class MyClass : public QThread. In the run method I have "my own" message loop:
run() {
// exec(); // while not reached
while (_runMessageLoop && ...) {
hr = CallDispatch(.....);
if (hr== 0) QThread::msleep(100);
// QCoreApplication::processEvents(); // Does not work
}
}
Since exec() is not executed, I have no Qt event loop. This obviously causes signal / slots not to work correctly. Is there any chance to combine the Qt and my own message loop? Or do I need a frequently firing timer in order to do what I have accomplished in my infinite loop?
The right way "Qt-wise" is to use a timer and let Qt manage the event loop.
If you need to depend on external things, you can use things like QAbstractSocket to send events when data comes in over an external socket, eg.
This is not really the answer for implementing the event loop correctly, I'm fairly sure there is a way, but more of a workaround:
Start the thread normally, exec() and all, and connect the start signal to a slot (make sure it gets called in the right thread), then put your loop there, and call Qt's processEvents() in that loop. That makes sure Qt event loop gets properly set up.

Resources