Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
fslpy
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Michiel Cottaar
fslpy
Commits
05fed6ed
Commit
05fed6ed
authored
11 years ago
by
Paul McCarthy
Browse files
Options
Downloads
Patches
Plain Diff
Commenting and cosmetic changes. I think the properties*py files now actually make some sense.
parent
7b03bc36
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
tkprop/properties.py
+38
-18
38 additions, 18 deletions
tkprop/properties.py
tkprop/properties_types.py
+55
-43
55 additions, 43 deletions
tkprop/properties_types.py
with
93 additions
and
61 deletions
tkprop/properties.py
+
38
−
18
View file @
05fed6ed
...
...
@@ -3,8 +3,8 @@
# properties.py - Tkinter control variables encapsulated inside Python
# descriptors.
#
# This module should not
typically
be imported directly - import the
#
tkprops package
. Property type definitions are in properties_types.py.
# This module should not be imported directly - import the
tkprops
#
package instead
. Property type definitions are in properties_types.py.
#
# Usage:
#
...
...
@@ -88,7 +88,7 @@
# allowing custom validation rules to be enforced on such control
# variables.
#
#
Class structure
is organised as follows:
#
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
...
...
@@ -121,7 +121,7 @@
# 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
# only be notified of changes to that TkVarProxy object.
#
then
only be notified of changes to that TkVarProxy object.
#
# author: Paul McCarthy <pauldmccarthy@gmail.com>
#
...
...
@@ -170,9 +170,9 @@ class TkVarProxy(object):
def
addListener
(
self
,
name
,
callback
):
"""
Adds a listener for this variable. When the variable value
, the
listener callback function is called. The
callback function
must accept these arguments:
Adds a listener for this variable. When the variable value
changes, the
listener callback function is called. The
callback function
must accept these arguments:
value - The new property value
valid - Whether the new value is valid or invalid
...
...
@@ -229,10 +229,12 @@ class TkVarProxy(object):
try
:
newValue
=
self
.
tkVar
.
get
()
# and if that fails, we manually look up the value
# via the current tk context.
# via the current tk context, thus avoiding the
# failing type cast. Ugly.
except
:
newValue
=
self
.
tkVar
.
_tk
.
globalgetvar
(
self
.
name
)
# if the new value is valid, save it
# if the new value is valid, save it as the last
# known good value
try
:
self
.
tkProp
.
validate
(
self
.
owner
,
newValue
)
self
.
lastValue
=
newValue
...
...
@@ -253,8 +255,9 @@ class TkVarProxy(object):
log
.
debug
(
'
Notifying listener on {}: {}
'
.
format
(
self
.
name
,
name
))
try
:
func
(
newValue
,
valid
,
self
.
owner
,
self
.
tkProp
,
self
.
name
)
except
:
log
.
debug
(
''
)
except
Exception
as
e
:
log
.
debug
(
'
Listener on {} ({}) raised exception: {}
'
.
format
(
self
.
name
,
name
,
e
))
def
revert
(
self
):
...
...
@@ -274,10 +277,28 @@ class TkVarProxy(object):
class
PropertyBase
(
object
):
"""
The base class for properties. Subclasses should override the
validate method to implement any required validation rules and, in
special cases, may override __get__, __set__, and _makeTkVar, with
care.
The base class for properties. Subclasses should:
- Ensure that PropertyBase.__init__ is called.
- Override the validate method to implement any built in
validation rules, ensuring that the PropertyBase.validate
method is called.
- Override __get__ and __set__ for any required implicit
casting/data transformation rules (see
properties_types.String for an example).
- Override _makeTkVar if creation of the TkVarProxy needs
to be controlled (see properties_types.Choice for an
example).
- Override getTkVar for properties which consist of
more than one TkVarProxy object
(see properties_types.List for an example).
- Override whatever you want for advanced usage (see
properties_types.List for an example).
"""
def
__init__
(
self
,
tkVarType
,
default
,
validateFunc
=
None
):
...
...
@@ -394,7 +415,7 @@ class PropertyBase(object):
"""
If called on the HasProperties class, and not on an instance,
returns this PropertyBase object. Otherwise, returns the value
contained in the Tk
control
variable which is attached to the
contained in the Tk
VarProxy
variable which is attached to the
instance.
"""
...
...
@@ -412,8 +433,7 @@ class PropertyBase(object):
the given value.
"""
instval
=
instance
.
__dict__
.
get
(
self
.
label
,
None
)
if
instval
is
None
:
instval
=
self
.
_makeTkVar
(
instance
)
instval
=
getattr
(
self
,
instance
)
instval
.
tkVar
.
set
(
value
)
...
...
This diff is collapsed.
Click to expand it.
tkprop/properties_types.py
+
55
−
43
View file @
05fed6ed
#!/usr/bin/env python
#
# properties_types.py - Definitions for different property types - see
# properties.py.
# properties.py
for more information
.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import
os
import
os
import
os.path
as
op
import
logging
as
log
from
collections
import
OrderedDict
import
Tkinter
as
tk
import
Tkinter
as
tk
import
tkprop.properties
as
props
...
...
@@ -33,7 +30,7 @@ class Boolean(props.PropertyBase):
class
Number
(
props
.
PropertyBase
):
"""
Base class for the Int and Double classes. Don
'
t
subclass this, subclass one of Int or Double.
use/
subclass this,
use/
subclass one of Int or Double.
"""
def
__init__
(
self
,
tkvartype
,
minval
=
None
,
maxval
=
None
,
**
kwargs
):
...
...
@@ -255,9 +252,11 @@ class Choice(String):
the real control variable is set to the corresponding choice.
Similarly, we add a trace to the original control variable, so that
when its choice value is modified, the label variable value is
changed. Even though this circular event callback situation looks
incredibly dangerous, Tkinter (in python 2.7.6) seems to be smart
enough to inhibit an infinitely recursive event explosion.
changed.
Even though this circular event callback situation looks incredibly
dangerous, Tkinter (in python 2.7.6) seems to be smart enough to
inhibit an infinitely recursive event explosion.
The label control variable is accessible via the Choice.getLabelVar()
method.
...
...
@@ -319,21 +318,22 @@ class FilePath(String):
self
.
label
,
value
))
class
_
ListWrapper
(
object
):
class
ListWrapper
(
object
):
"""
Used by the List property type, defined below. An object which
acts like a list, but for which items are embedded in
a
TkVarProxy
object, minimum/maximum list length may be enforced,
and
value/type constraints enforced on the values added to it.
acts like a list, but for which items are embedded in
TkVarProxy
object
s
, minimum/maximum list length may be enforced,
and
value/type constraints enforced on the values added to it.
Only basic list operations are supported. All list modifications
occur in the append and pop methods.
Only basic list operations are supported. List modifications
occur exclusively in the append, pop, __setitem__ and
__delitem__ methods.
A TkVarProxy object is created for each item that is added to
the list. When a list value is changed, instead of a new
variable being created, the value of the existing variable
is changed. References to the list of TkVarProxy objects may
be accessed via the _tkVars attribute of the
_
ListWrapper
be accessed via the _tkVars attribute of the ListWrapper
object.
"""
...
...
@@ -347,14 +347,21 @@ class _ListWrapper(object):
"""
Parameters:
- owner: The HasProperties object, of which the List object
which is managing this
_
ListWrapper object, is a
which is managing this ListWrapper object, is a
property.
- listProp: The List property object which is managing this
_ListWrapper object.
ListWrapper object. Whenever the list, or a value
within the list is modified, listProp._valueChanged
is called.
- values: list of initial values.
- listType: A PropertyBase instance, specifying the type of
data allowed in this list.
- minlen: minimum list length
- maxlen: maximum list length
"""
...
...
@@ -365,13 +372,16 @@ class _ListWrapper(object):
self
.
_minlen
=
minlen
self
.
_maxlen
=
maxlen
# This is the list that the
_
ListWrapper wraps.
# This is the list that the ListWrapper wraps.
# It contains TkVarProxy objects.
self
.
_tkVars
=
[]
# Set the list to the given initial values
if
values
is
not
None
:
self
.
extend
(
values
)
# Or create a list of length at least
# minlen, containing default values
elif
self
.
_minlen
is
not
None
:
for
i
in
range
(
self
.
_minlen
):
...
...
@@ -411,7 +421,8 @@ class _ListWrapper(object):
def
_notify
(
self
):
"""
If a listener was passed to the constructor, it is called.
Called on list modifications. Notifies the List property via
its _varChanged method.
"""
self
.
_listProp
.
_varChanged
(
...
...
@@ -507,10 +518,8 @@ class _ListWrapper(object):
def
extend
(
self
,
iterable
):
"""
Appends all items in the given iterable to the end of the
list. A ValueError is raised if any item does not meet the
list type/value constraints. An IndexError is raised if
an insertion would causes the list to grow beyond its
maximum length.
list. An IndexError is raised if an insertion would causes
the list to grow beyond its maximum length.
"""
toAdd
=
list
(
iterable
)
...
...
@@ -531,6 +540,7 @@ class _ListWrapper(object):
tkVar
=
self
.
_tkVars
.
pop
()
val
=
tkVar
.
tkVar
.
get
()
self
.
_notify
()
return
val
...
...
@@ -538,14 +548,12 @@ class _ListWrapper(object):
def
__setitem__
(
self
,
key
,
values
):
"""
Sets the value(s) of the list at the specified index/slice.
A ValueError is raised if any of the values do not meet the
list type/value constraints.
"""
if
isinstance
(
key
,
slice
):
if
(
key
.
step
is
not
None
)
and
(
key
.
step
>
1
):
raise
ValueError
(
'
_
ListWrapper does not support extended slices
'
)
'
ListWrapper does not support extended slices
'
)
indices
=
range
(
*
key
.
indices
(
len
(
self
)))
elif
isinstance
(
key
,
int
):
...
...
@@ -569,10 +577,12 @@ class _ListWrapper(object):
# removing items
elif
newLen
<
oldLen
:
self
.
_checkMinlen
(
-
lenDiff
)
# Replace values of existing items
if
newLen
==
oldLen
:
for
i
,
v
in
zip
(
indices
,
values
):
self
.
_tkVars
[
i
].
tkVar
.
set
(
v
)
# Replace old TkVarProxy objects with new ones.
else
:
values
=
[
self
.
_makeTkVar
(
v
)
for
v
in
values
]
if
len
(
values
)
==
1
:
values
=
values
[
0
]
...
...
@@ -600,10 +610,10 @@ class List(props.PropertyBase):
"""
A property which represents a list of items, of another property type.
List functionality is not complete - see the documentation for the
_
ListWrapper class, defined above.
ListWrapper class, defined above.
This class is a bit different from the other PropertyBase classes, in
that the validation logic is built into the
_
ListWrapper class, rather
that the validation logic is built into the ListWrapper class, rather
than this class.
"""
...
...
@@ -634,7 +644,7 @@ class List(props.PropertyBase):
def
getTkVar
(
self
,
instance
,
index
=
None
):
"""
Return a list of TkVarProxy objects or, if index is specif
r
ied,
Return a list of TkVarProxy objects or, if index is specified,
the TkVarProxy object at the specified index.
"""
if
index
is
None
:
return
instance
.
__dict__
[
self
.
label
].
_tkVars
...
...
@@ -643,14 +653,15 @@ class List(props.PropertyBase):
def
_makeTkVar
(
self
,
instance
):
"""
_ListWrapper instead of TkVarProxy.
Creates a ListWrapper object, and attaches it to the
given instance.
"""
instval
=
_
ListWrapper
(
instance
,
self
,
values
=
self
.
default
,
listType
=
self
.
listType
,
minlen
=
self
.
minlen
,
maxlen
=
self
.
maxlen
)
instval
=
ListWrapper
(
instance
,
self
,
values
=
self
.
default
,
listType
=
self
.
listType
,
minlen
=
self
.
minlen
,
maxlen
=
self
.
maxlen
)
instance
.
__dict__
[
self
.
label
]
=
instval
return
instval
...
...
@@ -658,7 +669,8 @@ class List(props.PropertyBase):
def
__get__
(
self
,
instance
,
owner
):
"""
Return _ListWrapper instead of value.
If instance is None, returns this List object. Otherwise returns
the ListWrapper instance attached to the given instance.
"""
if
instance
is
None
:
...
...
@@ -672,10 +684,10 @@ class List(props.PropertyBase):
def
__set__
(
self
,
instance
,
value
):
"""
Replace contents of list.
Replaces the contents of the ListWrapper object attached
to the given instance.
"""
instval
=
getattr
(
instance
,
self
.
label
)
instval
=
getattr
(
instance
,
self
.
label
)
instval
[:]
=
value
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment