From 6932c3412618da0843004cc473b5a76e910ae939 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Mon, 18 Jun 2012 14:00:19 -0400 Subject: [PATCH] - 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 --- examples/linkedViews.py | 16 +-- flowchart/Node.py | 2 +- graphicsItems/GraphicsItem.py | 47 ++++++--- graphicsItems/GraphicsObject.py | 7 +- graphicsItems/GraphicsWidget.py | 9 +- graphicsItems/ViewBox/ViewBox.py | 93 ++++++++++++++---- graphicsItems/ViewBox/ViewBoxMenu.py | 90 ++++++++++------- graphicsItems/ViewBox/axisCtrlTemplate.py | 86 +++++++++------- graphicsItems/ViewBox/axisCtrlTemplate.ui | 113 ++++++++++++++-------- 9 files changed, 302 insertions(+), 161 deletions(-) diff --git a/examples/linkedViews.py b/examples/linkedViews.py index 8abe7413..67bcfb2d 100644 --- a/examples/linkedViews.py +++ b/examples/linkedViews.py @@ -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. diff --git a/flowchart/Node.py b/flowchart/Node.py index a4204592..e3dce61d 100644 --- a/flowchart/Node.py +++ b/flowchart/Node.py @@ -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): diff --git a/graphicsItems/GraphicsItem.py b/graphicsItems/GraphicsItem.py index 8139cf05..0d0491f1 100644 --- a/graphicsItems/GraphicsItem.py +++ b/graphicsItems/GraphicsItem.py @@ -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): """ diff --git a/graphicsItems/GraphicsObject.py b/graphicsItems/GraphicsObject.py index f932f1ce..91354cfb 100644 --- a/graphicsItems/GraphicsObject.py +++ b/graphicsItems/GraphicsObject.py @@ -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) diff --git a/graphicsItems/GraphicsWidget.py b/graphicsItems/GraphicsWidget.py index 0af64f3f..c131a54a 100644 --- a/graphicsItems/GraphicsWidget.py +++ b/graphicsItems/GraphicsWidget.py @@ -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) diff --git a/graphicsItems/ViewBox/ViewBox.py b/graphicsItems/ViewBox/ViewBox.py index 2b1d2dcc..c2a4fd3d 100644 --- a/graphicsItems/ViewBox/ViewBox.py +++ b/graphicsItems/ViewBox/ViewBox.py @@ -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 diff --git a/graphicsItems/ViewBox/ViewBoxMenu.py b/graphicsItems/ViewBox/ViewBoxMenu.py index 73bd2874..dde6b129 100644 --- a/graphicsItems/ViewBox/ViewBoxMenu.py +++ b/graphicsItems/ViewBox/ViewBoxMenu.py @@ -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: diff --git a/graphicsItems/ViewBox/axisCtrlTemplate.py b/graphicsItems/ViewBox/axisCtrlTemplate.py index 21b6d010..08fa3af0 100644 --- a/graphicsItems/ViewBox/axisCtrlTemplate.py +++ b/graphicsItems/ViewBox/axisCtrlTemplate.py @@ -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", "

Links this axis with another view. When linked, both views will display the same data range.

", None, QtGui.QApplication.UnicodeUTF8)) + self.autoPercentSpin.setToolTip(QtGui.QApplication.translate("Form", "

Percent of data to be visible when auto-scaling. It may be useful to decrease this value for data with spiky noise.

", None, QtGui.QApplication.UnicodeUTF8)) + self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8)) + self.autoRadio.setToolTip(QtGui.QApplication.translate("Form", "

Automatically resize this axis whenever the displayed data is changed.

", None, QtGui.QApplication.UnicodeUTF8)) + self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8)) + self.manualRadio.setToolTip(QtGui.QApplication.translate("Form", "

Set the range for this axis manually. This disables automatic scaling.

", None, QtGui.QApplication.UnicodeUTF8)) + self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8)) + self.minText.setToolTip(QtGui.QApplication.translate("Form", "

Minimum value to display for this axis.

", None, QtGui.QApplication.UnicodeUTF8)) + self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8)) + self.maxText.setToolTip(QtGui.QApplication.translate("Form", "

Maximum value to display for this axis.

", None, QtGui.QApplication.UnicodeUTF8)) + self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8)) + self.invertCheck.setToolTip(QtGui.QApplication.translate("Form", "

Inverts the display of this axis. (+y points downward instead of upward)

", None, QtGui.QApplication.UnicodeUTF8)) + self.invertCheck.setText(QtGui.QApplication.translate("Form", "Invert Axis", None, QtGui.QApplication.UnicodeUTF8)) + self.mouseCheck.setToolTip(QtGui.QApplication.translate("Form", "

Enables mouse interaction (panning, scaling) for this axis.

", None, QtGui.QApplication.UnicodeUTF8)) self.mouseCheck.setText(QtGui.QApplication.translate("Form", "Mouse Enabled", None, QtGui.QApplication.UnicodeUTF8)) + self.visibleOnlyCheck.setToolTip(QtGui.QApplication.translate("Form", "

When checked, the axis will only auto-scale to data that is visible along the orthogonal axis.

", 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", "

When checked, the axis will automatically pan to center on the current data, but the scale along this axis will not change.

", None, QtGui.QApplication.UnicodeUTF8)) + self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/graphicsItems/ViewBox/axisCtrlTemplate.ui b/graphicsItems/ViewBox/axisCtrlTemplate.ui index 67e2618a..297fce75 100644 --- a/graphicsItems/ViewBox/axisCtrlTemplate.ui +++ b/graphicsItems/ViewBox/axisCtrlTemplate.ui @@ -7,7 +7,7 @@ 0 0 186 - 137 + 154 @@ -26,34 +26,20 @@ 0 - - + + - Manual + Link Axis: - - - - 0 + + + + <html><head/><body><p>Links this axis with another view. When linked, both views will display the same data range.</p></body></html> - - - - - - 0 - - - - - - - Auto - - - true + + QComboBox::AdjustToContents @@ -62,6 +48,9 @@ true + + <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> + % @@ -79,36 +68,64 @@ - - + + + + <html><head/><body><p>Automatically resize this axis whenever the displayed data is changed.</p></body></html> + - Visible Data Only + Auto + + + true - - + + + + <html><head/><body><p>Set the range for this axis manually. This disables automatic scaling. </p></body></html> + - Auto Pan Only + Manual - - + + + + <html><head/><body><p>Minimum value to display for this axis.</p></body></html> + - Link Axis: + 0 - - - - QComboBox::AdjustToContents + + + + <html><head/><body><p>Maximum value to display for this axis.</p></body></html> + + + 0 - + + + + <html><head/><body><p>Inverts the display of this axis. (+y points downward instead of upward)</p></body></html> + + + Invert Axis + + + + + + <html><head/><body><p>Enables mouse interaction (panning, scaling) for this axis.</p></body></html> + Mouse Enabled @@ -117,6 +134,26 @@ + + + + <html><head/><body><p>When checked, the axis will only auto-scale to data that is visible along the orthogonal axis.</p></body></html> + + + Visible Data Only + + + + + + + <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> + + + Auto Pan Only + + +