- Added workaround for Qt bug: https://bugreports.qt-project.org/browse/QTBUG-18616. (GraphicsItem.setParent needs to check for scene change first)
This _could_ cause other problems, but they will certainly be fewer than the existing problems. - Fixed bugs with ViewBox linking to views which are subsequently deleted
This commit is contained in:
parent
cc94e15d1e
commit
6932c34126
@ -26,19 +26,19 @@ win.addLabel("Linked Views", colspan=2)
|
||||
win.nextRow()
|
||||
|
||||
p1 = win.addPlot(x=x, y=y, name="Plot1", title="Plot1")
|
||||
p2 = win.addPlot(x=x, y=y, name="Plot2", title="Plot2 - Y linked with Plot1")
|
||||
p2 = win.addPlot(x=x, y=y, name="Plot2", title="Plot2: Y linked with Plot1")
|
||||
p2.setLabel('bottom', "Label to test offset")
|
||||
p2.setYLink(p1)
|
||||
p2.setYLink('Plot1') ## test linking by name
|
||||
|
||||
win.nextRow()
|
||||
|
||||
p3 = win.addPlot(x=x, y=y, name="Plot3", title="Plot3 - X linked with Plot1")
|
||||
p4 = win.addPlot(x=x, y=y, name="Plot4", title="Plot4 - X and Y linked with Plot1")
|
||||
## create plots 3 and 4 out of order
|
||||
p4 = win.addPlot(x=x, y=y, name="Plot4", title="Plot4: X -> Plot3 (deferred), Y -> Plot1", row=2, col=1)
|
||||
p4.setXLink('Plot3') ## Plot3 has not been created yet, but this should still work anyway.
|
||||
p4.setYLink(p1)
|
||||
p3 = win.addPlot(x=x, y=y, name="Plot3", title="Plot3: X linked with Plot1", row=2, col=0)
|
||||
p3.setXLink(p1)
|
||||
p3.setLabel('left', "Label to test offset")
|
||||
#QtGui.QApplication.processEvents()
|
||||
p3.setXLink(p1)
|
||||
p4.setXLink(p1)
|
||||
p4.setYLink(p1)
|
||||
|
||||
|
||||
## Start Qt event loop unless running in interactive mode or using pyside.
|
||||
|
@ -510,7 +510,7 @@ class NodeGraphicsItem(GraphicsObject):
|
||||
if change == self.ItemPositionHasChanged:
|
||||
for k, t in self.terminals.items():
|
||||
t[1].nodeMoved()
|
||||
return QtGui.QGraphicsItem.itemChange(self, change, val)
|
||||
return GraphicsObject.itemChange(self, change, val)
|
||||
|
||||
|
||||
#def contextMenuEvent(self, ev):
|
||||
|
@ -342,26 +342,47 @@ class GraphicsItem(object):
|
||||
|
||||
## check for this item's current viewbox or view widget
|
||||
view = self.getViewBox()
|
||||
if view is None:
|
||||
#print " no view"
|
||||
return
|
||||
#if view is None:
|
||||
##print " no view"
|
||||
#return
|
||||
|
||||
if self._connectedView is not None and view is self._connectedView():
|
||||
oldView = None
|
||||
if self._connectedView is not None:
|
||||
oldView = self._connectedView()
|
||||
|
||||
if view is oldView:
|
||||
#print " already have view", view
|
||||
return
|
||||
|
||||
## disconnect from previous view
|
||||
if self._connectedView is not None:
|
||||
cv = self._connectedView()
|
||||
if cv is not None:
|
||||
#print "disconnect:", self
|
||||
cv.sigRangeChanged.disconnect(self.viewRangeChanged)
|
||||
if oldView is not None:
|
||||
#print "disconnect:", self, oldView
|
||||
oldView.sigRangeChanged.disconnect(self.viewRangeChanged)
|
||||
self._connectedView = None
|
||||
|
||||
## connect to new view
|
||||
#print "connect:", self
|
||||
view.sigRangeChanged.connect(self.viewRangeChanged)
|
||||
self._connectedView = weakref.ref(view)
|
||||
self.viewRangeChanged()
|
||||
if view is not None:
|
||||
#print "connect:", self, view
|
||||
view.sigRangeChanged.connect(self.viewRangeChanged)
|
||||
self._connectedView = weakref.ref(view)
|
||||
self.viewRangeChanged()
|
||||
|
||||
## inform children that their view might have changed
|
||||
self._replaceView(oldView)
|
||||
|
||||
|
||||
def _replaceView(self, oldView, item=None):
|
||||
if item is None:
|
||||
item = self
|
||||
for child in item.childItems():
|
||||
if isinstance(child, GraphicsItem):
|
||||
if child.getViewBox() is oldView:
|
||||
child._updateView()
|
||||
#self._replaceView(oldView, child)
|
||||
else:
|
||||
self._replaceView(oldView, child)
|
||||
|
||||
|
||||
|
||||
def viewRangeChanged(self):
|
||||
"""
|
||||
|
@ -22,7 +22,8 @@ class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject):
|
||||
|
||||
def setParentItem(self, parent):
|
||||
## Workaround for Qt bug: https://bugreports.qt-project.org/browse/QTBUG-18616
|
||||
pscene = parent.scene()
|
||||
if pscene is not None and self.scene() is not pscene:
|
||||
pscene.addItem(self)
|
||||
if parent is not None:
|
||||
pscene = parent.scene()
|
||||
if pscene is not None and self.scene() is not pscene:
|
||||
pscene.addItem(self)
|
||||
return QtGui.QGraphicsObject.setParentItem(self, parent)
|
||||
|
@ -55,7 +55,8 @@ class GraphicsWidget(GraphicsItem, QtGui.QGraphicsWidget):
|
||||
|
||||
def setParentItem(self, parent):
|
||||
## Workaround for Qt bug: https://bugreports.qt-project.org/browse/QTBUG-18616
|
||||
pscene = parent.scene()
|
||||
if pscene is not None and self.scene() is not pscene:
|
||||
pscene.addItem(self)
|
||||
return QtGui.QGraphicsWidget.setParentItem(self, parent)
|
||||
if parent is not None:
|
||||
pscene = parent.scene()
|
||||
if pscene is not None and self.scene() is not pscene:
|
||||
pscene.addItem(self)
|
||||
return QtGui.QGraphicsObject.setParentItem(self, parent)
|
||||
|
@ -62,7 +62,6 @@ class ViewBox(GraphicsWidget):
|
||||
NamedViews = weakref.WeakValueDictionary() # name: ViewBox
|
||||
AllViews = weakref.WeakKeyDictionary() # ViewBox: None
|
||||
|
||||
|
||||
def __init__(self, parent=None, border=None, lockAspect=False, enableMouse=True, invertY=False, name=None):
|
||||
"""
|
||||
============= =============================================================
|
||||
@ -99,7 +98,8 @@ class ViewBox(GraphicsWidget):
|
||||
## otherwise float gives the fraction of data that is visible
|
||||
'autoPan': [False, False], ## whether to only pan (do not change scaling) when auto-range is enabled
|
||||
'autoVisibleOnly': [False, False], ## whether to auto-range only to the visible portion of a plot
|
||||
'linkedViews': [None, None],
|
||||
'linkedViews': [None, None], ## may be None, "viewName", or weakref.ref(view)
|
||||
## a name string indicates that the view *should* link to another, but no view with that name exists yet.
|
||||
|
||||
'mouseEnabled': [enableMouse, enableMouse],
|
||||
'mouseMode': ViewBox.PanMode if pyqtgraph.getConfigOption('leftButtonPan') else ViewBox.RectMode,
|
||||
@ -160,6 +160,8 @@ class ViewBox(GraphicsWidget):
|
||||
if name is not None:
|
||||
ViewBox.NamedViews[name] = self
|
||||
ViewBox.updateAllViewLists()
|
||||
self.destroyed.connect(lambda: ViewBox.forgetView(id(self), self.name))
|
||||
#self.destroyed.connect(self.unregister)
|
||||
|
||||
def unregister(self):
|
||||
"""
|
||||
@ -177,14 +179,26 @@ class ViewBox(GraphicsWidget):
|
||||
|
||||
|
||||
def getState(self, copy=True):
|
||||
"""Return the current state of the ViewBox.
|
||||
Linked views are always converted to view names in the returned state."""
|
||||
state = self.state.copy()
|
||||
state['linkedViews'] = [(None if v is None else v.name) for v in state['linkedViews']]
|
||||
views = []
|
||||
for v in state['linkedViews']:
|
||||
if isinstance(v, weakref.ref):
|
||||
v = v()
|
||||
if v is None or isinstance(v, basestring):
|
||||
views.append(v)
|
||||
else:
|
||||
views.append(v.name)
|
||||
state['linkedViews'] = views
|
||||
if copy:
|
||||
return deepcopy(self.state)
|
||||
return deepcopy(state)
|
||||
else:
|
||||
return self.state
|
||||
return state
|
||||
|
||||
def setState(self, state):
|
||||
"""Restore the state of this ViewBox.
|
||||
(see also getState)"""
|
||||
state = state.copy()
|
||||
self.setXLink(state['linkedViews'][0])
|
||||
self.setYLink(state['linkedViews'][1])
|
||||
@ -368,7 +382,7 @@ class ViewBox(GraphicsWidget):
|
||||
self.updateMatrix(changed)
|
||||
|
||||
for ax, range in changes.items():
|
||||
link = self.state['linkedViews'][ax]
|
||||
link = self.linkedView(ax)
|
||||
if link is not None:
|
||||
link.linkedViewChanged(self, ax)
|
||||
|
||||
@ -572,7 +586,7 @@ class ViewBox(GraphicsWidget):
|
||||
if view == '':
|
||||
view = None
|
||||
else:
|
||||
view = ViewBox.NamedViews[view]
|
||||
view = ViewBox.NamedViews.get(view, view) ## convert view name to ViewBox if possible
|
||||
|
||||
if hasattr(view, 'implements') and view.implements('ViewBoxWrapper'):
|
||||
view = view.getViewBox()
|
||||
@ -586,13 +600,19 @@ class ViewBox(GraphicsWidget):
|
||||
slot = self.linkedYChanged
|
||||
|
||||
|
||||
oldLink = self.state['linkedViews'][axis]
|
||||
oldLink = self.linkedView(axis)
|
||||
if oldLink is not None:
|
||||
getattr(oldLink, signal).disconnect(slot)
|
||||
try:
|
||||
getattr(oldLink, signal).disconnect(slot)
|
||||
except TypeError:
|
||||
## This can occur if the view has been deleted already
|
||||
pass
|
||||
|
||||
self.state['linkedViews'][axis] = view
|
||||
|
||||
if view is not None:
|
||||
if view is None or isinstance(view, basestring):
|
||||
self.state['linkedViews'][axis] = view
|
||||
else:
|
||||
self.state['linkedViews'][axis] = weakref.ref(view)
|
||||
getattr(view, signal).connect(slot)
|
||||
if view.autoRangeEnabled()[axis] is not False:
|
||||
self.enableAutoRange(axis, False)
|
||||
@ -608,14 +628,22 @@ class ViewBox(GraphicsWidget):
|
||||
|
||||
def linkedXChanged(self):
|
||||
## called when x range of linked view has changed
|
||||
view = self.state['linkedViews'][0]
|
||||
view = self.linkedView(0)
|
||||
self.linkedViewChanged(view, ViewBox.XAxis)
|
||||
|
||||
def linkedYChanged(self):
|
||||
## called when y range of linked view has changed
|
||||
view = self.state['linkedViews'][1]
|
||||
view = self.linkedView(1)
|
||||
self.linkedViewChanged(view, ViewBox.YAxis)
|
||||
|
||||
def linkedView(self, ax):
|
||||
## Return the linked view for axis *ax*.
|
||||
## this method _always_ returns either a ViewBox or None.
|
||||
v = self.state['linkedViews'][ax]
|
||||
if v is None or isinstance(v, basestring):
|
||||
return None
|
||||
else:
|
||||
return v() ## dereference weakref pointer. If the reference is dead, this returns None
|
||||
|
||||
def linkedViewChanged(self, view, axis):
|
||||
if self.linksBlocked or view is None:
|
||||
@ -623,10 +651,9 @@ class ViewBox(GraphicsWidget):
|
||||
|
||||
vr = view.viewRect()
|
||||
vg = view.screenGeometry()
|
||||
if vg is None:
|
||||
return
|
||||
|
||||
sg = self.screenGeometry()
|
||||
if vg is None or sg is None:
|
||||
return
|
||||
|
||||
view.blockLink(True)
|
||||
try:
|
||||
@ -683,8 +710,11 @@ class ViewBox(GraphicsWidget):
|
||||
By default, the positive y-axis points upward on the screen. Use invertY(True) to reverse the y-axis.
|
||||
"""
|
||||
self.state['yInverted'] = b
|
||||
self.updateMatrix()
|
||||
self.updateMatrix(changed=(False, True))
|
||||
self.sigStateChanged.emit(self)
|
||||
|
||||
def yInverted(self):
|
||||
return self.state['yInverted']
|
||||
|
||||
def setAspectLocked(self, lock=True, ratio=1):
|
||||
"""
|
||||
@ -1030,6 +1060,7 @@ class ViewBox(GraphicsWidget):
|
||||
def updateMatrix(self, changed=None):
|
||||
if changed is None:
|
||||
changed = [False, False]
|
||||
changed = list(changed)
|
||||
#print "udpateMatrix:"
|
||||
#print " range:", self.range
|
||||
tr = self.targetRect()
|
||||
@ -1124,20 +1155,40 @@ class ViewBox(GraphicsWidget):
|
||||
|
||||
## make a sorted list of all named views
|
||||
nv = list(ViewBox.NamedViews.values())
|
||||
|
||||
#print "new view list:", nv
|
||||
sortList(nv, cmpViews) ## see pyqtgraph.python2_3.sortList
|
||||
|
||||
if self in nv:
|
||||
nv.remove(self)
|
||||
names = [v.name for v in nv]
|
||||
self.menu.setViewList(names)
|
||||
|
||||
self.menu.setViewList(nv)
|
||||
|
||||
for ax in [0,1]:
|
||||
link = self.state['linkedViews'][ax]
|
||||
if isinstance(link, basestring): ## axis has not been linked yet; see if it's possible now
|
||||
for v in nv:
|
||||
if link == v.name:
|
||||
self.linkView(ax, v)
|
||||
#print "New view list:", nv
|
||||
#print "linked views:", self.state['linkedViews']
|
||||
|
||||
@staticmethod
|
||||
def updateAllViewLists():
|
||||
#print "Update:", ViewBox.AllViews.keys()
|
||||
#print "Update:", ViewBox.NamedViews.keys()
|
||||
for v in ViewBox.AllViews:
|
||||
v.updateViewLists()
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def forgetView(vid, name):
|
||||
|
||||
## Called with ID and name of view (the view itself is no longer available)
|
||||
for v in ViewBox.AllViews.iterkeys():
|
||||
if id(v) == vid:
|
||||
ViewBox.AllViews.pop(v)
|
||||
break
|
||||
ViewBox.NamedViews.pop(name, None)
|
||||
ViewBox.updateAllViewLists()
|
||||
|
||||
from .ViewBoxMenu import ViewBoxMenu
|
||||
|
@ -1,13 +1,15 @@
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
from pyqtgraph.WidgetGroup import WidgetGroup
|
||||
from .axisCtrlTemplate import Ui_Form as AxisCtrlTemplate
|
||||
import weakref
|
||||
|
||||
class ViewBoxMenu(QtGui.QMenu):
|
||||
def __init__(self, view):
|
||||
QtGui.QMenu.__init__(self)
|
||||
|
||||
self.view = view
|
||||
self.view = weakref.ref(view) ## keep weakref to view to avoid circular reference (don't know why, but this prevents the ViewBox from being collected)
|
||||
self.valid = False ## tells us whether the ui needs to be updated
|
||||
self.viewMap = weakref.WeakValueDictionary() ## weakrefs to all views listed in the link combos
|
||||
|
||||
self.setTitle("ViewBox options")
|
||||
self.viewAll = QtGui.QAction("View All", self)
|
||||
@ -47,7 +49,9 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
|
||||
for sig, fn in connects:
|
||||
sig.connect(getattr(self, axis.lower()+fn))
|
||||
|
||||
|
||||
self.ctrl[0].invertCheck.hide() ## no invert for x-axis
|
||||
self.ctrl[1].invertCheck.toggled.connect(self.yInvertToggled)
|
||||
## exporting is handled by GraphicsScene now
|
||||
#self.export = QtGui.QMenu("Export")
|
||||
#self.setExportMethods(view.exportMethods)
|
||||
@ -64,7 +68,7 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
self.mouseModes = [pan, zoom]
|
||||
self.addMenu(self.leftMenu)
|
||||
|
||||
self.view.sigStateChanged.connect(self.viewStateChanged)
|
||||
self.view().sigStateChanged.connect(self.viewStateChanged)
|
||||
|
||||
self.updateState()
|
||||
|
||||
@ -97,14 +101,15 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
self.updateState()
|
||||
|
||||
def updateState(self):
|
||||
state = self.view.getState(copy=False)
|
||||
## Something about the viewbox has changed; update the menu GUI
|
||||
|
||||
state = self.view().getState(copy=False)
|
||||
if state['mouseMode'] == ViewBox.PanMode:
|
||||
self.mouseModes[0].setChecked(True)
|
||||
else:
|
||||
self.mouseModes[1].setChecked(True)
|
||||
|
||||
|
||||
for i in [0,1]:
|
||||
for i in [0,1]: # x, y
|
||||
tr = state['targetRange'][i]
|
||||
self.ctrl[i].minText.setText("%0.5g" % tr[0])
|
||||
self.ctrl[i].maxText.setText("%0.5g" % tr[1])
|
||||
@ -116,17 +121,15 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
self.ctrl[i].manualRadio.setChecked(True)
|
||||
self.ctrl[i].mouseCheck.setChecked(state['mouseEnabled'][i])
|
||||
|
||||
## Update combo to show currently linked view
|
||||
c = self.ctrl[i].linkCombo
|
||||
c.blockSignals(True)
|
||||
try:
|
||||
view = state['linkedViews'][i]
|
||||
view = state['linkedViews'][i] ## will always be string or None
|
||||
if view is None:
|
||||
view = ''
|
||||
|
||||
if isinstance(view, basestring):
|
||||
ind = c.findText(view)
|
||||
else:
|
||||
ind = c.findText(view.name)
|
||||
ind = c.findText(view)
|
||||
|
||||
if ind == -1:
|
||||
ind = 0
|
||||
@ -136,76 +139,79 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
|
||||
self.ctrl[i].autoPanCheck.setChecked(state['autoPan'][i])
|
||||
self.ctrl[i].visibleOnlyCheck.setChecked(state['autoVisibleOnly'][i])
|
||||
|
||||
|
||||
self.ctrl[1].invertCheck.setChecked(state['yInverted'])
|
||||
self.valid = True
|
||||
|
||||
|
||||
def autoRange(self):
|
||||
self.view.autoRange() ## don't let signal call this directly--it'll add an unwanted argument
|
||||
self.view().autoRange() ## don't let signal call this directly--it'll add an unwanted argument
|
||||
|
||||
def xMouseToggled(self, b):
|
||||
self.view.setMouseEnabled(x=b)
|
||||
self.view().setMouseEnabled(x=b)
|
||||
|
||||
def xManualClicked(self):
|
||||
self.view.enableAutoRange(ViewBox.XAxis, False)
|
||||
self.view().enableAutoRange(ViewBox.XAxis, False)
|
||||
|
||||
def xMinTextChanged(self):
|
||||
self.ctrl[0].manualRadio.setChecked(True)
|
||||
self.view.setXRange(float(self.ctrl[0].minText.text()), float(self.ctrl[0].maxText.text()), padding=0)
|
||||
self.view().setXRange(float(self.ctrl[0].minText.text()), float(self.ctrl[0].maxText.text()), padding=0)
|
||||
|
||||
def xMaxTextChanged(self):
|
||||
self.ctrl[0].manualRadio.setChecked(True)
|
||||
self.view.setXRange(float(self.ctrl[0].minText.text()), float(self.ctrl[0].maxText.text()), padding=0)
|
||||
self.view().setXRange(float(self.ctrl[0].minText.text()), float(self.ctrl[0].maxText.text()), padding=0)
|
||||
|
||||
def xAutoClicked(self):
|
||||
val = self.ctrl[0].autoPercentSpin.value() * 0.01
|
||||
self.view.enableAutoRange(ViewBox.XAxis, val)
|
||||
self.view().enableAutoRange(ViewBox.XAxis, val)
|
||||
|
||||
def xAutoSpinChanged(self, val):
|
||||
self.ctrl[0].autoRadio.setChecked(True)
|
||||
self.view.enableAutoRange(ViewBox.XAxis, val*0.01)
|
||||
self.view().enableAutoRange(ViewBox.XAxis, val*0.01)
|
||||
|
||||
def xLinkComboChanged(self, ind):
|
||||
self.view.setXLink(str(self.ctrl[0].linkCombo.currentText()))
|
||||
self.view().setXLink(str(self.ctrl[0].linkCombo.currentText()))
|
||||
|
||||
def xAutoPanToggled(self, b):
|
||||
self.view.setAutoPan(x=b)
|
||||
self.view().setAutoPan(x=b)
|
||||
|
||||
def xVisibleOnlyToggled(self, b):
|
||||
self.view.setAutoVisible(x=b)
|
||||
self.view().setAutoVisible(x=b)
|
||||
|
||||
|
||||
def yMouseToggled(self, b):
|
||||
self.view.setMouseEnabled(y=b)
|
||||
self.view().setMouseEnabled(y=b)
|
||||
|
||||
def yManualClicked(self):
|
||||
self.view.enableAutoRange(ViewBox.YAxis, False)
|
||||
self.view().enableAutoRange(ViewBox.YAxis, False)
|
||||
|
||||
def yMinTextChanged(self):
|
||||
self.ctrl[1].manualRadio.setChecked(True)
|
||||
self.view.setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1].maxText.text()), padding=0)
|
||||
self.view().setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1].maxText.text()), padding=0)
|
||||
|
||||
def yMaxTextChanged(self):
|
||||
self.ctrl[1].manualRadio.setChecked(True)
|
||||
self.view.setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1].maxText.text()), padding=0)
|
||||
self.view().setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1].maxText.text()), padding=0)
|
||||
|
||||
def yAutoClicked(self):
|
||||
val = self.ctrl[1].autoPercentSpin.value() * 0.01
|
||||
self.view.enableAutoRange(ViewBox.YAxis, val)
|
||||
self.view().enableAutoRange(ViewBox.YAxis, val)
|
||||
|
||||
def yAutoSpinChanged(self, val):
|
||||
self.ctrl[1].autoRadio.setChecked(True)
|
||||
self.view.enableAutoRange(ViewBox.YAxis, val*0.01)
|
||||
self.view().enableAutoRange(ViewBox.YAxis, val*0.01)
|
||||
|
||||
def yLinkComboChanged(self, ind):
|
||||
self.view.setYLink(str(self.ctrl[1].linkCombo.currentText()))
|
||||
self.view().setYLink(str(self.ctrl[1].linkCombo.currentText()))
|
||||
|
||||
def yAutoPanToggled(self, b):
|
||||
self.view.setAutoPan(y=b)
|
||||
self.view().setAutoPan(y=b)
|
||||
|
||||
def yVisibleOnlyToggled(self, b):
|
||||
self.view.setAutoVisible(y=b)
|
||||
self.view().setAutoVisible(y=b)
|
||||
|
||||
def yInvertToggled(self, b):
|
||||
self.view().invertY(b)
|
||||
|
||||
|
||||
def exportMethod(self):
|
||||
@ -214,14 +220,24 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
|
||||
|
||||
def set3ButtonMode(self):
|
||||
self.view.setLeftButtonAction('pan')
|
||||
self.view().setLeftButtonAction('pan')
|
||||
|
||||
def set1ButtonMode(self):
|
||||
self.view.setLeftButtonAction('rect')
|
||||
self.view().setLeftButtonAction('rect')
|
||||
|
||||
|
||||
def setViewList(self, views):
|
||||
views = [''] + views
|
||||
names = ['']
|
||||
self.viewMap.clear()
|
||||
|
||||
## generate list of views to show in the link combo
|
||||
for v in views:
|
||||
name = v.name
|
||||
if name is None: ## unnamed views do not show up in the view list (although they are linkable)
|
||||
continue
|
||||
names.append(name)
|
||||
self.viewMap[name] = v
|
||||
|
||||
for i in [0,1]:
|
||||
c = self.ctrl[i].linkCombo
|
||||
current = asUnicode(c.currentText())
|
||||
@ -229,9 +245,9 @@ class ViewBoxMenu(QtGui.QMenu):
|
||||
changed = True
|
||||
try:
|
||||
c.clear()
|
||||
for v in views:
|
||||
c.addItem(v)
|
||||
if v == current:
|
||||
for name in names:
|
||||
c.addItem(name)
|
||||
if name == current:
|
||||
changed = False
|
||||
c.setCurrentIndex(c.count()-1)
|
||||
finally:
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'axisCtrlTemplate.ui'
|
||||
#
|
||||
# Created: Wed Mar 28 23:29:45 2012
|
||||
# by: PyQt4 UI code generator 4.8.3
|
||||
# Created: Fri Jun 1 17:38:02 2012
|
||||
# by: PyQt4 UI code generator 4.9.1
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@ -17,12 +17,31 @@ except AttributeError:
|
||||
class Ui_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName(_fromUtf8("Form"))
|
||||
Form.resize(186, 137)
|
||||
Form.resize(186, 154)
|
||||
Form.setMaximumSize(QtCore.QSize(200, 16777215))
|
||||
self.gridLayout = QtGui.QGridLayout(Form)
|
||||
self.gridLayout.setMargin(0)
|
||||
self.gridLayout.setSpacing(0)
|
||||
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
|
||||
self.label = QtGui.QLabel(Form)
|
||||
self.label.setObjectName(_fromUtf8("label"))
|
||||
self.gridLayout.addWidget(self.label, 7, 0, 1, 2)
|
||||
self.linkCombo = QtGui.QComboBox(Form)
|
||||
self.linkCombo.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
self.linkCombo.setObjectName(_fromUtf8("linkCombo"))
|
||||
self.gridLayout.addWidget(self.linkCombo, 7, 2, 1, 2)
|
||||
self.autoPercentSpin = QtGui.QSpinBox(Form)
|
||||
self.autoPercentSpin.setEnabled(True)
|
||||
self.autoPercentSpin.setMinimum(1)
|
||||
self.autoPercentSpin.setMaximum(100)
|
||||
self.autoPercentSpin.setSingleStep(1)
|
||||
self.autoPercentSpin.setProperty("value", 100)
|
||||
self.autoPercentSpin.setObjectName(_fromUtf8("autoPercentSpin"))
|
||||
self.gridLayout.addWidget(self.autoPercentSpin, 2, 2, 1, 2)
|
||||
self.autoRadio = QtGui.QRadioButton(Form)
|
||||
self.autoRadio.setChecked(True)
|
||||
self.autoRadio.setObjectName(_fromUtf8("autoRadio"))
|
||||
self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 2)
|
||||
self.manualRadio = QtGui.QRadioButton(Form)
|
||||
self.manualRadio.setObjectName(_fromUtf8("manualRadio"))
|
||||
self.gridLayout.addWidget(self.manualRadio, 1, 0, 1, 2)
|
||||
@ -32,48 +51,43 @@ class Ui_Form(object):
|
||||
self.maxText = QtGui.QLineEdit(Form)
|
||||
self.maxText.setObjectName(_fromUtf8("maxText"))
|
||||
self.gridLayout.addWidget(self.maxText, 1, 3, 1, 1)
|
||||
self.autoRadio = QtGui.QRadioButton(Form)
|
||||
self.autoRadio.setChecked(True)
|
||||
self.autoRadio.setObjectName(_fromUtf8("autoRadio"))
|
||||
self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 2)
|
||||
self.autoPercentSpin = QtGui.QSpinBox(Form)
|
||||
self.autoPercentSpin.setEnabled(True)
|
||||
self.autoPercentSpin.setMinimum(1)
|
||||
self.autoPercentSpin.setMaximum(100)
|
||||
self.autoPercentSpin.setSingleStep(1)
|
||||
self.autoPercentSpin.setProperty(_fromUtf8("value"), 100)
|
||||
self.autoPercentSpin.setObjectName(_fromUtf8("autoPercentSpin"))
|
||||
self.gridLayout.addWidget(self.autoPercentSpin, 2, 2, 1, 2)
|
||||
self.visibleOnlyCheck = QtGui.QCheckBox(Form)
|
||||
self.visibleOnlyCheck.setObjectName(_fromUtf8("visibleOnlyCheck"))
|
||||
self.gridLayout.addWidget(self.visibleOnlyCheck, 3, 1, 1, 3)
|
||||
self.autoPanCheck = QtGui.QCheckBox(Form)
|
||||
self.autoPanCheck.setObjectName(_fromUtf8("autoPanCheck"))
|
||||
self.gridLayout.addWidget(self.autoPanCheck, 4, 1, 1, 3)
|
||||
self.label = QtGui.QLabel(Form)
|
||||
self.label.setObjectName(_fromUtf8("label"))
|
||||
self.gridLayout.addWidget(self.label, 5, 0, 1, 2)
|
||||
self.linkCombo = QtGui.QComboBox(Form)
|
||||
self.linkCombo.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
|
||||
self.linkCombo.setObjectName(_fromUtf8("linkCombo"))
|
||||
self.gridLayout.addWidget(self.linkCombo, 5, 2, 1, 2)
|
||||
self.invertCheck = QtGui.QCheckBox(Form)
|
||||
self.invertCheck.setObjectName(_fromUtf8("invertCheck"))
|
||||
self.gridLayout.addWidget(self.invertCheck, 5, 0, 1, 4)
|
||||
self.mouseCheck = QtGui.QCheckBox(Form)
|
||||
self.mouseCheck.setChecked(True)
|
||||
self.mouseCheck.setObjectName(_fromUtf8("mouseCheck"))
|
||||
self.gridLayout.addWidget(self.mouseCheck, 0, 0, 1, 4)
|
||||
self.gridLayout.addWidget(self.mouseCheck, 6, 0, 1, 4)
|
||||
self.visibleOnlyCheck = QtGui.QCheckBox(Form)
|
||||
self.visibleOnlyCheck.setObjectName(_fromUtf8("visibleOnlyCheck"))
|
||||
self.gridLayout.addWidget(self.visibleOnlyCheck, 3, 2, 1, 2)
|
||||
self.autoPanCheck = QtGui.QCheckBox(Form)
|
||||
self.autoPanCheck.setObjectName(_fromUtf8("autoPanCheck"))
|
||||
self.gridLayout.addWidget(self.autoPanCheck, 4, 2, 1, 2)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QtCore.QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.visibleOnlyCheck.setText(QtGui.QApplication.translate("Form", "Visible Data Only", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.label.setText(QtGui.QApplication.translate("Form", "Link Axis:", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.linkCombo.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Links this axis with another view. When linked, both views will display the same data range.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoPercentSpin.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Percent of data to be visible when auto-scaling. It may be useful to decrease this value for data with spiky noise.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoRadio.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Automatically resize this axis whenever the displayed data is changed.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.manualRadio.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Set the range for this axis manually. This disables automatic scaling. </p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.minText.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Minimum value to display for this axis.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.maxText.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Maximum value to display for this axis.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.invertCheck.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Inverts the display of this axis. (+y points downward instead of upward)</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.invertCheck.setText(QtGui.QApplication.translate("Form", "Invert Axis", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.mouseCheck.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>Enables mouse interaction (panning, scaling) for this axis.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.mouseCheck.setText(QtGui.QApplication.translate("Form", "Mouse Enabled", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.visibleOnlyCheck.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>When checked, the axis will only auto-scale to data that is visible along the orthogonal axis.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.visibleOnlyCheck.setText(QtGui.QApplication.translate("Form", "Visible Data Only", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoPanCheck.setToolTip(QtGui.QApplication.translate("Form", "<html><head/><body><p>When checked, the axis will automatically pan to center on the current data, but the scale along this axis will not change.</p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
|
||||
self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>186</width>
|
||||
<height>137</height>
|
||||
<height>154</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
@ -26,34 +26,20 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="manualRadio">
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Manual</string>
|
||||
<string>Link Axis:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="minText">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
<item row="7" column="2" colspan="2">
|
||||
<widget class="QComboBox" name="linkCombo">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Links this axis with another view. When linked, both views will display the same data range.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="maxText">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="autoRadio">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -62,6 +48,9 @@
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Percent of data to be visible when auto-scaling. It may be useful to decrease this value for data with spiky noise.</p></body></html></string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>%</string>
|
||||
</property>
|
||||
@ -79,36 +68,64 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="visibleOnlyCheck">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="autoRadio">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Automatically resize this axis whenever the displayed data is changed.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Visible Data Only</string>
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="3">
|
||||
<widget class="QCheckBox" name="autoPanCheck">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QRadioButton" name="manualRadio">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Set the range for this axis manually. This disables automatic scaling. </p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto Pan Only</string>
|
||||
<string>Manual</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="minText">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Minimum value to display for this axis.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Link Axis:</string>
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2" colspan="2">
|
||||
<widget class="QComboBox" name="linkCombo">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="maxText">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Maximum value to display for this axis.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<item row="5" column="0" colspan="4">
|
||||
<widget class="QCheckBox" name="invertCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Inverts the display of this axis. (+y points downward instead of upward)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Invert Axis</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="4">
|
||||
<widget class="QCheckBox" name="mouseCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enables mouse interaction (panning, scaling) for this axis.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mouse Enabled</string>
|
||||
</property>
|
||||
@ -117,6 +134,26 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" colspan="2">
|
||||
<widget class="QCheckBox" name="visibleOnlyCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>When checked, the axis will only auto-scale to data that is visible along the orthogonal axis.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Visible Data Only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" colspan="2">
|
||||
<widget class="QCheckBox" name="autoPanCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>When checked, the axis will automatically pan to center on the current data, but the scale along this axis will not change.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto Pan Only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
Loading…
Reference in New Issue
Block a user