Fix panning the x axis too fast, the right click zoom not working, and the mouse mode not propagating properly

This commit is contained in:
herodotus77 2021-10-11 17:33:45 -07:00
parent e06a4657ad
commit 415aaba36f
3 changed files with 32 additions and 15 deletions

View File

@ -135,10 +135,6 @@ class PlotItem(GraphicsWidget):
self.vb = viewBox self.vb = viewBox
self.vb.sigStateChanged.connect(self.viewStateChanged) self.vb.sigStateChanged.connect(self.viewStateChanged)
# A set containing view boxes which are stacked underneath the top level view. These views will be needed
# in order to support multiple axes on the same plot. This set will remain empty if the plot has only one set of axes
self.stackedViews = weakref.WeakSet()
# Enable or disable plotItem menu # Enable or disable plotItem menu
self.setMenuEnabled(enableMenu, None) self.setMenuEnabled(enableMenu, None)
@ -147,7 +143,6 @@ class PlotItem(GraphicsWidget):
self.vb.sigRangeChanged.connect(self.sigRangeChanged) self.vb.sigRangeChanged.connect(self.sigRangeChanged)
self.vb.sigXRangeChanged.connect(self.sigXRangeChanged) self.vb.sigXRangeChanged.connect(self.sigXRangeChanged)
self.vb.sigYRangeChanged.connect(self.sigYRangeChanged) self.vb.sigYRangeChanged.connect(self.sigYRangeChanged)
self.vb.sigResized.connect(self.updateStackedViews)
self.layout.addItem(self.vb, 2, 1) self.layout.addItem(self.vb, 2, 1)
self.alpha = 1.0 self.alpha = 1.0
@ -365,6 +360,7 @@ class PlotItem(GraphicsWidget):
view = ViewBox() view = ViewBox()
view.setXLink(self) # Link this view to the shared x-axis of this plot item TODO: Allow for multiple x axes view.setXLink(self) # Link this view to the shared x-axis of this plot item TODO: Allow for multiple x axes
view.setMouseMode(self.vb.state['mouseMode']) # Ensure that mouse behavior is consistent between stacked views view.setMouseMode(self.vb.state['mouseMode']) # Ensure that mouse behavior is consistent between stacked views
view.isTopLevel = False
axis.linkToView(view) axis.linkToView(view)
if plotDataItem is not None: if plotDataItem is not None:
view.addItem(plotDataItem) view.addItem(plotDataItem)
@ -375,7 +371,7 @@ class PlotItem(GraphicsWidget):
# Rebuilding the layout of the plot item will put the new axis in the correct place # Rebuilding the layout of the plot item will put the new axis in the correct place
self.rebuildLayout() self.rebuildLayout()
self.updateStackedViews() self.vb.updateStackedViews()
def addStackedView(self, view): def addStackedView(self, view):
""" """
@ -388,20 +384,12 @@ class PlotItem(GraphicsWidget):
The view to be added. Events handled by the top level view box will be passed through to this one as well The view to be added. Events handled by the top level view box will be passed through to this one as well
""" """
self.stackedViews.add(view) self.vb.stackedViews.add(view)
# These signals will be emitted by the top level view when it handles these events # These signals will be emitted by the top level view when it handles these events
self.vb.sigMouseDragged.connect(view.mouseDragEvent) self.vb.sigMouseDragged.connect(view.mouseDragEvent)
self.vb.sigMouseWheelZoomed.connect(view.wheelEvent) self.vb.sigMouseWheelZoomed.connect(view.wheelEvent)
self.vb.sigHistoryChanged.connect(view.scaleHistory) self.vb.sigHistoryChanged.connect(view.scaleHistory)
def updateStackedViews(self):
"""
Callback for resizing stacked views when the geometry of their top level view changes
"""
for view in self.stackedViews:
view.setGeometry(self.vb.sceneBoundingRect())
view.linkedViewChanged(self.vb, view.XAxis)
def linkDataToAxis(self, plotDataItem, axisName): def linkDataToAxis(self, plotDataItem, axisName):
""" """
Links the input PlotDataItem to the axis with the given name. Raises an exception if that axis does not exist. Links the input PlotDataItem to the axis with the given name. Raises an exception if that axis does not exist.

