Unsolved Update often the text of a label
-
I wrote an algoritm in python that solve efficently sudoku, and now using PyQt5 I'm tring to show every iteration that the algoritm does. I creat a principal function that solve the sudoku and another one that update all the label (it works because at the start show the original sudoku) but i have an issue: I can't update the label until the function (the principal) is finished, stupidly I can say that PyQt5 update only when all the code is in "standby" waiting an input.
-
Just update the labels at the end of each iteration?!
Then give the user the opportunity to chose between processing a single step or just running through everything and just show the final result at the end. -
@Spidiii
This is because when you go, say,QLabel.setText()
, this is not redrawn on-screen until the next time the Qt event loop is hit, which will not be happening if your backend is sitting in a loop keeping calculating the next move and updating the labels. The next you get to "when all the code is in "standby" ", the update will happen, showing only the final state.There are a couple of ways you can address this.
-
As @Pl45m4 says, make it so there is a button for the user to "single-step" through your algorithm, just executing one iteration in response to each click. Or, have a
QTimer
ticking which executes one step each time. Labels will update, and your GUI will be "responsive" to user input. This requires a redesign of your program, and it may not be how you wish it to function. -
Put
QCoreApplication::processEvents()
calls into your code after updating the label. To see every update you would need to put this after everyQLabel.setText()
. If your algorithm has many steps and runs "fast", as I imagine it does, you may find this is a considerable slow down for its execution speed. You could only callprocessEvents()
after every so-many steps to speed up, but then user won't see intermediate updates. -
Try calling
QLabel.repaint()
(notQLabel.update()
) after everysetText()
. This is the only way to achieve "animation" of the label without hitting the Qt event loop and slowing execution down. Try it!?
-
-
@Spidiii said in Update often the text of a label:
I can't update the label until the function (the principal) is finished
This sounds like you're blocking the event loop.
One (dirty) solution would be to call https://doc.qt.io/qt-5/qcoreapplication.html#processEvents in your loop inside that function.
But it is hard to say what really happens without seeing code. -
uhuhu 😱 all the processEvent suggestions, quick clap your hands or all the fairies will die
But seriously, don't go that route if you don't have to! I Already see thread sleep calls being placed because the labels update "too quickly"
-
@J-Hilk
For a backend which is calculating and producing lots of updates, like this or a chess playing program, you only basically have a choice ofprocessEvents()
orrepaint()
, so what else? E.g. threading won't help here. If you/the OP want to slow down the animation, I'd go for theQTimer
approach. -
@JonB said in Update often the text of a label:
threading won't help here
Why not?
You should of course not produce too many GUI updates as it anyway does not make sense. But this can be solved. -
@jsulm
With thread you have two ways of signalling the GUI to update: queued connection or blocking connection.With queued connection the user won't see the updates till the next time the GUI thread runs, and at that point it is very likely to have many sequential updates to process so the user will only see the final state, not the intermediates.
With blocking connection it will work but be really slow. You might as well not use a thread in this case as it's all sequential, non-threaded would actually run faster.
I read the OP's requirement as "I'd like the UI to visually change as fast as the backend generated a new state, whether that's too fast for the user to read or not". It's an "animation". In which case only
repaint()
will keep up. If that's not the desire, then fine, it can be implemented differently. -
@JonB The way I would do it is, move the calculating into a thread, emit each new state of the labels.
In the Gui thread, save those states in a vector/list.
Than you can quite easily either show all states consecutively via a timer or cycle through them with a button
-
@JonB said in Update often the text of a label:
and at that point it is very likely to have many sequential updates to process so the user will only see the final state, not the intermediates
I disagree. You will not see all updates if you do too many, but if you do it properly you will see more than just final state. Properly means: the thread should make sure it does not send too many updates.
-
@J-Hilk , @jsulm
That's OK, I disagree too :) Tell you what --- let's agree that we can't say what the best solution for the OP is until he makes clear what precisely he wants to achieve? In particular, let's see what he means byI'm tring to show every iteration that the algoritm does
and then consider whether threading adds anything assuming he does wish to display every iteration.
-
@JonB said in Update often the text of a label:
I'm tring to show every iteration that the algoritm does
Yes, I also was wondering how this makes sene :-=)