~gdesklets-desklet-team/gdesklets/0.36

« back to all changes in this revision

Viewing changes to doc/book/ctrl-write.xml

  • Committer: Robert Pastierovic
  • Date: 2007-10-07 10:08:42 UTC
  • Revision ID: pastierovic@gmail.com-20071007100842-fdvp2vzmqgh1j87k
merged 0.3x branch and basic documentation and some other changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<section id="ctrl-write" xmlns:xi="http://www.w3.org/2001/XInclude">
 
2
  <title>Writing Controls</title>
 
3
 
 
4
<section><title>Important Rules!</title>
 
5
 
 
6
  <para>Before you start publishing controls, please thoroughly read these
 
7
    rules. They make both your and the users' lives easier.</para>
 
8
 
 
9
  <orderedlist>
 
10
    <listitem>Before writing a new control, please check if the functionality
 
11
      you need has already been implemented by somebody else. There's no point
 
12
      in having two or more controls with different interfaces doing the same
 
13
      thing!</listitem>
 
14
 
 
15
    <listitem>If there already is a control doing what you want, but you want
 
16
      to make a more efficient implementation, please implement the interfaces
 
17
      of the other control to ensure backwards compatibility.</listitem>
 
18
 
 
19
    <listitem><emphasize>Never</emphasize> put applet-specific functionality
 
20
      into a control! Controls are meant to be shared among applets.</listitem>
 
21
 
 
22
    <listitem>Never publish a control without obeying rules 1 - 3!</listitem>
 
23
 
 
24
  </orderedlist>
 
25
 
 
26
</section>
 
27
 
 
28
 
 
29
 
 
30
<section><title>Anatomy of Controls</title>
 
31
 
 
32
  <para>Controls are Python classes derived from the <literal>Control</literal>
 
33
    base class and from the interfaces which they implement. The base class
 
34
    can be loaded from <literal>libdesklets.controls</literal>:</para>
 
35
 
 
36
  <programlisting>
 
37
from libdesklets.controls import Control
 
38
  </programlisting>
 
39
 
 
40
  <para>Each control has its own directory, which at least consists of the
 
41
    <filename>__init__.py</filename> file. That file initializes the control
 
42
    and provides a function <function>get_class()</function> returning the
 
43
    main class (not an instance of the class) of the control.</para>
 
44
 
 
45
  <para>The typical directory structure of a control looks like:</para>
 
46
  <programlisting>
 
47
MyControl/
 
48
  IMyInterface.py
 
49
  __init__.py
 
50
  </programlisting>
 
51
 
 
52
  <para>The control directory has to include all interface files from which the
 
53
    control inherits.
 
54
    By convention, the filenames of interface files start with an
 
55
    "<filename>I</filename>" to distinguish them from regular files.
 
56
    The file <filename>__init__.py</filename> is also mandatory. If neccessary,
 
57
    a control can also include other files as well, which are loaded by the
 
58
    initialization file. You should, however, keep in mind to design controls
 
59
    as generic as possible.</para>
 
60
 
 
61
</section>
 
62
 
 
63
 
 
64
<section><title>Deriving from Interfaces</title>
 
65
 
 
66
  <para>Every control implements one or more interfaces. Since an interface
 
67
    is a simple Python class, you just have to derive your control from the
 
68
    interface classes:</para>
 
69
 
 
70
  <programlisting>
 
71
from libdesklets.controls import Control
 
72
from IMyInterface import IMyInterface
 
73
 
 
74
class MyControl(Control, IMyInterface):
 
75
 
 
76
    def __init__(self):
 
77
 
 
78
        Control.__init__(self)
 
79
        ...
 
80
 
 
81
    ...
 
82
 
 
83
 
 
84
def get_class(): return MyControl
 
85
  </programlisting>
 
86
 
 
87
  <para>Because interfaces are implementation-less, there is no
 
88
    super-constructor to invoke for them.</para>
 
89
 
 
90
  <para>Always remember to derive from the <literal>Control</literal> class and
 
91
    to invoke its constructor to get a valid control class.</para>
 
92
 
 
93
</section>
 
94
 
 
95
 
 
96
 
 
97
<section><title>Implementing Properties</title>
 
98
 
 
99
  <para>Every property in the interfaces must be implemented by creating
 
100
    appropriate <literal>property</literal> objects.</para>
 
101
 
 
102
  <para>Python's <literal>property</literal> constructor takes four arguments,
 
