PDA

View Full Version : How to make QT Mouse move event faster?



Yippiyak
10th July 2018, 20:19
Hello!
I am designing a ui that incorporates a cross hair like feature that tracks the mouse in the UI windows, but when I move the mouse quickly I get significant lag behind the cursor. I am wondering if anyone knows a way to increase the update/refresh rate on the mouseMoveEvent function. Thank you!

d_stranz
10th July 2018, 23:11
What you are observing is likely due to excessive repainting in your widget. If have implemented your cursor such that each mouse move causes a repaint of the window content, then that's probably the cause of the lag.

Yippiyak
13th July 2018, 01:50
What you are observing is likely due to excessive repainting in your widget. If have implemented your cursor such that each mouse move causes a repaint of the window content, then that's probably the cause of the lag.

So what do you suggest instead of repainting? I need the crosshairs to track the cursor flawlessly, so I am unsure what I need to fix in order to do so.

d_stranz
13th July 2018, 18:17
You could try using a Qt::CrossCursor QCursor instead of your own crosshairs. You could also derive from QRubberBand and pay careful attention to how the QRubberBand::paintEvent() is implemented.

Yippiyak
16th July 2018, 21:11
You could also derive from QRubberBand and pay careful attention to how the QRubberBand::paintEvent() is implemented.

Can you elaborate on how I would do such a thing? I do implement a rubberband for selecting/highlighting data, but perhaps I am in fact not paying enough attention to its implementation.

d_stranz
16th July 2018, 23:10
What I have done to implement custom rubberbands is a little bit complex. My plotting widget supports many different rubber band types, from vertical or horizontal lines, to rectangles, to arbitrary lassos. There are also three modes of operation: zoom, pan, or select. These different modes can be controlled by the mouse or keyboard (or both). To handle all this, I have a large state machine (using the Qt state machine framework) which controls what happens in each mode, what gets painted, and what signals are emitted at the end of an interaction. It is very generic, meant to handle almost any type of interaction with a plot.

What it does not support is having a crosshair cursor that is visible all the time. It does support a crosshair rubberband which is turned on by a mouse press, moved, and turned off by a mouse release.

To give this real-time performance, I do essentially this:

- when the mouse is pressed, I create a snapshot of the window by rendering it into a QPixmap. I also create a QPainterPath and put the mouse point into it.

- when the mouse moves, I update the QPainterPath as appropriate for the style of rubber band. For example, for a horizontal line rubber band, I update the path to hold a line from the initial position to the current position while keeping the y coordinate fixed. I then invalidate the widget to cause an repaint.

- in the widget's paint event, I check the state machine to see if the rubberband is active, and if so, I draw the pixmap (instead of the normal paint update for the widget), then I draw the painter path. If the rubberband is not active, I let the widget redraw itself as normal. This procedure of drawing the pixmap then drawing the path means the path gets erased and redrawn smoothly with each move and doesn't leave "mouse droppings" behind.

- in the mouse release event, I emit a signal appropriate for the mode (eg. zoomTo( x0, y0, x1, y1 ) based on the start and end coordinates of the rubber band), destroy the pixmap, and invalidate the window.

The net effect is that while the rubber band is active, the underlying QWidget is being redrawn from the pixmap, not its native painting code. This gives realtime performance since drawing a pixmap is instantaneous. As soon as the mouse interaction is over, the widget gets repainted using its normal code.

Your plotting widget doesn't necessarily need to be rewritten to use this; you can install an event filter that tracks the paint and mouse events and overrides the widget's normal behaviour by vectoring them into the custom rubber band class. If the rubber band is active, the rubber band class eats the events and does what it needs. If the rubber band is not active, the event filter does nothing and lets the widget handle them as normal.

But like I said, this doesn't work if you need dynamic updates to the widget while the mouse is moving.

If the updates to the plot are not frequent and if you want to redesign your plot widget, you can move the pixmap code into the widget itself. Each time the plot data (or viewport onto the data) changes, you render the new plot to a pixmap and simply draw the pixmap in every paint event. This will give you realtime redraws under all circumstances, and the only time the actual drawing code gets executed is on a data, viewport, or size change.