1
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
4
<link rel="STYLESHEET" href="howto.css" type='text/css' />
5
<link rel="first" href="howto.html" title='Developing applications with Kiwi' />
6
<link rel='last' href='about.html' title='About this document...' />
7
<link rel='help' href='about.html' title='About this document...' />
8
<link rel="next" href="node21.html" />
9
<link rel="prev" href="node19.html" />
10
<link rel="parent" href="node16.html" />
11
<link rel="next" href="node21.html" />
12
<meta name='aesop' content='information' />
13
<title>2.9.4 Customizing Proxies and Models</title>
16
<DIV CLASS="navigation">
17
<div id='top-navigation-panel' xml:id='top-navigation-panel'>
18
<table align="center" width="100%" cellpadding="0" cellspacing="2">
20
<td class='online-navigation'><a rel="prev" title="2.9.3 Propagating changes from"
21
href="node19.html"><img src='previous.png'
22
border='0' height='32' alt='Previous Page' width='32' /></A></td>
23
<td class='online-navigation'><a rel="parent" title="2.9 Proxies and Models"
24
href="node16.html"><img src='up.png'
25
border='0' height='32' alt='Up One Level' width='32' /></A></td>
26
<td class='online-navigation'><a rel="next" title="2.9.5 Using Signal Handlers"
27
href="node21.html"><img src='next.png'
28
border='0' height='32' alt='Next Page' width='32' /></A></td>
29
<td align="center" width="100%">Developing applications with Kiwi</td>
30
<td class='online-navigation'><img src='blank.png'
31
border='0' height='32' alt='' width='32' /></td>
32
<td class='online-navigation'><img src='blank.png'
33
border='0' height='32' alt='' width='32' /></td>
34
<td class='online-navigation'><img src='blank.png'
35
border='0' height='32' alt='' width='32' /></td>
37
<div class='online-navigation'>
38
<b class="navlabel">Previous:</b>
39
<a class="sectref" rel="prev" href="node19.html">2.9.3 Propagating changes from</A>
40
<b class="navlabel">Up:</b>
41
<a class="sectref" rel="parent" href="node16.html">2.9 Proxies and Models</A>
42
<b class="navlabel">Next:</b>
43
<a class="sectref" rel="next" href="node21.html">2.9.5 Using Signal Handlers</A>
47
<!--End of Navigation Panel-->
49
<H3><A NAME="SECTION000294000000000000000">
50
2.9.4 Customizing Proxies and Models</A>
54
From our example, proxy and instance appear to be completely coupled -
55
even the names of the components and attributes are tied. This is a
56
precise interpretation of the situation, but in my opinion, this
57
coupling is not only unavoidable, it is the essence of UI architecture.
58
Treating the interface as a completely separate entity from the object
59
it manipulates is, honestly, a bad idea, because <B>the interface is a
60
representation of the object</B>, and as such, essentially coupled to it.
61
Would it make sense to remove the <code>url</code> attribute from the model
62
and <I>not</I> remove it from the interface in question?
65
Because the UI is really a representation, however, there are times
66
where the contents of the widget and its attached proxy attribute must
67
differ in some way. Often, it is a matter of cardinality: more than one
68
widget defines a single proxy attribute, or vice-versa; at other times,
69
the data format in the widget does not match the format in the model
70
(think of dates, represented by strings in the interface, but stored as
71
DateTime objects in the object)<A NAME="tex2html7"
72
HREF="#foot294"><SUP>7</SUP></A>. The Kiwi Proxy was
73
designed to cater to these different requirements, using accessor
74
functions when available.
77
Accessors provide an easy way to translate the model value to the
78
interface value: a pair of <code>get_*()</code> and <code>set_*()</code> functions
79
implemented in the model that perform internal manipulation of its
80
variables, removing the need to directly manipulate the instance
81
variable. You can define accessors for as few or as many model
85
To make the process clearer, it is worth discussing how the model and
86
the UI are updated. The heuristics for updating a model are:
91
<LI>If a change happens in the Proxy's widget <code>X</code>, it looks at
92
the model attached to it.
94
<LI>If the model offers a <code>set_X()</code> method, it is called, with
95
the new value as its only parameter.
97
<LI>If not, it manipulates the model directly by using
98
<code>setattr()</code>, which is the equivalent of <code>model.X = value</code>. If
99
<code>Proxies.set_attr_warnings(True)</code> has been called, a warning like
100
the following will be printed:
103
<div class="verbatim"><pre>
104
Kiwi warning: could not find method set_title in model
105
<__main__.NewsItem instance at 0x82011ac>, using setattr()
110
<LI>The model is updated (If multiple proxies are attached to the
111
model, special things happen, additionally, as you will see in section
112
<A href="multipleproxies.html#multipleproxies">2.9</A>).
117
The heuristics for updating the interface widget are:
122
<LI>On startup, the proxy queries the model for the value for
123
attribute <code>X</code>.
125
<LI>It tries first using an accessor method <code>get_X()</code>
126
(which should return a single value). If the accessor does not exist, it
127
will attempt to access the model's variable directly (using
128
<code>getattr()</code>). As with <code>setattr()</code> above, a warning will be
129
printed if attribute warnings are enabled.
131
<LI>The interface is updated with this initial value, and normal
132
event processing begins.
134
<LI>If a model's state for <code>X</code> is altered (<code>item.X =
135
"foo"</code>), a notification is sent to the proxy, with the attribute that
136
was altered. If a callback calls <code>self.update("X")</code>, a notification
137
is sent to the proxy, with the attribute that was altered.
139
<LI>The proxy receives the notification; it gets the value of <code>X</code>
140
from the model using the same method as in step 2, and updates the
141
widget contents accordingly.
146
Summarizing: if you would like to customize the connection between model
147
and proxy for an attribute, implement accessor functions
148
(<code>get_foo()</code> and <code>set_foo()</code>) for it. If you would like to
149
verify that no direct instance manipulations are happening, use the
150
module function <code>set_attr_warnings()</code> and check the output
151
printed to the console's standard error.
154
Let's extend our previous example to provide an accessor and explain how
155
things work out (<span class="file">newsform3.py</span>).
158
<div class="verbatim"><pre>
159
class NewsItem(FrameWork.Model):
160
"""An instance representing an item of news.
161
Attributes: title, author, url"""
162
def set_url(self, url):
163
"""sets the url, prefixing "http://" if missing"""
165
if len(url) > len(http) and string.find(url, http) != 0:
171
In this example, we provide an accessor for setting the url (a "setter")
172
prefixed by "http://". The accessor is called when the entry's text
173
changes (for each character inserted or deleted), which is why I have to
174
check for the length of the url typed in. Note that I don't provide a
175
<code>get_url()</code> method (a "getter"), which means the raw url would be
176
loaded from the instance into the interface. In this specific case, this
177
is not an issue, because data is only loaded from the instance at
178
instantiation time and when the model attribute is changed. However, for
179
most cases both setter and getter need to convert to and from the model
183
<BR><HR><H4>Footnotes</H4>
185
<DT><A NAME="foot294">... object)</A><A
186
HREF="node20.html#tex2html7"><SUP>7</SUP></A></DT>
187
<DD> Apart from these reasons, some
188
people insist that it is bad or wrong to manipulate the instance
189
directly, and that accessors should always be used.
193
<DIV CLASS="navigation">
194
<div class='online-navigation'>
196
<table align="center" width="100%" cellpadding="0" cellspacing="2">
198
<td class='online-navigation'><a rel="prev" title="2.9.3 Propagating changes from"
199
href="node19.html"><img src='previous.png'
200
border='0' height='32' alt='Previous Page' width='32' /></A></td>
201
<td class='online-navigation'><a rel="parent" title="2.9 Proxies and Models"
202
href="node16.html"><img src='up.png'
203
border='0' height='32' alt='Up One Level' width='32' /></A></td>
204
<td class='online-navigation'><a rel="next" title="2.9.5 Using Signal Handlers"
205
href="node21.html"><img src='next.png'
206
border='0' height='32' alt='Next Page' width='32' /></A></td>
207
<td align="center" width="100%">Developing applications with Kiwi</td>
208
<td class='online-navigation'><img src='blank.png'
209
border='0' height='32' alt='' width='32' /></td>
210
<td class='online-navigation'><img src='blank.png'
211
border='0' height='32' alt='' width='32' /></td>
212
<td class='online-navigation'><img src='blank.png'
213
border='0' height='32' alt='' width='32' /></td>
215
<div class='online-navigation'>
216
<b class="navlabel">Previous:</b>
217
<a class="sectref" rel="prev" href="node19.html">2.9.3 Propagating changes from</A>
218
<b class="navlabel">Up:</b>
219
<a class="sectref" rel="parent" href="node16.html">2.9 Proxies and Models</A>
220
<b class="navlabel">Next:</b>
221
<a class="sectref" rel="next" href="node21.html">2.9.5 Using Signal Handlers</A>
225
<span class="release-info">Release 1.9.12, documentation updated on August, 2006.</span>
227
<!--End of Navigation Panel-->