103
    of which are all optional. From the Python inline help:</para>
 
104
 
 
105
  <programlisting><![CDATA[
 
106
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
 
107
 
 
108
# fget is a function to be used for getting an attribute value. Likewise,
 
109
# fset is a function for setting an attribute and fdel is a function for
 
110
# deleting an attribute.  Typical use is to define a managed attribute x:
 
111
class C(object):
 
112
    def getx(self): return self.__x
 
113
    def setx(self, value): self.__x = value
 
114
    def delx(self): del self.__x
 
115
    x = property(getx, setx, delx, "I'm the 'x' property.")
 
116
  ]]></programlisting>
 
117
 
 
118
  <para>The <literal>fdel</literal> argument is not needed for controls.
 
119
    If a property is not readable, you also omit the <literal>fget</literal>
 
120
    argument or set it to <literal>None</literal>. Likewise, for non-writable
 
121
    properties, omit the <literal>fset</literal> argument. The read-write
 
122
    permissions must match those
 
123
    <link linkend="ctrl-write-interface-declare">declared by the interfaces.</link>
 
124
    </para>
 
125
 
 
126
  <para>The <literal>doc</literal> argument can be used for describing the
 
127
    property in human-readable form. It is highly recommended to give a
 
128
    useful description for every property. Doing so makes it easier for
 
129
    others to use your control.</para>
 
130
</section>
 
131
 
 
132
 
 
133
 
 
134
<section><title>Methods of the Control Class</title>
 
135
 
 
136
  <para>The <literal>Control</literal> class provides you with all you need for
 
137
    writing compliant controls. The following methods can be used inside
 
138
    controls:</para>
 
139
 
 
140
  <informaltable frame="topbot">
 
141
  <tgroup>
 
142
 
 
143
  <thead>
 
144
    <row>
 
145
      <entry>Method Name</entry>
 
146
      <entry>Arguments</entry>
 
147
      <entry>Description</entry>
 
148
    </row>
 
149
  </thead>
 
150
 
 
151
  <tbody>
 
152
    <row>
 
153
      <entry valign="top">__init__</entry>
 
154
      <entry valign="top"></entry>
 
155
      <entry valign="top">The constructor of the <literal>Control</literal>.
 
156
        This always has to be called as the super-constructor within the
 
157
        constructor.</entry>
 
158
    </row>
 
159
    <row>
 
160
      <entry valign="top">_add_timer</entry>
 
161
      <entry valign="top">
 
162
        <para>interval: integer</para>
 
163
        <para>callback: function</para>
 
164
        <para>*args</para>
 
165
      </entry>
 
166
      <entry valign="top">This is a convenience function for adding a timeout
 
167
        handler which gets called after <literal>interval</literal> milliseconds.
 
168
        If the <literal>callback</literal> function returns
 
169
        <literal>True</literal>, the callback will be called again after the
 
170
        next timeout. This method returns an ID which can be used with
 
171
        <function>_remove_timer()</function> to remove the timer again.</entry>
 
172
    </row>
 
173
    <row>
 
174
      <entry valign="top">_remove_timer</entry>
 
175
      <entry valign="top">
 
176
        <para>ident: integer</para>
 
177
      </entry>
 
178
      <entry valign="top">Removes the timer with the given ID
 
179
        <literal>ident</literal>.</entry>
 
180
    </row>
 
181
    <row>
 
182
      <entry valign="top">_shutdown</entry>
 
183
      <entry valign="top"></entry>
 
184
      <entry valign="top">This is a hook method which can be overridden in
 
185
        order to perform cleanup operations before the control is being closed.
 
186
        </entry>
 
187
    </row>
 
188
    <row>
 
189
      <entry valign="top">_update</entry>
 
190
      <entry valign="top">
 
191
        <para>prop: string</para>
 
192
      </entry>
 
193
      <entry valign="top">Notifies observers of property <literal>prop</literal>
 
194
        that the value has changed. You have to call this method whenever
 
195
        a property which is watchable using
 
196
        <link linkend="ctrl-use-watch"><function>bind()</function></link>
 
197
        changes its value.
 
198
        Of course it does not make sense for all properties to be watchable.
 
199
        Always call this method <emphasize>after</emphasize> the change has
 
200
        actually taken place.</entry>
 
201
    </row>
 
202
 
 
203
  </tbody>
 
204
 
 
205
  </tgroup>
 
206
  </informaltable>
 
207
 
 
208
</section>
 
209
 
 
210
 
 
211
</section>