Corrected mouse clicking on PlotCurveItem - now uses stroke outline instead of path shape

Added 'width' argument to PlotCurveItem.setClickable()
This commit is contained in:
Luke Campagnola 2013-12-19 09:56:58 -05:00
parent 4e9e75817f
commit a0b7e5a61c
2 changed files with 85 additions and 19 deletions

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
"""
Demonstrates selecting plot curves by mouse click
"""
import initExample ## Add path to library (just for examples; you do not need this)
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
win = pg.plot()
win.setWindowTitle('pyqtgraph example: Plot data selection')
curves = [
pg.PlotCurveItem(y=np.sin(np.linspace(0, 20, 1000)), pen='r', clickable=True),
pg.PlotCurveItem(y=np.sin(np.linspace(1, 21, 1000)), pen='g', clickable=True),
pg.PlotCurveItem(y=np.sin(np.linspace(2, 22, 1000)), pen='b', clickable=True),
]
def plotClicked(curve):
global curves
for i,c in enumerate(curves):
if c is curve:
c.setPen('rgb'[i], width=3)
else:
c.setPen('rgb'[i], width=1)
for c in curves:
win.addItem(c)
c.sigClicked.connect(plotClicked)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()

View File

@ -53,9 +53,6 @@ class PlotCurveItem(GraphicsObject):
""" """
GraphicsObject.__init__(self, kargs.get('parent', None)) GraphicsObject.__init__(self, kargs.get('parent', None))
self.clear() self.clear()
self.path = None
self.fillPath = None
self._boundsCache = [None, None]
## this is disastrous for performance. ## this is disastrous for performance.
#self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache) #self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache)
@ -70,6 +67,7 @@ class PlotCurveItem(GraphicsObject):
'name': None, 'name': None,
'antialias': pg.getConfigOption('antialias'),\ 'antialias': pg.getConfigOption('antialias'),\
'connect': 'all', 'connect': 'all',
'mouseWidth': 8, # width of shape responding to mouse click
} }
self.setClickable(kargs.get('clickable', False)) self.setClickable(kargs.get('clickable', False))
self.setData(*args, **kargs) self.setData(*args, **kargs)
@ -80,9 +78,17 @@ class PlotCurveItem(GraphicsObject):
return ints return ints
return interface in ints return interface in ints
def setClickable(self, s): def setClickable(self, s, width=None):
"""Sets whether the item responds to mouse clicks.""" """Sets whether the item responds to mouse clicks.
The *width* argument specifies the width in pixels orthogonal to the
curve that will respond to a mouse click.
"""
self.clickable = s self.clickable = s
if width is not None:
self.opts['mouseWidth'] = width
self._mouseShape = None
self._boundingRect = None
def getData(self): def getData(self):
@ -148,6 +154,8 @@ class PlotCurveItem(GraphicsObject):
w += pen.widthF()*0.7072 w += pen.widthF()*0.7072
if spen is not None and spen.isCosmetic() and spen.style() != QtCore.Qt.NoPen: if spen is not None and spen.isCosmetic() and spen.style() != QtCore.Qt.NoPen:
w = max(w, spen.widthF()*0.7072) w = max(w, spen.widthF()*0.7072)
if self.clickable:
w = max(w, self.opts['mouseWidth']//2 + 1)
return w return w
def boundingRect(self): def boundingRect(self):
@ -171,6 +179,7 @@ class PlotCurveItem(GraphicsObject):
#px += self._maxSpotWidth * 0.5 #px += self._maxSpotWidth * 0.5
#py += self._maxSpotWidth * 0.5 #py += self._maxSpotWidth * 0.5
self._boundingRect = QtCore.QRectF(xmn-px, ymn-py, (2*px)+xmx-xmn, (2*py)+ymx-ymn) self._boundingRect = QtCore.QRectF(xmn-px, ymn-py, (2*px)+xmx-xmn, (2*py)+ymx-ymn)
return self._boundingRect return self._boundingRect
def viewTransformChanged(self): def viewTransformChanged(self):
@ -328,6 +337,7 @@ class PlotCurveItem(GraphicsObject):
self.path = None self.path = None
self.fillPath = None self.fillPath = None
self._mouseShape = None
#self.xDisp = self.yDisp = None #self.xDisp = self.yDisp = None
if 'name' in kargs: if 'name' in kargs:
@ -376,12 +386,14 @@ class PlotCurveItem(GraphicsObject):
return path return path
def shape(self): def getPath(self):
if self.path is None: if self.path is None:
try: x,y = self.getData()
self.path = self.generatePath(*self.getData()) if x is None or len(x) == 0 or y is None or len(y) == 0:
except:
return QtGui.QPainterPath() return QtGui.QPainterPath()
self.path = self.generatePath(*self.getData())
self.fillPath = None
self._mouseShape = None
return self.path return self.path
@pg.debug.warnOnException ## raising an exception here causes crash @pg.debug.warnOnException ## raising an exception here causes crash
@ -396,14 +408,8 @@ class PlotCurveItem(GraphicsObject):
x = None x = None
y = None y = None
if self.path is None: path = self.getPath()
x,y = self.getData()
if x is None or len(x) == 0 or y is None or len(y) == 0:
return
self.path = self.generatePath(x,y)
self.fillPath = None
path = self.path
profiler('generate path') profiler('generate path')
if self._exportOpts is not False: if self._exportOpts is not False:
@ -522,13 +528,36 @@ class PlotCurveItem(GraphicsObject):
self.xDisp = None ## display values (after log / fft) self.xDisp = None ## display values (after log / fft)
self.yDisp = None self.yDisp = None
self.path = None self.path = None
self.fillPath = None
self._mouseShape = None
self._mouseBounds = None
self._boundsCache = [None, None]
#del self.xData, self.yData, self.xDisp, self.yDisp, self.path #del self.xData, self.yData, self.xDisp, self.yDisp, self.path
def mouseShape(self):
"""
Return a QPainterPath representing the clickable shape of the curve
"""
if self._mouseShape is None:
view = self.getViewBox()
if view is None:
return QtGui.QPainterPath()
stroker = QtGui.QPainterPathStroker()
path = self.getPath()
path = self.mapToItem(view, path)
stroker.setWidth(self.opts['mouseWidth'])
mousePath = stroker.createStroke(path)
self._mouseShape = self.mapFromItem(view, mousePath)
return self._mouseShape
def mouseClickEvent(self, ev): def mouseClickEvent(self, ev):
if not self.clickable or ev.button() != QtCore.Qt.LeftButton: if not self.clickable or ev.button() != QtCore.Qt.LeftButton:
return return
ev.accept() if self.mouseShape().contains(ev.pos()):
self.sigClicked.emit(self) ev.accept()
self.sigClicked.emit(self)
class ROIPlotItem(PlotCurveItem): class ROIPlotItem(PlotCurveItem):