|
From: Kevin A. <al...@se...> - 2001-10-20 20:22:20
|
When the framework was started we had the stated goal of hiding all of
wxPython, partially because we thought we might want to eventually sit on
top of other GUI toolkits. The code and discussion below explores what
user/programmer code might look like if we weren't using dot notation or
class wrappers for wxPython widgets.
First of all, PythonCard widgets/components use a unique alphanumeric name
to uniquely identify each widget. I really like this aspect of what we have
today since dictionaries and lists are fundamental to Python, you can skip
using numeric identifiers entirely. A widget in wxPython terms is a control.
wxPython already supports setting the name of a control directly, so it is
possible to reference a particular control just by using its name in many
cases. widget.py in the prototype framework sets the name as part of
initialization as shown by this code fragment for the TextField class from
widget.py:
delegate = wxTextCtrl(
aParent._getDelegate(),
self.getId(),
aResource.text,
wxPoint( aResource.position[ 0 ], aResource.position[ 1 ] ),
wxSize( aResource.size[ 0 ], aResource.size[ 1 ] ),
style = borderStyle | wxCLIP_SIBLINGS,
name = aResource.name )
If you run the proof sample with the shell, you can see the name and class
info of the underlying wxPython controls. A background in PythonCard
contains a Panel class (wxPanel) which contains all the widgets/controls.
Thus the wxPython methods can be used with the panel as the following
example shows.
>>> bg = pcapp.getCurrentBackground()
>>> comp = bg.components
>>> children = bg.panel.GetChildren()
>>> for c in children:
... print c.GetName(), c.__class__.__name__, c.GetClassName()
...
field1 wxTextCtrlPtr wxTextCtrl
field2 wxTextCtrlPtr wxTextCtrl
button1 wxButtonPtr wxButton
...and so on...
There is already a method to find windows by name and since wxTextCtrl is
derived from a wxWindow and wxControl, you can do:
>>> f = bg.panel.FindWindowByName('field1')
>>> f.GetName(), f.GetClassName()
('field1', 'wxTextCtrl')
That means a lot of the work currently done by the WidgetDict class could
probably be done by just using a helper method to look up the name or id of
a wxPython control or just use the built-in wxPython method. The event
dispatch should still work as well. The framework simply needs to be changed
to bind/dispatch using wxPython controls instead of wrapped
widgets/controls.
The handler lookup could be changed to start from the control itself or its
immediate parent and then work up the chain until it gets to the app. Right
now the lookup starts with the background.
The framework we have today supports dot notation for all widget attributes
and the components dictionary. In general, an attribute such as 'text' maps
directly to _get/_set methods such as _getText/_setText. Here are the actual
methods from the TextField class.
def _setText( self, aString ) :
"""Sets the text value and marks the widget as not-modified.
aString may contain newline characters if the text widget is
multi-line."""
self._getDelegate().SetValue( aString )
def _getText( self ) :
"""Gets the contents of the widget. Notice that for a multiline text
widget, the lines will be separated by (Unix-style) \\n characters,
even under Windows where they are separated by a \\r\\n sequence in
the native control."""
return self._getDelegate().GetValue()
As you can see, these methods just turn around and call wxPython methods.
There are more complicated _get/_set examples, but quite a few are as simple
as this. The other thing that is going on here is an attempt to use more
consistent names. wxPython sometimes uses GetValue/SetValue and other times
has GetLabel/SetLabel. wxStaticBitmap uses GetBitmap/SetBitmap, but
wxBitmapButton uses GetBitmapLabel/SetBitmapLabel. PythonCard certainly has
its own problems, but we were attempting to fix some naming issues when we
came up with the attribute names.
So, what would getting and setting an attribute look like without dot
notation and using wxPython directly? 'panel' below might need to be another
FindWindowByName() call, but maybe the code would look something like this:
self.panel.FindWindowByName('field1').SetValue('hello world')
txt = self.panel.FindWindowByName('field1').GetValue()
compare that to what we currently do:
self.components.field1.text = 'hello world'
txt = self.components.field1.text
Somewhere between the two extremes is probably the right answer. It would be
possible to put a dot notation layer directly on top of wxPython by
providing a dictionary of attribute names and then the methods for that
attribute.
{'text':['GetValue', 'SetValue']}
Some variation like that.
ka
|