View File

@ -191,6 +191,12 @@ class ViewBox(GraphicsWidget):
self.childGroup = ChildGroup(self) self.childGroup = ChildGroup(self)
self.childGroup.itemsChangedListeners.append(self) self.childGroup.itemsChangedListeners.append(self)
# A set containing view boxes which are stacked underneath the top level view. These views will be needed
# in order to support multiple axes on the same plot. This set will remain empty if the plot has only one set of axes
self.stackedViews = weakref.WeakSet()
self.isTopLevel = True # True if this view box is the top of any stacked view, false otherwise
self.sigResized.connect(self.updateStackedViews)
self.background = QtGui.QGraphicsRectItem(self.rect()) self.background = QtGui.QGraphicsRectItem(self.rect())
self.background.setParentItem(self) self.background.setParentItem(self)
self.background.setZValue(-1e6) self.background.setZValue(-1e6)
@ -1050,6 +1056,14 @@ class ViewBox(GraphicsWidget):
finally: finally:
view.blockLink(False) view.blockLink(False)
def updateStackedViews(self):
"""
Callback for resizing stacked views when the geometry of their top level view changes
"""
for view in self.stackedViews:
view.setGeometry(self.sceneBoundingRect())
view.linkedViewChanged(self, view.XAxis)
def screenGeometry(self): def screenGeometry(self):
"""return the screen geometry of the viewbox""" """return the screen geometry of the viewbox"""
v = self.getViewWidget() v = self.getViewWidget()
@ -1281,6 +1295,10 @@ class ViewBox(GraphicsWidget):
self._resetTarget() self._resetTarget()
if x is not None or y is not None: if x is not None or y is not None:
if not self.isTopLevel:
# Prevent each view in the stack from scrolling the same x axis at the same time
# TODO: Something better in the case of multiple x axes
x = None
self.translateBy(x=x, y=y) self.translateBy(x=x, y=y)
self.sigRangeChangedManually.emit(self.state['mouseEnabled']) self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
if axis is None: if axis is None:
@ -1302,10 +1320,15 @@ class ViewBox(GraphicsWidget):
x = s[0] if mouseEnabled[0] == 1 else None x = s[0] if mouseEnabled[0] == 1 else None
y = s[1] if mouseEnabled[1] == 1 else None y = s[1] if mouseEnabled[1] == 1 else None
if not self.isTopLevel: # TODO: Like above, also something better than this
x = None
center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.MouseButton.RightButton))) center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.MouseButton.RightButton)))
self._resetTarget() self._resetTarget()
self.scaleBy(x=x, y=y, center=center) self.scaleBy(x=x, y=y, center=center)
self.sigRangeChangedManually.emit(self.state['mouseEnabled']) self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
if axis is None:
self.sigMouseDragged.emit(ev, axis)
def keyPressEvent(self, ev): def keyPressEvent(self, ev):
""" """

View File

@ -219,9 +219,15 @@ class ViewBoxMenu(QtGui.QMenu):
def set3ButtonMode(self): def set3ButtonMode(self):
self.view().setLeftButtonAction('pan') self.view().setLeftButtonAction('pan')
if len(self.view().stackedViews) > 0:
for view in self.view().stackedViews:
view.setLeftButtonAction('pan')
def set1ButtonMode(self): def set1ButtonMode(self):
self.view().setLeftButtonAction('rect') self.view().setLeftButtonAction('rect')
if len(self.view().stackedViews) > 0:
for view in self.view().stackedViews:
view.setLeftButtonAction('rect')
def setViewList(self, views): def setViewList(self, views):
names = [''] names = ['']