From 4384944952a919ef7f9a79e039fab92e60dfc4f6 Mon Sep 17 00:00:00 2001 From: Luke Campagnola <> Date: Mon, 9 Jul 2012 17:14:41 -0400 Subject: [PATCH] Cleaned up parametertree example --- examples/__main__.py | 2 +- examples/parametertree.py | 160 ++++++++++++++++++++++++++++++++ parametertree/Parameter.py | 7 +- parametertree/__main__.py | 132 -------------------------- parametertree/parameterTypes.py | 1 + 5 files changed, 168 insertions(+), 134 deletions(-) create mode 100644 examples/parametertree.py delete mode 100644 parametertree/__main__.py diff --git a/examples/__main__.py b/examples/__main__.py index 39c51b7f..84a175e6 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -11,7 +11,7 @@ examples = OrderedDict([ ('Command-line usage', 'CLIexample.py'), ('Basic Plotting', 'Plotting.py'), ('ImageView', 'ImageView.py'), - ('ParameterTree', '../parametertree'), + ('ParameterTree', 'parametertree.py'), ('Crosshair / Mouse interaction', 'crosshair.py'), ('Video speed test', 'VideoSpeedTest.py'), ('Plot speed test', 'PlotSpeedTest.py'), diff --git a/examples/parametertree.py b/examples/parametertree.py new file mode 100644 index 00000000..c4aca740 --- /dev/null +++ b/examples/parametertree.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +""" +This example demonstrates the use of pyqtgraph's parametertree system. This provides +a simple way to generate user interfaces that control sets of parameters. The example +demonstrates a variety of different parameter types (int, float, list, etc.) +as well as some customized parameter types + +""" + + +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 collections +app = QtGui.QApplication([]) +import pyqtgraph.parametertree.parameterTypes as pTypes +from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType + + +## test subclassing parameters +## This parameter automatically generates two child parameters which are always reciprocals of each other +class ComplexParameter(pTypes.GroupParameter): + def __init__(self, **opts): + opts['type'] = 'bool' + opts['value'] = True + pTypes.GroupParameter.__init__(self, **opts) + + self.addChild({'name': 'A = 1/B', 'type': 'float', 'value': 7, 'suffix': 'Hz', 'siPrefix': True}) + self.addChild({'name': 'B = 1/A', 'type': 'float', 'value': 1/7., 'suffix': 's', 'siPrefix': True}) + self.a = self.param('A = 1/B') + self.b = self.param('B = 1/A') + self.a.sigValueChanged.connect(self.aChanged) + self.b.sigValueChanged.connect(self.bChanged) + + def aChanged(self): + self.b.setValue(1.0 / self.a.value(), blockSignal=self.bChanged) + + def bChanged(self): + self.a.setValue(1.0 / self.b.value(), blockSignal=self.aChanged) + + +## test add/remove +## this group includes a menu allowing the user to add new parameters into its child list +class ScalableGroup(pTypes.GroupParameter): + def __init__(self, **opts): + opts['type'] = 'group' + opts['addText'] = "Add" + opts['addList'] = ['str', 'float', 'int'] + pTypes.GroupParameter.__init__(self, **opts) + + def addNew(self, typ): + val = { + 'str': '', + 'float': 0.0, + 'int': 0 + }[typ] + self.addChild(dict(name="ScalableParam %d" % (len(self.childs)+1), type=typ, value=val, removable=True, renamable=True)) + + +## test column spanning (widget sub-item that spans all columns) +class TextParameterItem(pTypes.WidgetParameterItem): + def __init__(self, param, depth): + pTypes.WidgetParameterItem.__init__(self, param, depth) + self.subItem = QtGui.QTreeWidgetItem() + self.addChild(self.subItem) + + def treeWidgetChanged(self): + self.treeWidget().setFirstItemColumnSpanned(self.subItem, True) + self.treeWidget().setItemWidget(self.subItem, 0, self.textBox) + self.setExpanded(True) + + def makeWidget(self): + self.textBox = QtGui.QTextEdit() + self.textBox.setMaximumHeight(100) + self.textBox.value = lambda: str(self.textBox.toPlainText()) + self.textBox.setValue = self.textBox.setPlainText + self.textBox.sigChanged = self.textBox.textChanged + return self.textBox + +class TextParameter(Parameter): + type = 'text' + itemClass = TextParameterItem + +registerParameterType('text', TextParameter) + + + + +params = [ + {'name': 'Basic parameter data types', 'type': 'group', 'children': [ + {'name': 'Integer', 'type': 'int', 'value': 10}, + {'name': 'Float', 'type': 'float', 'value': 10.5, 'step': 0.1}, + {'name': 'String', 'type': 'str', 'value': "hi"}, + {'name': 'List', 'type': 'list', 'values': [1,2,3], 'value': 2}, + {'name': 'Named List', 'type': 'list', 'values': {"one": 1, "two": 2, "three": 3}, 'value': 2}, + {'name': 'Boolean', 'type': 'bool', 'value': True, 'tip': "This is a checkbox"}, + {'name': 'Color', 'type': 'color', 'value': "FF0", 'tip': "This is a color button"}, + {'name': 'Subgroup', 'type': 'group', 'children': [ + {'name': 'Sub-param 1', 'type': 'int', 'value': 10}, + {'name': 'Sub-param 2', 'type': 'float', 'value': 1.2e6}, + ]}, + ]}, + {'name': 'Numerical Parameter Options', 'type': 'group', 'children': [ + {'name': 'Units + SI prefix', 'type': 'float', 'value': 1.2e-6, 'step': 1e-6, 'siPrefix': True, 'suffix': 'V'}, + {'name': 'Limits (min=7;max=15)', 'type': 'int', 'value': 11, 'limits': (7, 15), 'default': -6}, + {'name': 'DEC stepping', 'type': 'float', 'value': 1.2e6, 'dec': True, 'step': 1, 'siPrefix': True, 'suffix': 'Hz'}, + + ]}, + {'name': 'Extra Parameter Options', 'type': 'group', 'children': [ + {'name': 'Read-only', 'type': 'float', 'value': 1.2e6, 'siPrefix': True, 'suffix': 'Hz', 'readonly': True}, + {'name': 'Renamable', 'type': 'float', 'value': 1.2e6, 'siPrefix': True, 'suffix': 'Hz', 'renamable': True}, + {'name': 'Removable', 'type': 'float', 'value': 1.2e6, 'siPrefix': True, 'suffix': 'Hz', 'removable': True}, + ]}, + ComplexParameter(name='Custom parameter group (reciprocal values)'), + ScalableGroup(name="Expandable Parameter Group", children=[ + {'name': 'ScalableParam 1', 'type': 'str', 'value': "default param 1"}, + {'name': 'ScalableParam 2', 'type': 'str', 'value': "default param 2"}, + ]), + {'name': 'Custom parameter class (text box)', 'type': 'text', 'value': 'Some text...'}, +] + +## Create tree of Parameter objects +p = Parameter(name='params', type='group', children=params) + +## If anything changes in the tree, print a message +def change(param, changes): + print("tree changes:") + for param, change, data in changes: + path = p.childPath(param) + if path is not None: + childName = '.'.join(path) + else: + childName = param.name() + print(' parameter: %s'% childName) + print(' change: %s'% change) + print(' data: %s'% str(data)) + print(' ----------') + +p.sigTreeStateChanged.connect(change) + +## Create two ParameterTree widgets, both accessing the same data +t = ParameterTree() +t.setParameters(p, showTop=False) +t.show() +t.resize(400,600) +t2 = ParameterTree() +t2.setParameters(p, showTop=False) +t2.show() +t2.resize(400,600) + + + + +## Start Qt event loop unless running in interactive mode or using pyside. +import sys +if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + QtGui.QApplication.instance().exec_() diff --git a/parametertree/Parameter.py b/parametertree/Parameter.py index 1c92457e..ebf9be58 100644 --- a/parametertree/Parameter.py +++ b/parametertree/Parameter.py @@ -131,11 +131,16 @@ class Parameter(QtCore.QObject): return name def childPath(self, child): - """Return the path of parameter names from self to child.""" + """ + Return the path of parameter names from self to child. + If child is not a (grand)child of self, return None. + """ path = [] while child is not self: path.insert(0, child.name()) child = child.parent() + if child is None: + return None return path def setValue(self, value, blockSignal=None): diff --git a/parametertree/__main__.py b/parametertree/__main__.py deleted file mode 100644 index 95bc9b70..00000000 --- a/parametertree/__main__.py +++ /dev/null @@ -1,132 +0,0 @@ -## tests for ParameterTree - -## make sure pyqtgraph is in path -import sys,os -md = os.path.abspath(os.path.dirname(__file__)) -sys.path.append(os.path.join(md, '..', '..')) - -from pyqtgraph.Qt import QtCore, QtGui -import collections -app = QtGui.QApplication([]) -import pyqtgraph.parametertree.parameterTypes as pTypes -from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType - - -## test subclassing parameters -## This parameter automatically generates two child parameters which are always reciprocals of each other -class ComplexParameter(Parameter): - def __init__(self, **opts): - opts['type'] = 'bool' - opts['value'] = True - Parameter.__init__(self, **opts) - - self.addChild({'name': 'A = 1/B', 'type': 'float', 'value': 7, 'suffix': 'Hz', 'siPrefix': True}) - self.addChild({'name': 'B = 1/A', 'type': 'float', 'value': 1/7., 'suffix': 's', 'siPrefix': True}) - self.a = self.param('A = 1/B') - self.b = self.param('B = 1/A') - self.a.sigValueChanged.connect(self.aChanged) - self.b.sigValueChanged.connect(self.bChanged) - - def aChanged(self): - self.b.setValue(1.0 / self.a.value(), blockSignal=self.bChanged) - - def bChanged(self): - self.a.setValue(1.0 / self.b.value(), blockSignal=self.aChanged) - - -## test add/remove -## this group includes a menu allowing the user to add new parameters into its child list -class ScalableGroup(pTypes.GroupParameter): - def __init__(self, **opts): - opts['type'] = 'group' - opts['addText'] = "Add" - opts['addList'] = ['str', 'float', 'int'] - pTypes.GroupParameter.__init__(self, **opts) - - def addNew(self, typ): - val = { - 'str': '', - 'float': 0.0, - 'int': 0 - }[typ] - self.addChild(dict(name="ScalableParam %d" % (len(self.childs)+1), type=typ, value=val, removable=True, renamable=True)) - - -## test column spanning (widget sub-item that spans all columns) -class TextParameterItem(pTypes.WidgetParameterItem): - def __init__(self, param, depth): - pTypes.WidgetParameterItem.__init__(self, param, depth) - self.subItem = QtGui.QTreeWidgetItem() - self.addChild(self.subItem) - - def treeWidgetChanged(self): - self.treeWidget().setFirstItemColumnSpanned(self.subItem, True) - self.treeWidget().setItemWidget(self.subItem, 0, self.textBox) - self.setExpanded(True) - - def makeWidget(self): - self.textBox = QtGui.QTextEdit() - self.textBox.setMaximumHeight(100) - self.textBox.value = lambda: str(self.textBox.toPlainText()) - self.textBox.setValue = self.textBox.setPlainText - self.textBox.sigChanged = self.textBox.textChanged - return self.textBox - -class TextParameter(Parameter): - type = 'text' - itemClass = TextParameterItem - -registerParameterType('text', TextParameter) - - - - -params = [ - {'name': 'Group 0', 'type': 'group', 'children': [ - {'name': 'Param 1', 'type': 'int', 'value': 10}, - {'name': 'Param 2', 'type': 'float', 'value': 10}, - ]}, - {'name': 'Group 1', 'type': 'group', 'children': [ - {'name': 'Param 1.1', 'type': 'float', 'value': 1.2e-6, 'dec': True, 'siPrefix': True, 'suffix': 'V'}, - {'name': 'Param 1.2', 'type': 'float', 'value': 1.2e6, 'dec': True, 'siPrefix': True, 'suffix': 'Hz'}, - {'name': 'Group 1.3', 'type': 'group', 'children': [ - {'name': 'Param 1.3.1', 'type': 'int', 'value': 11, 'limits': (-7, 15), 'default': -6}, - {'name': 'Param 1.3.2', 'type': 'float', 'value': 1.2e6, 'dec': True, 'siPrefix': True, 'suffix': 'Hz', 'readonly': True}, - ]}, - {'name': 'Param 1.4', 'type': 'str', 'value': "hi"}, - {'name': 'Param 1.5', 'type': 'list', 'values': [1,2,3], 'value': 2}, - {'name': 'Param 1.6', 'type': 'list', 'values': {"one": 1, "two": 2, "three": 3}, 'value': 2}, - ComplexParameter(name='ComplexParam'), - ScalableGroup(name="ScalableGroup", children=[ - {'name': 'ScalableParam 1', 'type': 'str', 'value': "hi"}, - {'name': 'ScalableParam 2', 'type': 'str', 'value': "hi"}, - - ]) - ]}, - {'name': 'Param 5', 'type': 'bool', 'value': True, 'tip': "This is a checkbox"}, - {'name': 'Param 6', 'type': 'color', 'value': "FF0", 'tip': "This is a color button. It cam be renamed.", 'renamable': True}, - {'name': 'TextParam', 'type': 'text', 'value': 'Some text...'}, -] - -#p = pTypes.ParameterSet("params", params) -p = Parameter(name='params', type='group', children=params) -def change(param, changes): - print("tree changes:") - for param, change, data in changes: - print(" [" + '.'.join(p.childPath(param))+ "] ", change, data) - -p.sigTreeStateChanged.connect(change) - - -t = ParameterTree() -t.setParameters(p, showTop=False) -t.show() -t.resize(400,600) -t2 = ParameterTree() -t2.setParameters(p, showTop=False) -t2.show() -t2.resize(400,600) - -import sys -if sys.flags.interactive == 0: - app.exec_() diff --git a/parametertree/parameterTypes.py b/parametertree/parameterTypes.py index a9fbd413..039c0493 100644 --- a/parametertree/parameterTypes.py +++ b/parametertree/parameterTypes.py @@ -348,6 +348,7 @@ class GroupParameterItem(ParameterItem): def treeWidgetChanged(self): ParameterItem.treeWidgetChanged(self) + self.treeWidget().setFirstItemColumnSpanned(self, True) if self.addItem is not None: self.treeWidget().setItemWidget(self.addItem, 0, self.addWidgetBox) self.treeWidget().setFirstItemColumnSpanned(self.addItem, True)