diff --git a/fsl/props/build.py b/fsl/props/build.py index cea25f7c743600d0bfc91c52fb2522989af80749..84a1a1356758fbedbeaa57c116a9a35abb40b304 100644 --- a/fsl/props/build.py +++ b/fsl/props/build.py @@ -23,6 +23,10 @@ # tab for each child Group. The label for, and behaviour of, the widget # for an individual property may be customised with a Widget object. # +# As an alternative to passing in a view, labels, and tooltips, they +# may be specified as class attributes of the HasProperties object, +# with respective names '_view', '_labels', and '_tooltips'. +# # Author: Paul McCarthy <pauldmccarthy@gmail.com> # @@ -337,7 +341,6 @@ def _makeGroupBorder(parent, group, ctr, *args, **kwargs): borderSizer.Fit(borderPanel) return borderPanel, groupObject - def _createNotebookGroup(parent, group, hasProps, propGui): diff --git a/fsl/props/properties.py b/fsl/props/properties.py index 192ae16b20b7c7e9d7eba472fc9329f9aa50baf0..f18360bebc4d42d7d933e48029713aa16b9e643e 100644 --- a/fsl/props/properties.py +++ b/fsl/props/properties.py @@ -7,54 +7,44 @@ # # Usage: # -# import Tkinter as tk -# import tkprops as tkp +# >>> import fsl.props as props # +# >>> class PropObj(props.HasProperties): +# >>> myProperty = props.Boolean() # -# class PropObj(tkp.HasProperties): -# myProperty = tkp.Boolean() -# -# -# # The Tk root object must be created -# # before any HasProperties objects. -# app = tk.Tk() -# myPropObj = PropObj() +# >>> myPropObj = PropObj() # # # # Access the property value as a normal attribute: -# myPropObj.myProperty = True -# myPropObj.myProperty -# -# # >>> True +# >>> myPropObj.myProperty = True +# >>> myPropObj.myProperty +# >>> True # # -# # access the tkp.Boolean instance: -# myPropObj.getTkProp('myProperty') +# # access the props.Boolean instance: +# >>> myPropObj.getProp('myProperty') +# >>> <props.prop.Boolean at 0x1045e2710> # -# # >>> <tkprops.tkprop.Boolean at 0x1045e2710> # -# -# # access the underlying Tkinter control variable +# # access the underlying props.PropertyValue object # # (there are caveats for List properties): -# myPropObj.getTkVar('myProperty').tkVar -# -# # >>> <tkinter.BooleanVar instance at 0x1047ef518> +# >>> myPropObj.getPropVal('myProperty') +# >>> <props.prop.PropertyValue instance at 0x1047ef518> # # # # Receive notification of property value changes -# def myPropertyChanged(instance, name, value): -# print('New value for {}: {}'.format(name, value)) +# >>> def myPropertyChanged(value, *args): +# >>> print('New property value: {}'.format(value)) # -# PropObj.myProperty.addListener( -# myPropObj, 'myListener', myPropertyChanged) +# >>> myPropObj.addListener( +# >>> 'myProperty', 'myListener', myPropertyChanged) # -# myPropObj.myProperty = False -# -# # >>> New value for myProperty: False +# >>> myPropObj.myProperty = False +# >>> New property value: False # # # # Remove a previously added listener -# PropObj.myProperty.removeListener(myPropObj, 'myListener') +# myPropObj.removeListener('myListener') # # # Lots of the code in this file is probably very confusing. First of @@ -74,53 +64,37 @@ # # - http://pyvideo.org/video/1760/encapsulation-with-descriptors # -# Once you know how Python descriptors work, you then need to know how -# Tk control variables work. These are simple objects which may be -# passed to a Tkinter widget object when it is created. When a user -# modifies the widget value, the Tk control variable is -# modified. Conversely, if the value of a Tk control variable object is -# modified, any widgets which are bound to the variable are updated to -# reflect the new value. -# -# This module, and the associated tkpropwidget module, uses magic to -# encapsulate Tkinter control variables within python descriptors, thus -# allowing custom validation rules to be enforced on such control -# variables. -# -# The runtime structure of Tk properties is organised as follows: # -# A HasProperties (sub)class contains a collection of PropertyBase -# instances. When an instance of the HasProperties class is created, one -# or more TkVarProxy objects are created for each of the PropertyBase +# A HasProperties (sub)class contains a collection of PropertyBase instances +# as class attributes. When an instance of the HasProperties class is created, +# one or more PropertyValue objects are created for each of the PropertyBase # instances. For most properties, there is a one-to-one mapping between -# TkVarProxy instances and PropertyBase instances (for each -# HasProperties instance), however this is not mandatory. For example, -# the List property manages multiple TkVarProxy objects for each -# HasProperties instance. - -# Each of these TkVarProxy instances encapsulates a single Tkinter -# control variable. Whenever a variable value changes, the TkVarProxy -# instance passes the new value to the validate method of its parent -# PropertyBase instance to determine whether the new value is valid, and -# notifies any registered listeners of the change. The TkVarProxy object -# will allow its underlying Tkinter variable to be given invalid values, -# but it will tell registered listeners whether the new value is valid -# or invalid. -# -# Application code may be notified of property changes in two ways. -# First, a listener may be registered with a PropertyBase object, by -# passing a reference to the HasProperties instance, a name, and a -# callback function to the PropertyBase.addListener method. Such a -# listener will be notified of changes to any of the TkVarProxy objects -# managed by the PropertyBase object, and associated with the -# HasProperties instance. This is important for List properties, as it -# means that a change to a single TkVarProxy object in a list will -# result in notification of all registered listeners. -# -# If one is interested in changes to a single TkVarProxy object -# (e.g. one element of a List property), then a listener may be -# registered directly with the TkVarProxy object. This listener will -# then only be notified of changes to that TkVarProxy object. +# ProperyyValue instances and PropertyBase instances (for each HasProperties +# instance), however this is not mandatory. For example, the List property +# manages multiple PropertyValue objects for each HasProperties instance. + +# Each of these PropertyValue instances encapsulates a single value, of any +# type. Whenever a variable value changes, the PropertyValue instance passes +# the new value to the validate method of its parent PropertyBase instance to +# determine whether the new value is valid, and notifies any registered +# listeners of the change. The PropertyValue object will allow its underlying +# value to be set to something invalid, but it will tell registered listeners +# whether the new value is valid or invalid. +# +# Application code may be notified of property changes in two ways. First, a +# listener may be registered with a PropertyBase object, either via the +# HasProperties.addListener instance method, or the PropertyBase.addListener +# class method (these are equivalent). Such a listener will be notified of +# changes to any of the PropertyValue objects managed by the PropertyBase +# object, and associated with the HasProperties instance. This is important +# for List properties, as it means that a change to a single PropertyValue +# object in a list will result in notification of all registered listeners. +# +# If one is interested in changes to a single PropertyValue object (e.g. one +# element of a List property), then a listener may be registered directly with +# the PropertyValue object, via the PropertyValue.addListener instance +# method. This listener will then only be notified of changes to that +# PropertyValue object. # # author: Paul McCarthy <pauldmccarthy@gmail.com> #