pyqtgraph 鼠标交互:使用鼠标右键或中键缩放到所选框
pyqtgraph mouse interaction: using mouse right or middle button to zoom to the selected box
在 pyqtgraph examples -> View Box Freatures 中,我们可以通过设置 v2.setMouseMode(v2.RectMode)
使用鼠标交互“左拖动缩放到框”
但此交互仅在鼠标一键模式下可用。我如何修改交互,以便我可以在标准的三键鼠标模式下使用鼠标右键或鼠标中键 缩放到所选框?
谢谢大家!
pyqtgraph
的ViewBox
class只有两种“鼠标模式”:
- PanMode:鼠标左键和中键用于拖动。鼠标右键拖动缩放in/out。
- RectMode: 鼠标左键和中键用于缩放框。鼠标右键拖动缩放in/out。
左键和中键的作用相同的原因在于ViewBox
class 的源代码。
您希望鼠标左键拖动图片,鼠标中键缩放框,鼠标中键缩放框以通过拖动缩放 in/out。我的解决方案可能很激进,但它确实有效。我修改了class,使用源代码作为模型(来源:Pyqtgraph's ViewBox class):
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
class ViewBox(pg.ViewBox):
MyMode = 2
def __init__(self):
pg.ViewBox.__init__(self)
def setMouseMode(self, mode):
## First we change this method to accept our new configuration
if mode not in [ViewBox.PanMode, ViewBox.RectMode, ViewBox.MyMode]:
raise Exception("Mode must be ViewBox.PanMode, ViewBox.RectMode or ViewBox.MyMode")
self.state['mouseMode'] = mode
self.sigStateChanged.emit(self)
def mouseDragEvent(self, ev, axis=None):
ev.accept()
pos = ev.pos()
lastPos = ev.lastPos()
dif = pos - lastPos
dif = dif * -1
mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
mask = mouseEnabled.copy()
if axis is not None:
mask[1-axis] = 0.0
## Here is the main change for it to work
if ev.button() & QtCore.Qt.LeftButton:
if self.state['mouseMode'] == ViewBox.RectMode and axis is None:
if ev.isFinish(): ## This is the final move in the drag; change the view scale now
#print "finish"
self.rbScaleBox.hide()
ax = QtCore.QRectF(QtCore.QPointF(ev.buttonDownPos(ev.button())), QtCore.QPointF(pos))
ax = self.childGroup.mapRectFromParent(ax)
self.showAxRect(ax)
self.axHistoryPointer += 1
self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
else:
## update shape of scale box
self.updateScaleBox(ev.buttonDownPos(), ev.pos())
else:
tr = self.childGroup.transform()
tr = pg.functions.invertQTransform(tr)
tr = tr.map(dif*mask) - tr.map(QtCore.QPointF(0,0))
x = tr.x() if mask[0] == 1 else None
y = tr.y() if mask[1] == 1 else None
self._resetTarget()
if x is not None or y is not None:
self.translateBy(x=x, y=y)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
elif ev.button() & QtCore.Qt.MidButton:
if self.state['mouseMode'] in {ViewBox.RectMode,ViewBox.MyMode} and axis is None:
if ev.isFinish(): ## This is the final move in the drag; change the view scale now
#print "finish"
self.rbScaleBox.hide()
ax = QtCore.QRectF(QtCore.QPointF(ev.buttonDownPos(ev.button())), QtCore.QPointF(pos))
ax = self.childGroup.mapRectFromParent(ax)
self.showAxRect(ax)
self.axHistoryPointer += 1
self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
else:
## update shape of scale box
self.updateScaleBox(ev.buttonDownPos(), ev.pos())
else:
tr = self.childGroup.transform()
tr = pg.functions.invertQTransform(tr)
tr = tr.map(dif*mask) - tr.map(QtCore.QPointF(0,0))
x = tr.x() if mask[0] == 1 else None
y = tr.y() if mask[1] == 1 else None
self._resetTarget()
if x is not None or y is not None:
self.translateBy(x=x, y=y)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
elif ev.button() & QtCore.Qt.RightButton:
if self.state['aspectLocked'] is not False:
mask[0] = 0
dif = ev.screenPos() - ev.lastScreenPos()
dif = np.array([dif.x(), dif.y()])
dif[0] *= -1
s = ((mask * 0.02) + 1) ** dif
tr = self.childGroup.transform()
tr = pg.functions.invertQTransform(tr)
x = s[0] if mouseEnabled[0] == 1 else None
y = s[1] if mouseEnabled[1] == 1 else None
center = QtCore.QPointF(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
self._resetTarget()
self.scaleBy(x=x, y=y, center=center)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
我们继承Pyqtgraph的ViewBoxclass,然后改两个方法:
setMouseMode()
兼容性
mouseDragEvent
3次点击的不同功能
在上面的 class 中,您保持其他两种鼠标模式不变,但添加了一种新模式:MyMode
.
然后不要像这样添加 ViewBox
:
sub2 = win.addLayout()
sub2.addLabel("<b>One-button mouse interaction:</b><br>left-drag zoom to box, wheel to zoom out.")
sub2.nextRow()
v2 = sub2.addViewBox()
v2.setMouseMode(v2.RectMode)
l2 = pg.PlotDataItem(y)
v2.addItem(l2)
你应该这样做:
sub2 = win.addLayout()
sub2.addLabel("<b>One-button mouse interaction:</b><br>left-drag zoom to box, wheel to zoom out.")
sub2.nextRow()
v2 = ViewBox() ## This is our new class
sub2.addItem(v2)
v2.setMouseMode(v2.MyMode) ## Seting the new Mouse Mode
l2 = pg.PlotDataItem(y)
v2.addItem(l2)
我测试了代码并没有发现任何问题,但我不得不承认这个解决方案有点夸张。希望有更简单的方法。
Edit: 例子取自Pyqtgraph的例子 (ViewBox Features) (Here)
在 pyqtgraph examples -> View Box Freatures 中,我们可以通过设置 v2.setMouseMode(v2.RectMode)
但此交互仅在鼠标一键模式下可用。我如何修改交互,以便我可以在标准的三键鼠标模式下使用鼠标右键或鼠标中键 缩放到所选框?
谢谢大家!
pyqtgraph
的ViewBox
class只有两种“鼠标模式”:
- PanMode:鼠标左键和中键用于拖动。鼠标右键拖动缩放in/out。
- RectMode: 鼠标左键和中键用于缩放框。鼠标右键拖动缩放in/out。
左键和中键的作用相同的原因在于ViewBox
class 的源代码。
您希望鼠标左键拖动图片,鼠标中键缩放框,鼠标中键缩放框以通过拖动缩放 in/out。我的解决方案可能很激进,但它确实有效。我修改了class,使用源代码作为模型(来源:Pyqtgraph's ViewBox class):
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
class ViewBox(pg.ViewBox):
MyMode = 2
def __init__(self):
pg.ViewBox.__init__(self)
def setMouseMode(self, mode):
## First we change this method to accept our new configuration
if mode not in [ViewBox.PanMode, ViewBox.RectMode, ViewBox.MyMode]:
raise Exception("Mode must be ViewBox.PanMode, ViewBox.RectMode or ViewBox.MyMode")
self.state['mouseMode'] = mode
self.sigStateChanged.emit(self)
def mouseDragEvent(self, ev, axis=None):
ev.accept()
pos = ev.pos()
lastPos = ev.lastPos()
dif = pos - lastPos
dif = dif * -1
mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
mask = mouseEnabled.copy()
if axis is not None:
mask[1-axis] = 0.0
## Here is the main change for it to work
if ev.button() & QtCore.Qt.LeftButton:
if self.state['mouseMode'] == ViewBox.RectMode and axis is None:
if ev.isFinish(): ## This is the final move in the drag; change the view scale now
#print "finish"
self.rbScaleBox.hide()
ax = QtCore.QRectF(QtCore.QPointF(ev.buttonDownPos(ev.button())), QtCore.QPointF(pos))
ax = self.childGroup.mapRectFromParent(ax)
self.showAxRect(ax)
self.axHistoryPointer += 1
self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
else:
## update shape of scale box
self.updateScaleBox(ev.buttonDownPos(), ev.pos())
else:
tr = self.childGroup.transform()
tr = pg.functions.invertQTransform(tr)
tr = tr.map(dif*mask) - tr.map(QtCore.QPointF(0,0))
x = tr.x() if mask[0] == 1 else None
y = tr.y() if mask[1] == 1 else None
self._resetTarget()
if x is not None or y is not None:
self.translateBy(x=x, y=y)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
elif ev.button() & QtCore.Qt.MidButton:
if self.state['mouseMode'] in {ViewBox.RectMode,ViewBox.MyMode} and axis is None:
if ev.isFinish(): ## This is the final move in the drag; change the view scale now
#print "finish"
self.rbScaleBox.hide()
ax = QtCore.QRectF(QtCore.QPointF(ev.buttonDownPos(ev.button())), QtCore.QPointF(pos))
ax = self.childGroup.mapRectFromParent(ax)
self.showAxRect(ax)
self.axHistoryPointer += 1
self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
else:
## update shape of scale box
self.updateScaleBox(ev.buttonDownPos(), ev.pos())
else:
tr = self.childGroup.transform()
tr = pg.functions.invertQTransform(tr)
tr = tr.map(dif*mask) - tr.map(QtCore.QPointF(0,0))
x = tr.x() if mask[0] == 1 else None
y = tr.y() if mask[1] == 1 else None
self._resetTarget()
if x is not None or y is not None:
self.translateBy(x=x, y=y)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
elif ev.button() & QtCore.Qt.RightButton:
if self.state['aspectLocked'] is not False:
mask[0] = 0
dif = ev.screenPos() - ev.lastScreenPos()
dif = np.array([dif.x(), dif.y()])
dif[0] *= -1
s = ((mask * 0.02) + 1) ** dif
tr = self.childGroup.transform()
tr = pg.functions.invertQTransform(tr)
x = s[0] if mouseEnabled[0] == 1 else None
y = s[1] if mouseEnabled[1] == 1 else None
center = QtCore.QPointF(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
self._resetTarget()
self.scaleBy(x=x, y=y, center=center)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
我们继承Pyqtgraph的ViewBoxclass,然后改两个方法:
setMouseMode()
兼容性mouseDragEvent
3次点击的不同功能
在上面的 class 中,您保持其他两种鼠标模式不变,但添加了一种新模式:MyMode
.
然后不要像这样添加 ViewBox
:
sub2 = win.addLayout()
sub2.addLabel("<b>One-button mouse interaction:</b><br>left-drag zoom to box, wheel to zoom out.")
sub2.nextRow()
v2 = sub2.addViewBox()
v2.setMouseMode(v2.RectMode)
l2 = pg.PlotDataItem(y)
v2.addItem(l2)
你应该这样做:
sub2 = win.addLayout()
sub2.addLabel("<b>One-button mouse interaction:</b><br>left-drag zoom to box, wheel to zoom out.")
sub2.nextRow()
v2 = ViewBox() ## This is our new class
sub2.addItem(v2)
v2.setMouseMode(v2.MyMode) ## Seting the new Mouse Mode
l2 = pg.PlotDataItem(y)
v2.addItem(l2)
我测试了代码并没有发现任何问题,但我不得不承认这个解决方案有点夸张。希望有更简单的方法。
Edit: 例子取自Pyqtgraph的例子 (ViewBox Features) (Here)