QT: QGraphicsView not updating from inside loop - qt

I'm trying to draw a picture to the screen repeatedly from inside an infinite loop. When I try to draw the picture to the QGraphicsView, it doesn't update unless I break from the loop. Here is my function with the infinite loop:
void MainWindow::displayNoise() {
QImage noise(WIDTH, HEIGHT, QImage::Format_RGB32);
float t = 0;
while (true) {
// Populate noise
rendered_image = noise;
DisplayQImage(rendered_image);
t += 0.200;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
And here is DisplayQImage():
void MainWindow::DisplayQImage(QImage &i)
{
QPixmap pixmap(QPixmap::fromImage(i));
graphics_scene.addPixmap(pixmap);
graphics_scene.setSceneRect(pixmap.rect());
ui->scene_display->setScene(&graphics_scene);
}
Note that graphics_scene and rendered_image are members of MainWindow. If I insert a break statement after my call to DisplayQImage then the first frame renders, but if I don't exit the displayNoise function then the widget doesn't update. I set up a signal so that when I press N it calls displayNoise, and I know the loop is looping. Why isn't the picture showing?

It is because you are not giving the eventloop time to do it's thing. Your function is being called from the eventloop, and the rendering is called from the same eventloop, because they live in the same thread. So you have two options:
write your code in an asyncronous way, eg. with a QTimer.
manually call the eventloop: https://doc.qt.io/qt-5/qeventloop.html#processEvents
I think the first option is probably the nicest way.

Related

In this code can you please explain what is happening after the draw(n -1) function

#include <stdio.h>
#include <cs50.h>
void draw(int n);
int main(void)
{
int height = get_int("number:");
draw(height);
}
void draw(int n)
{
if(n <= 0)
{
return;
}
draw(n - 1);
for(int i = 0 ; i < n ; i++)
{
printf("#");
}
printf("\n");
}
Iam learing recursion topic, suppose the user input 4 when the compiler completes the if part the value of n is '0' and returning when i debug , but then the for loop starts the value of 'n' becomes '1' and also 'i' doesn't change it constantly 0 why is that iam expected n becomes 0 after the if draw(n - 1) completes.
I will try to make this explanation as simple as I can. First things first, To begin with, when using recursion, you would be noticing the calling of a method within itself with a different argument. In your case it is the draw method.
Now each time, a draw method is called inside another draw method, the outer method(in this case the draw that is called first) stops its flow of execution till the completion of the inner draw.
So when you called draw(4), it ran all the code till it reached line 5 in draw method, and called draw(3). Your for loop of draw(4) is not executed yet. This will continue till draw(1) calls a draw(0). At this stage, draw(0) will return out and the draw(1) will continue its for loop from where it left. So you would find that here n=1, leading to the first print of # and then a new line after it. Once the operation completes in here, it continues with where it left for draw(2). Which is the for loop in draw(2) where the value of n=2. And here it does two print of # and then a new line. This continues.
Now for the question why i is always 0, it is to do with what we call scopes in programming, you can see that each time the i is declared fresh in the loop and assigned a value 0. This means, each time a for loop is hit, the value of i is reinitialised to 0. If you had a global var i out side of your draw method, you would have had the value of i being retained.
I did try my best to put things in as simple form as possible but feel free to let me know if you needed more clarity.

How to continue after signal emission?

I'm building a Othello game in Qt quick and C++.
I use this code from QML dialog to start new game, when one player is human, I wait for input. When two players are PC, I face the problem that the GUI will wait for the slot to finish, in PC players the slot call flipTurn() (because it is PC, no input to wait for), flipTurn is recursive, so the GUI will block until the game end.
I want it to update the board after each move. link for the project:
reversi project
myBroker.createGame(blacktypebutton.checkedButton.playertype,
whitetypebutton.checkedButton.playertype,
getBlackAlgo(),
getWhiteAlgo(),
getBlackDep(),
getWhiteDep());
console.log("finished creating game !");
void Broker::flipTurn()
{
if(someoneWon()){
emit gameEnd();
return;
}
emit updateBoard();
if (currentGame->getTurn() == Constants::BLACK){
currentGame->setTurn(Constants::WHITE);
if (currentGame->getWhitePlayer().getType() == Constants::PC){
currentGame->pcMove(Constants::WHITE);
flipTurn();
}
else
currentGame->updatePossible();
}
else{
currentGame->setTurn(Constants::BLACK);
if (currentGame->getBlackPlayer().getType() == Constants::PC){
currentGame->pcMove(Constants::BLACK);
flipTurn();
}
else
currentGame->updatePossible();
return;
}
emit updateBoard();
}
bool Broker::createGame(int blacktype, int whitetype, int blackalg, int whitealg, int blackdep, int whitedep)
{
currentGame = new Game(blacktype,whitetype,blackalg,whitealg,blackdep,whitedep);
currentGame->setGameBoard(&gameBoard);
updatePossible();
emit gameStart();
}
void Broker::onGameStart()
{
if(currentGame->getTurnType() == Constants::PC){
currentGame->pcMove(currentGame->getTurn());
cout<<"in ongamestart slot"<<endl;
flipTurn();
}
}
Since it is a turn based game, you will just need a different source to trigger the next turn.
Instead of calling flipTurn() directly, you call it through Qt's event loop.
Since you probably will want the human in front of the computer to see the game progressing, very likely with a delay.
For example with a single shot timer
// instead of calling flipTurn() directly
QTimer::singleShot(500, this, SLOT(flipTurn()));
Call next flipTurn() after 500 milliseconds.
I used
QCoreApplication::processEvents();
After each call to flipTurn() , so the GUI engine process any waiting signals (in my case the updateBoard() signal).
Although it isn't the best solution, it worked well for my homework.

QProgressDialog does not display immediately

I have a QProgressDialog that I want to display immediately
QProgressDialog *progress = new QProgressDialog("Downloading files...",
"Cancel", 0, 2*selection.size()+1);
progress->setMinimumDuration(0);
progress->setWindowModality(Qt::WindowModal);
progress->setValue(0);
Then I run a for loop with the task and finally assign the maximum value:
for (int i = 1; i < selection.size()+1; ++i)
{
progress->setValue(2*i-1);
if (progress->wasCanceled())
break;
do_half_task();
progress->setValue(2*i);
if (progress->wasCanceled())
break;
do_second_half();
}
progress->setValue(2*selection.size()+1);
But with this code, the dialog window borders appear, transparents without any widgets inside, and only gets filled with the label and progressbar when a full for loop has completed.
I think this is because only after a full loop has completed is that Qt can compute the duration of each step, and check that it will be >0 which I am setting as minimum duration. However, from the docs I see
minimumDuration : int
If set to 0, the dialog is always shown as soon as any progress is set. The default is 4000 milliseconds.
From where I would've expected the dialog to show up immediately in the first loop pass after setting progress->setValue(1).
How can I get my QProgressDialog to appear immediately?
Not sure if this matches for Qt too
but in C# if you run the execution of your code in the same thread like
ProcessBar p = new ProcessBar();
this.Controls.Add(p);
...
for (int i = 0; i < 100; i++) {
p.Value = i;
Thread.Sleep(1);
}
then you have the problem that your Form does not get to the code where it is redrawn.
Maybe try making your execution loop in a nother thread?
When you make the main thread go into a loop, it can't do any event processing until the loop ends and your method returns.
So it can only process all "paint update" requests once you are done.
You can call QCoreApplication::processEvents() inside the loop to allow it to return to event processing for a while.
To show the dialog immediately then just call QProgressDialog::show().

Qt/PyQt: How do I manually draw a caret?

I know a position within a QWidget where I would like to draw a caret.
Calling paint redraws the entire widget, and I only want to redraw that one 'box' containing the caret/character. Is there a way to tell it not to erase the entire widget?
How do I create a timer that will cause it to blink (even when the program is doing something else)?
I am looking to do it manually, not through QTextLayout.
QWidget has a repaint() method to repaint only a certain portion of the widget
QWidget.repaint (self, int x, int y, int w, int h)
QWidget.repaint (self, QRect)
QWidget.repaint (self, QRegion)
You can create a QTimer that will fire at intervals:
timer = QtCore.QTimer()
timer.timeout.connect(doBlinkMethod)
timer.start(1000) # every second
def doBlinkMethod():
print "blah"
You could also implement your widgets own built in timer to just act on itself internally:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qobject.html#startTimer

How to read each line of a QPlainTextEdit in Qt?

I want to make a program where I take each line of QPlainTextEdit and send it to a WebView which will load those urls. I don't need to check the URL's because the system makes it like that
http://someurl.com/ + each line of the QPlainTextEdit
I have few ideas which I don't know how to use:
Use a foreach loop which will make its self wait 5 seconds to loop again
Make a QTimer to wait like 5 seconds and tick with an integer and when the integer hits the number of lines it will stop
And all of that will be done on every 4 hours by waiting with another timer.
First of all you need the contents of the QPlainTextEdit. Get them and split them using the new line separator to get a list of QStrings each representing a line.
QString plainTextEditContents = ui->plainTextEdit->toPlainText()
QStringList lines = plainTextEditContents.split("\n");
The easiest way to process the lines is to use a QTimer and store somewhere the current index in the list.
// Start the timer
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(processLine()));
timer->start(5000);
Now the slot is called whenever the timer is triggered. It just gets the current line and you do it whatever you want.
void processLine(){
// This is the current index in the string list. If we have reached the end
// then we stop the timer.
currentIndex ++;
if (currentIndex == lines.count())
{
timer.stop();
currentIndex = 0;
return;
}
QString currentLine = lines[currentIndex];
doSomethingWithTheLine(currentLine);
}
Similarly do the same with the 4h timer.

Resources