Qt - Recursive repaint needed, how? - c++

I have the following code:
paintGL()
{
if(mouse_was_clicked)
{
... do the color picking with openGL to identify a clicked element
... !!! now I need to call again paintGL() to switch the selected element from the
old one to the new one but I can't create a recursive cycle!
}
else
{
... normal code to draw the scene and the selected element in red ...
}
}
As the lines suggest, I need a way to call once more the paint event.. is there any way to accomplish this without creating a potential livelock? Something like deferring a new paint event?

If the control flow within your paintGL() is that simple, just make sure that the contens currently being in the else block are executed in every case:
void MyWidget::paintGL()
{
if(mouse_was_clicked)
{
... do the color picking with openGL to identify a clicked element
}
... normal code to draw the scene and the selected element in red ...
}

It's a bit hard to tell exactly what you're doing here.
If you're trying to setup a display widget (a color picker) when paintGL detects a mouse button has been clicked, you've mixed up your events. You should make a separate action for handling a mouseclick, which sets up flags/variables and triggers a repaint. IE, move the mouse-event handling out of the repaint callback.
I could easily have misunderstood your problem here, however... if so I apologize.
As a general rule, though, if you find yourself needing a recursive repaint in QT, you're probably working against, rather than with, the system.

Related

how can i draw a sprite by left clicking?

i've tried to make a project, but i can't draw a sprite as i want. I mean that everything works when i just draw a sprite, but it stop working when i am trying to draw the sprite by clicking left mouse button. There's code i tried:
if(zdarzenie.type == Event::MouseButtonPressed && zdarzenie.mouseButton.button == Mouse::Left)
{
pocisk.setPosition(10, 10);
oknoAplikacji.draw(pocisk);
}
Btw, I am writing in Polish as if it would change something.
And yes, i have everything good besides that.
(and i am using 2.4.1 version of SFML)
I don't know what you are doing now because you didn't provide enough of your code and I actually don't understand your if statement but, it can just be :
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sprite.setPosition(sf::Mouse::getPosition());
renderTarget.draw(sprite);
}
By the way I strongly suggest that you do not use the draw function here but organize your code to have a draw method called in a render loop, because depending on where your code is in your program, the sprite could be drawn for only one frame and then erased since it's not updated.
From what I understand in your code in Polish, you have the right code to do what you want, but the problem comes from the fact that you draw the sprite only once.
The draw method is called every frame and it will erase everything on screen and then redraw them. Doing it only once, like in your code, will only draw it a single time then delete it the very next frame.
At that point multiple solution can be used. If its a GameObject clicking can activate the object to then draw it or a simple bool could be used has a switch in your draw to make it appear.

Qt5 QOpenglWidget How can I ensure the scene is updated immediately during mousemove envent?

I am currently working on a simple CAD-like drawing program using Qt and openGL.
What I am doing is that I maintain a list of objects which is on the canvas. The paintGL() function is just loop through the list and render the objects one by one.
objects are fed to the list via slot drawObject(Object obj), in which there is an update() function to schedule an update event to update the scene.
Now, I want to do some rubberband drawing of lines:
After pick one endpoint of the line, whenever I move the cursor, a mouseMoveEvent() is triggered and it will generate an object for the line and emit a signal to drawObject(Object) slot. what the slot does is to erase the old line by doing xor drawing, and draw the new line in xor mode as well.
What I expect to happen is that every time the mouse is Moved, a new object is rendered to the scene. However, it is not. For example, if I move the mouse
fast, then before the update() function actually update the scene, multiple mouseMove events has been triggered and it seems that these events are never been handled, i.e., the correspondence objects never goes to screen. What the program actually does is that a lot of random artifacts is left on the screen after a fast rubberband dragging.
It seems that this is due to the fact that what update() function of QOpenGLWidget does is that it generate an event to inform the widget to redraw later for performance purpose.
During the course of me writing this question, I discovered the repaint() function which do an immediate update. However, the lagging is quite significant: when I move the mouse fast, the rubberband line is not following.
So, my question is, how to implement the rubberband drawing so that it could take advantage of the update() machanism to boost the performance while not having those glitches on the screen?
I have searching around on this but I could find a single article talking about this fast-moving mouse stuff.
Thank you in advance!

How to get control back after drawing on scene

I am trying to implement simple backtracking algorythm (solitaire game) and I also want to show the progress, not only the answer. So I decided to use QGraphicsView to draw gamefield's status on it. I want to update scene after I field's changd and when I want to get control back, to resume changing gamefield. What is the best way to do this?
UPD:
pseudocode
List<Step>* solve(GameField& field) {
//changing gamefield, clearing scene, adding some objects (rects with text) to scene
updateScene(); //here I want the scene to be updated right now, and
//not when it's scheduled to
}

Trying to update only a rectangle in a widget in Qt, but the entire widget's area is updated instead

This happens in Qt Simulator (for phones). I'm trying to update only a portion of a widget's area, but the entire widget is updated instead.
To illustrate, the following code:
void Widget::mousePressEvent(QMouseEvent *event)
{
update(0, 0, 10, 10);
}
void Widget::paintEvent(QPaintEvent *event)
{
qDebug() << event->rect();
}
Gives the following debug output when I click on the widget:
QRect(0,0 458x832)
Which is the entire area of the widget.
What am I doing wrong here?
Edit
I ran the same code on Linux, and it worked as it should, the debug output was
QRect(0,0 10x10)
In most GUI framework I've seen you can't update just some part of the application window/widget. Even if there's some function in API to update some rectangle - like update(x,y,x,y) you're using - it's just to inform the Framework that it needs to update at least the given rectangle, and framework can update a bigger part of the screen.
I'm not sure how it works in phone Qt but it's done this way in desktop version because in most OSes GUI application doesn't store its 'image' anywhere, and if you minimize and then show your window you need to recreate entire surface.
All this means that you can't rely on the assumption, that you'll paint something and then you'll be adding other paint operations in some custom rectangle when you need. You should implement some general 'paint' function, that can redraw everything from scratch and leave the painting optimization to the framework.
I am not familiar with Qt on the phones. But maybe something else is triggering the update of the whole widget. Qt sends one paintEvent for all update() called during one event loop processing. So your code may be calling for a partial update but somewhere in the window system may somehow get touched and calls for a full update.
Try repaint() and see if that sends your paintEvent the right region.
It turned out that this bug was present only in Qt Simulator. On the actual phone itself, the update region was being passed correctly. I tested this by displaying a QMessageBox with the coordinates of event->rect.

How to have dynamic scene update in libqglviewer

I'm using libqglviewer for a project, I read input from a motion capture device through USB and display this as a human in the viewer. I draw the opengl things in the draw() method of the viewer, it works fine. However, when the motion controllers change, I actually get new position values and i draw these in the viewer, BUT i dont see this update until i click on the viewer screen. Is it possible to update the frames in the viewer by itself?
It looks like you just need to post an updateGL right after you get the new position values.
QGLWidget::updateGL()
void QGLWidget::updateGL () [virtual slot]
Updates the widget by calling glDraw().
For painting in 2D the function is called update.
Also, don't call it from inside your draw method (see updateGL in the libQGLViewer documentation).
This note comes from QWidget::paintEvent():
Note: Generally, you should refrain from calling update() or repaint() inside a paintEvent(). For example, calling update() or repaint() on children inside a paintevent() results in undefined behavior; the child may or may not get a paint event.
The same probably applies for QGLViewer.
You can also use repaint, but is isn't recommended (see QWidget::repaint()).