I'm trying to get the position of the mouse on a keyPressEvent
of a custom pg.ViewBox
.
The only solution I've found so far is to create some crosshairs and get the position of those on a keyPressEvent
. Is there a better way to do this without crosshairs?
Also, in the example I give, when I press a key, the first time nothing happens and the second time, I get a strange undecipherable error message, followed by the expected behavior (which is to print the position of the cursor) but repeated many many times:
Error in sys.excepthook:
Original exception was:
Mouse position from crosshairs: [0.3896103896103896, 0.5307017543859649]
Mouse position from crosshairs: [0.3896103896103896, 0.5307017543859649]
Mouse position from crosshairs: [0.3896103896103896, 0.5307017543859649]
...
I would be grateful for any clue about what is going on.
Here is a minimal working example:
from PyQt6 import QtWidgets
import pyqtgraph as pg
import sys
class CrosshairViewBox(pg.ViewBox):
def __init__(self, *args, **kwds):
pg.ViewBox.__init__(self, *args, **kwds)
self.crosshair_x = pg.InfiniteLine(
angle=90, movable=False
)
self.crosshair_y = pg.InfiniteLine(
angle=0, movable=False
)
self.addItem(self.crosshair_x, ignoreBounds=True)
self.addItem(self.crosshair_y, ignoreBounds=True)
def activate_crosshairs(self):
self.scene().sigMouseMoved.connect(self.move_crosshair)
def move_crosshair(self, ev):
"""
This is triggered on a sigMouseMoved which sends a position as an event
"""
pos = ev
if self.sceneBoundingRect().contains(pos):
mousePoint = self.mapSceneToView(ev)
self.crosshair_x.setPos(mousePoint.x())
self.crosshair_y.setPos(mousePoint.y())
def keyPressEvent(self, ev):
"""
In this case, ev is a QKeyEvent, for which I cannot get
the position of the mouse. So I have to use the crosshairs.
"""
self.scene().keyPressEvent(ev)
posx = self.crosshair_x.getPos()[0]
posy = self.crosshair_y.getPos()[1]
print(f"Mouse position from crosshairs: [{posx}, {posy}]")
def main():
app = QtWidgets.QApplication(sys.argv)
win = pg.GraphicsLayoutWidget(show=True)
chvb = CrosshairViewBox()
win.addItem(chvb)
chvb.activate_crosshairs()
sys.exit(app.exec())
if __name__ == "__main__":
main()
There is absolutely no need to complicate things by creating other items. Just store the mouse position as an instance attribute:
class CrosshairViewBox(pg.ViewBox):
def __init__(self, *args, **kwds):
super().__init__(*args, **kwds)
self.mousePoint = QtCore.QPointF()
def itemChange(self, change, value):
if change == self.GraphicsItemChange.ItemSceneChange and value:
# automatically connect the signal when added to a scene
value.sigMouseMoved.connect(self.mouse_moved)
self.setFocus()
return super().itemChange(change, value)
def mouse_moved(self, pos):
self.mousePoint = self.mapSceneToView(pos)
def keyPressEvent(self, ev):
print("Mouse position from crosshairs: [{}, {}]".format(
self.mousePoint.x(), self.mousePoint.y()))
Also, do not call self.scene().keyPressEvent(ev)
as it would probably cause recursion (which may be what causes the error you are seeing).