Mouse handling using asyncio?
-
So I'm writing a mouse class that you call when you want to drag and draw a selection area on the screen. The idea is that the calling function calls areaSelect, then waits for areaSelect to return a Rect() of the location of the dragged rectangle. I have written a very basic outline of what the class will look like. Right now it hooks into the mouse events, sets a bool to True, then waits forever for the mouse release. I was wondering if there is a more elegant way than an endless While, like using async or something, to wait for the bool to be set to False.
from PySide6.QtWidgets import QWidget from PySide6.QtCore import QRect class MouseHandler(QWidget): def __init__(self): super().__init__() self.drag_in_progress = False def mousePressEvent(self, event): if self.drag_in_progress is True: # do something pass def mouseMoveEvent(self, event): if self.drag_in_progress is True: # do something pass def mouseReleaseEvent(self, event): if self.drag_in_progress is True: # do something self.drag_in_progress = False def areaSelect(self) -> QRect: self.drag_in_progress = True while self.drag_in_progress is not False: pass return QRect(0, 0, 1, 1) -
Leaving aside whether there are already other ways to do this.
The point about event-driven UI coding is that you don't write or call a function like your
areaSelect(), which blocks till something happens. Instead in yourmouseReleaseEvent()you recognise/calculate the dragged rectangle and execute whatever you want to do with it from there, either directly or via Qt's signal/slot system so you can write the handler code elsewhere. -
two things:
my code already does a "zoom to area" thing that does get handled in the mouseRelease event, but I wanted to come up with a more generalized way of doing it, as I can see "drag and click" to come in handy in other parts of my program. And yes, if I call this function from inside another event handler, then the mouse clicks will never even be seen.
you mentioned "other ways to do this". can you point me in that direction?
-
If you want to draw the selecting band see QRubberBand.
If you were using aGraphicsScenethat has rubberband drawing and selection. I don't know aboutQWidget, what you are doing there, what your zooming is about, etc.
Qt also has various item-selection mechanisms if that is what you want.
If you want a "more generalized way of doing it" have yourmouseReleaseEvent()emit a signal for the area selection or whatever.
It is "unusual" to declare a class deriving fromQWidgetto be aMouseHandlerin any generic sense. I don't know how you think you are going to use your class. -
D dullfig has marked this topic as solved on
-
I just realized that this idea won't work. You can't just have one event handler halt the whole GUI while waiting for a rectangle to be drawn. Back to the drawing board.
@dullfig
But that is exactly what I said! You must not "wait" for anything. And you don't need to. You don't have to "go back to the drawing board", you just need to do your work frommouseReleaseEvent(), as I wrote earlier either directly or via emitting a signal. I don't see the problem. -
Well, there is a way to achieve what you want to do. Still, it is better not to do it this way. Instead of your infinite loop you can create QEventLoop and call
exec()on it. On mouseReleaseEvent you can then quit the local event loop. Be careful with this if you really want to go down this route... (nested event loops can be nasty!)