[pygtk-web] 2009-09-18 Rafael Villar Burke <pachi rvburke com>
- From: Rafael Villar Burke <rvburke src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [pygtk-web] 2009-09-18 Rafael Villar Burke <pachi rvburke com>
- Date: Fri, 18 Sep 2009 11:40:02 +0000 (UTC)
commit c9e461453ca74a36b570deedcdc19e8daff7fa3b
Author: Rafael Villar Burke <pachi rvburke com>
Date: Fri Sep 18 13:39:30 2009 +0200
2009-09-18 Rafael Villar Burke <pachi rvburke com>
* articles/subclassing-gobject/*: Add article
* articles.src: direct broken link to local copy
ChangeLog | 5 +
articles.src | 2 +-
articles/subclassing-gobject/resources/1.png | Bin 0 -> 346 bytes
articles/subclassing-gobject/resources/2.png | Bin 0 -> 469 bytes
articles/subclassing-gobject/resources/3.png | Bin 0 -> 476 bytes
articles/subclassing-gobject/resources/4.png | Bin 0 -> 420 bytes
articles/subclassing-gobject/resources/5.png | Bin 0 -> 477 bytes
articles/subclassing-gobject/resources/6.png | Bin 0 -> 475 bytes
.../sub-classing-gobject-in-python.htm | 1315 ++++++++++++++++++++
9 files changed, 1321 insertions(+), 1 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 03f9e59..589170c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-09-18 Rafael Villar Burke <pachi rvburke com>
+
+ * articles/subclassing-gobject/*: Add article
+ * articles.src: direct broken link to local copy
+
2009-09-17 Rafael Villar Burke <pachi rvburke com>
* applications.src: Add Pyblassreport
diff --git a/articles.src b/articles.src
index c14dd93..c313554 100644
--- a/articles.src
+++ b/articles.src
@@ -214,7 +214,7 @@
<tr>
<td>Nov 2003</td>
- <td><a href="http://www.sicem.biz/personal/lgs/docs/gobject-python/gobject-tutorial.html">Sub-classing GObject in Python</a></td>
+ <td><a href="articles/subclassing-gobject/sub-classing-gobject-in-python.htm">Sub-classing GObject in Python</a></td>
<td>Lorenzo G. Sanchez</td>
</tr>
diff --git a/articles/subclassing-gobject/resources/1.png b/articles/subclassing-gobject/resources/1.png
new file mode 100644
index 0000000..4a7701f
Binary files /dev/null and b/articles/subclassing-gobject/resources/1.png differ
diff --git a/articles/subclassing-gobject/resources/2.png b/articles/subclassing-gobject/resources/2.png
new file mode 100644
index 0000000..8847720
Binary files /dev/null and b/articles/subclassing-gobject/resources/2.png differ
diff --git a/articles/subclassing-gobject/resources/3.png b/articles/subclassing-gobject/resources/3.png
new file mode 100644
index 0000000..fa004bb
Binary files /dev/null and b/articles/subclassing-gobject/resources/3.png differ
diff --git a/articles/subclassing-gobject/resources/4.png b/articles/subclassing-gobject/resources/4.png
new file mode 100644
index 0000000..7990d11
Binary files /dev/null and b/articles/subclassing-gobject/resources/4.png differ
diff --git a/articles/subclassing-gobject/resources/5.png b/articles/subclassing-gobject/resources/5.png
new file mode 100644
index 0000000..0db9f58
Binary files /dev/null and b/articles/subclassing-gobject/resources/5.png differ
diff --git a/articles/subclassing-gobject/resources/6.png b/articles/subclassing-gobject/resources/6.png
new file mode 100644
index 0000000..282df3a
Binary files /dev/null and b/articles/subclassing-gobject/resources/6.png differ
diff --git a/articles/subclassing-gobject/sub-classing-gobject-in-python.htm b/articles/subclassing-gobject/sub-classing-gobject-in-python.htm
new file mode 100644
index 0000000..b856eaa
--- /dev/null
+++ b/articles/subclassing-gobject/sub-classing-gobject-in-python.htm
@@ -0,0 +1,1315 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+
+
+
+ <meta http-equiv="content-type" content="text/html; charset=us-ascii" />
+
+ <title>Sub-classing GObject in Python</title>
+ <meta name="generator" content="DocBook XSL Stylesheets V1.58.1" />
+</head><body>
+ <div class="article" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h1 class="title"><a id="d0e1" name="d0e1">Sub-classing GObject in
+ Python</a></h1>
+ </div>
+
+ <div>
+ <h3 class="subtitle"><a id="d0e1" name="d0e1"><i>Or how to create
+ custom properties and signals with PyGTK</i></a></h3>
+ </div>
+
+ <div>
+ <div class="authorgroup">
+ <div class="author">
+ <h3 class="author"><a id="d0e1" name="d0e1">Lorenzo Gil
+ Sanchez</a></h3>
+ </div>
+ </div>
+ </div>
+
+ <div>
+ <div class="legalnotice">
+ <p><a id="d0e1" name="d0e1">This document is released under the
+ terms of the</a> <a href="http://www.gnu.org/copyleft/fdl.html" target="_top">FDL</a></p>
+ </div>
+ </div>
+
+ <div>
+ <div class="revhistory">
+ <table summary="Revision history" border="1" width="100%">
+ <tbody>
+ <tr>
+ <th colspan="2" align="left" valign="top"><b>Revision
+ History</b></th>
+ </tr>
+
+ <tr>
+ <td align="left">Revision 0.1.1</td>
+
+ <td align="left">29-10-2003</td>
+ </tr>
+
+ <tr>
+ <td colspan="2" align="left">
+ <p>Added gobject.SIGNAL_ACTION for key bindings stuff</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left">Revision 0.1.0</td>
+
+ <td align="left">05-10-2003</td>
+ </tr>
+
+ <tr>
+ <td colspan="2" align="left">
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p>Lots of typos fixed</p>
+ </li>
+
+ <li>
+ <p>New section: 'Overriding the class closure'</p>
+ </li>
+
+ <li>
+ <p>Lots of changes after the great review of Christian
+ Reis</p>
+ </li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left">Revision First Draft</td>
+
+ <td align="left">29-09-2003</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <hr />
+ </div>
+
+ <div class="toc">
+ <p><b>Table of Contents</b></p>
+
+ <dl>
+ <dt><a href="#d0e67">
+ Introduction</a></dt>
+
+ <dt><a href="#d0e93">
+ Advantages of subclassing GObject</a></dt>
+
+ <dt><a href="#d0e127">
+ Creating custom properties</a></dt>
+
+ <dt><a href="#d0e412">
+ Using the properties</a></dt>
+
+ <dt><a href="#d0e479">
+ Some warnings when using GObject properties in Python</a></dt>
+
+ <dd>
+ <dl>
+ <dt><a href="#d0e482">
+ Properties with long names</a></dt>
+
+ <dt><a href="#d0e530">
+ Subclassing other GObject derivates</a></dt>
+ </dl>
+ </dd>
+
+ <dt><a href="#d0e570">
+ Creating your own signals</a></dt>
+
+ <dt><a href="#d0e723">
+ Using your signals</a></dt>
+
+ <dt><a href="#d0e754">
+ Overriding the class closure</a></dt>
+
+ <dt><a href="#d0e821">
+ Bibliography</a></dt>
+ </dl>
+ </div>
+
+ <div class="abstract">
+ <p class="title"><b>Abstract</b></p>
+
+ <p>This document tries to explain the process of creating subclasses of
+ GObject, the base class of the GNOME framework, in Python.</p>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e67" name="d0e67">Introduction</a></h2>
+ </div>
+ </div>
+
+ <p><a href="http://www.gnome.org/" target="_top">GNOME</a> (GNU Network Object Model Environment) is a
+ project whose main goals are to create a complete, free and easy-to-use
+ desktop environment for users as well as a powerful application
+ development framework for software developers. As a result of this
+ second goal GNOME is based on a set of libraries which are very easy to
+ access from a large amount of programming languages.</p>
+
+ <p>The library most modules depend on is <a href="http://library.gnome.org/devel/glib/unstable/index.html" target="_top">GLib</a> which provides a lot of useful functionality
+ embedded and used in the GNOME framework; this document in particular
+ discussed the Object system defined in Glib that allow us to use Object
+ Orientation throughout the GNOME framework. The Glib library, as most of
+ the GNOME core libraries, is programmed in the C programming language,
+ which is not an Object Oriented language in the sense that it does not
+ contains the syntax and built-in types that are conventionally used when
+ programming in an Object Oriented way in other languages like C++, Java
+ or Python. But this does not mean that you can not program in an Object
+ Oriented way with C, it's only that you have to do some extra work. And
+ it's your lucky day, because GLib does most of this work for you.
+ <a href="http://library.gnome.org/devel/gobject/unstable/index.html" target="_top">GObject</a> is commonly known as the part of GLib that
+ provides the Object Oriented features that C lacks.</p>
+
+ <p>One of the nice things that GObject provides is a class mechanism
+ with the kind of things you are used to work within an Object Oriented
+ language like inheritance, polymorph-ism, interfaces and virtual
+ methods. But it also gives you a very powerful feature that allows you
+ to connect different objects in an asynchronous and independent way. Yes
+ I'm talking about signals. If all this is not enough for you, then let
+ me tell you that GObject also support introspection allowing some
+ programs (like GUI builders or debuggers) to know the properties of an
+ object.</p>
+
+ <p>But what if you are used to another programming language like Python
+ and you create GNOME applications using some of the GNOME bindings (like
+ <a href="http://www.pygtk.org/" target="_top">PyGTK</a>) but you still want to use some of those nice
+ features of GObject? Well, in that case, this article is for you.</p>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e93" name="d0e93">Advantages of subclassing GObject</a></h2>
+ </div>
+ </div>
+
+ <p><a id="d0e93" name="d0e93">You may wonder why not use Python's own
+ Object Oriented features to implement Object Oriented programs. And in
+ most of the situations you are probably right. But, as said before,
+ there are a few features of GObject, that are really useful when working
+ with the GNOME framework. These are:</a></p>
+
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p><span class="emphasis"><a id="d0e93" name="d0e93"><em>Signals.</em></a></span> <a id="d0e93" name="d0e93">This is a mechanism to communicate your program with its
+ environment (the user input and the Window Manager actions). But
+ what is really useful is that you can use signals to communicate
+ between different parts of your programs in a very modular manner.
+ Have you ever heard of the Model View Controller philosophy? Well,
+ let me tell you that signals make this possible in a very simple
+ way. We will talk about this later.</a></p>
+ </li>
+
+ <li>
+ <p><span class="emphasis"><a id="d0e93" name="d0e93"><em>Property
+ change notifications.</em></a></span> <a id="d0e93" name="d0e93">As you can guess, having callbacks that listen for
+ property changes is a nice feature that can make your design a
+ little bit cleaner.</a></p>
+ </li>
+
+ <li>
+ <p><span class="emphasis"><a id="d0e93" name="d0e93"><em>Property
+ introspection.</em></a></span> <a id="d0e93" name="d0e93">Sure,
+ you can have the same thing with <b>dir(MyClass)</b> but what if
+ you just want to get the properties, not the methods?</a></p>
+ </li>
+
+ <li>
+ <p><span class="emphasis"><a id="d0e93" name="d0e93"><em>Type
+ checking.</em></a></span> <a id="d0e93" name="d0e93">If you have a
+ boolean property and you want to avoid things like
+ <b>self.my_boolean_prop = 'foo'</b>, the GObject property system
+ can help you.</a></p>
+ </li>
+ </ul>
+ </div>
+
+ <p><a id="d0e93" name="d0e93">One more good thing about GObject
+ subclassing is that you can always use the normal Python Object Oriented
+ features at the same time you use the GObject features and things will
+ just work smoothly.</a></p>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e127" name="d0e127">Creating custom properties</a></h2>
+ </div>
+ </div>
+
+ <p><a id="d0e127" name="d0e127">So let's get some action and create our
+ first example. We are going to create a Car class with a <span class="emphasis"><em>fuel</em></span> property that indicates the amount of
+ fuel that our car has. This is the</a> <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/car1.py" target="_top">code</a></p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk <a id="co-imports" name="co-imports"><img src="resources/1.png" alt="1" border="0" />
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 class Car(gobject.GObject):
+ 6 __gproperties__ = { </a><a id="co-gproperties-dictionary" name="co-gproperties-dictionary"><img src="resources/2.png" alt="2" border="0" />
+ 7 'fuel' : (gobject.TYPE_FLOAT, # type
+ 8 'fuel of the car', # nick name
+ 9 'amount of fuel that remains in the tank', # description
+ 10 0, # minimum value
+ 11 60, # maximum value
+ 12 50, # default value
+ 13 gobject.PARAM_READWRITE) # flags
+ 14 }
+ 15
+ 16 def __init__(self):
+ 17 gobject.GObject.__init__(self) </a><a id="co-gobject-init" name="co-gobject-init"><img src="resources/3.png" alt="3" border="0" />
+ 18 self.fuel = 50
+ 19
+ 20 def do_get_property(self, property): </a><a id="co-do-get-property" name="co-do-get-property"><img src="resources/4.png" alt="4" border="0" />
+ 21 if property.name == 'fuel':
+ 22 return self.fuel
+ 23 else:
+ 24 raise AttributeError, 'unknown property %s' % property.name
+ 25
+ 26 def do_set_property(self, property, value): </a><a id="co-do-set-property" name="co-do-set-property"><img src="resources/5.png" alt="5" border="0" />
+ 27 if property.name == 'fuel':
+ 28 self.fuel = value
+ 29 else:
+ 30 raise AttributeError, 'unknown property %s' % property.name
+ 31
+ 32 gobject.type_register(Car) </a><a id="co-type-register" name="co-type-register"><img src="resources/6.png" alt="6" border="0" /></a>
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="calloutlist">
+ <table summary="Callout list" border="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#co-imports">
+ <img src="resources/1.png" alt="1" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>These are the standard imports you need to use when using
+ PyGTK</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#co-gproperties-dictionary">
+ <img src="resources/2.png" alt="2" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>The <tt>__gproperties__</tt> dictionary is a class property
+ where you define the properties of your cars. In our example
+ we just have one property, the <tt>fuel</tt>. The format to
+ define a property is the following:</p>
+
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p>The key is the name of the property, in our case,
+ <tt>fuel</tt>.</p>
+ </li>
+
+ <li>
+ <p>The value is a tuple which describe the property. The
+ number of elements of this tuple depends on its first
+ element but the tuple will always contain at least the
+ following items:</p>
+
+ <div class="itemizedlist">
+ <ul type="circle">
+ <li>
+ <p>The first element is the property's type. This
+ is the list of the possible types:
+ <tt>TYPE_BOOLEAN</tt>, <tt>TYPE_BOXED</tt>,
+ <tt>TYPE_CHAR</tt>, <tt>TYPE_DOUBLE</tt>,
+ <tt>TYPE_ENUM</tt>, <tt>TYPE_FLAGS</tt>,
+ <tt>TYPE_FLOAT</tt>, <tt>TYPE_INT</tt>,
+ <tt>TYPE_INT64</tt>, <tt>TYPE_INTERFACE</tt>,
+ <tt>TYPE_INVALID</tt>, <tt>TYPE_LONG</tt>,
+ <tt>TYPE_NONE</tt>, <tt>TYPE_OBJECT</tt>,
+ <tt>TYPE_PARAM</tt>, <tt>TYPE_POINTER</tt>,
+ <tt>TYPE_PYOBJECT</tt>, <tt>TYPE_STRING</tt>,
+ <tt>TYPE_UCHAR</tt>, <tt>TYPE_UINT</tt>,
+ <tt>TYPE_UINT64</tt>, <tt>TYPE_ULONG</tt>. If you
+ don't find the type you are looking for, you
+ probably want the <tt>TYPE_PYOBJECT</tt> type.</p>
+ </li>
+
+ <li>
+ <p>The second element is the property's nick name,
+ which is a string with a short description of the
+ property. This is generally used by programs with
+ strong introspection capabilities, like the
+ graphical user interface builder <a href="http://glade.gnome.org/" target="_top">Glade</a>.</p>
+ </li>
+
+ <li>
+ <p>The third one is the property's description or
+ blurb, which is another string with a longer
+ description of the property. Also used by <a href="http://glade.gnome.org/" target="_top">Glade</a> and similar programs.</p>
+ </li>
+
+ <li>
+ <p>The last one (which is not necessarily the
+ forth one as we will see later) is the property's
+ flags, which is a bitwise or'ed combination of the
+ following parameter flags:</p>
+
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p><tt>gobject.PARAM_CONSTRUCT</tt>: The
+ property will be set upon object
+ construction.</p>
+ </li>
+
+ <li>
+ <p><tt>gobject.PARAM_CONSTRUCT_ONLY</tt>:
+ The property will only be set upon object
+ construction.</p>
+ </li>
+
+ <li>
+ <p><tt>gobject.PARAM_LAX_VALIDATION</tt>:
+ Upon property conversion strict validation
+ is not required. In C if your property has
+ the <tt>TYPE_FLOAT</tt> type and you try to
+ set it with 10, GObject internally calls
+ g_param_value_convert() to get a float from
+ that constant unless this flag is used.</p>
+ </li>
+
+ <li>
+ <p><tt>gobject.PARAM_READABLE</tt>: The
+ property is readable.</p>
+ </li>
+
+ <li>
+ <p><tt>gobject.PARAM_WRITABLE</tt>: The
+ property is writable.</p>
+ </li>
+
+ <li>
+ <p><tt>gobject.PARAM_READWRITE</tt>: The
+ property is readable and writable. This is
+ the same as <tt>gobject.PARAM_READABLE |
+ gobject.PARAM_WRITABLE</tt></p>
+ </li>
+ </ul>
+ </div>
+
+ <p>Note that setting <tt>PARAM_CONSTRUCT*</tt>
+ without <tt>PARAM_WRITABLE</tt> will fail.</p>
+
+ <p>Actually, these flags are not working very well
+ in PyGTK and I have run into some problems while
+ working with them:</p>
+
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p>Setting the flag
+ <tt>gobject.PARAM_READABLE</tt> still let
+ you call the <tt>set_property()</tt> method
+ See the <a href="http://bugzilla.gnome.org/show_bug.cgi?id=121544" target="_top">bug number 121544.</a></p>
+ </li>
+
+ <li>
+ <p>The <tt>gobject.PARAM_CONSTRUCT</tt>
+ method does make GObject call your
+ <tt>do_set_property()</tt> method upon
+ object initialization but in a different
+ object instance!! See the <a href="http://bugzilla.gnome.org/show_bug.cgi?id=123891" target="_top">bug number 123891.</a></p>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </li>
+
+ <li>
+ <p>The absolute length of the tuple depends on the
+ property type (the first element of the tuple). Thus we
+ have the following situations:</p>
+
+ <div class="itemizedlist">
+ <ul type="circle">
+ <li>
+ <p>If the type is <tt>TYPE_BOOLEAN</tt>,
+ <tt>TYPE_ENUM</tt>, <tt>TYPE_FLAGS</tt> or
+ <tt>TYPE_STRING</tt>, the forth element is the
+ default value of the property.</p>
+ </li>
+
+ <li>
+ <p>If the type is <tt>TYPE_*CHAR</tt>,
+ <tt>TYPE_*INT*</tt>,<tt>TYPE_*LONG</tt>,
+ <tt>TYPE_FLOAT</tt> or <tt>TYPE_DOUBLE</tt>, the
+ forth element is the minimum accepted value, the
+ fifth element is the maximum accepted value and
+ the sixth element is the default value. This is
+ the case of our example.</p>
+ </li>
+
+ <li>
+ <p>If the type is <tt>TYPE_PARAM</tt>,
+ <tt>TYPE_BOXED</tt>, <tt>TYPE_POINTER</tt> or
+ <tt>TYPE_OBJECT</tt>, there are no additional
+ elements.</p>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#co-gobject-init">
+ <img src="resources/3.png" alt="3" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>Next thing you need to do is call the <tt>__init__</tt>
+ method of <tt>gobject.GObject</tt>. This call is used to
+ register your properties and signals. You also need to create
+ the appropriate Python instance members to hold your
+ properties. In this case we just need a <tt>fuel</tt> instance
+ variable.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#co-do-get-property">
+ <img src="resources/4.png" alt="4" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>When using GObject properties you need to define a method
+ called <tt>do_get_property</tt> which will be called for you
+ each time somebody tries to access one of your properties. All
+ you need to do is return the appropriate property.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#co-do-set-property">
+ <img src="resources/5.png" alt="5" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>You also need to define the <tt>do_set_property</tt>
+ method, that will be called when somebody tries to set one of
+ your property's value. GObject will make sure that the type of
+ the new value matches the type of your property and that the
+ value is in the appropriate range if this is needed (for char,
+ int, long, float and double types) before calling this
+ method.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#co-type-register">
+ <img src="resources/6.png" alt="6" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>Last thing you have to do is a call to
+ <tt>gobject.type_register</tt> with your class as the
+ argument. This call registers your class as an official GType
+ and it is absolutely necessary. Some people say that this is
+ not a very elegant solution but so far that's the way to do
+ it. The main problem is that this is a class initialization
+ process and not an instance initialization issue. That's why
+ it can not be implemented in the __init__() method. Maybe
+ using Python metaclasses can solve this in a nice manner.</p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e412" name="d0e412">Using the properties</a></h2>
+ </div>
+ </div>
+
+ <p><a id="d0e412" name="d0e412">You can use your brand new custom
+ properties as with any other regular property like the ones you find
+ using GTK+ Widgets. For those of you that don't know what I'm talking
+ about, here is a small example:</a></p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting">>>> from car1 import Car
+>>> aCar = Car()
+>>> print "The car has %f of fuel at the beginning" % aCar.get_property('fuel')
+The car has 50.000000 of fuel at the beginning
+>>> aCar.set_property('fuel', 20)
+>>> print "Now the car has %f of fuel" % aCar.get_property('fuel')
+Now the car has 20.000000 of fuel
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <p><a id="d0e412" name="d0e412">What I think is really useful is
+ connecting a callback to the <span class="emphasis"><em>notify</em></span> signal of a property. In the next</a>
+ <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/car2.py" target="_top">example</a> we will create a function that will check if
+ we are running out of fuel using the notify mechanism of GObject:</p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 from car1 import Car
+ 6
+ 7 def myCallback(obj, property):
+ 8 if property.name == 'fuel':
+ 9 if obj.get_property('fuel') < 10:
+ 10 print 'we are running out of fuel!!'
+ 11
+ 12 def test():
+ 13 aCar = Car()
+ 14 aCar.connect('notify', myCallback)
+ 15 aCar.set_property('fuel', 5.0)
+ 16
+ 17 if __name__ == '__main__':
+ 18 test()
+ 19
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <p>In this example, the <tt>myCallback</tt> function is called for
+ <span class="emphasis"><em>any</em></span> change in <span class="emphasis"><em>any</em></span> property of <tt>aCar</tt>. Suppose we
+ have 4 different properties in a <tt>Car</tt>, that's why we need the if
+ clause at the beginning of the callback.</p>
+
+ <p>Now we will <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/car4.py" target="_top">see in</a> another way of doing the same as in the
+ previous example but using a nice feature of GObject signal names:</p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 from car1 import Car
+ 6
+ 7 def myCallback(obj, property):
+ 8 if obj.get_property('fuel') < 10: <a id="one-less-if" name="one-less-if"><img src="resources/1.png" alt="1" border="0" />
+ 9 print 'we are running out of fuel!!'
+ 10
+ 11 def test():
+ 12 aCar = Car()
+ 13 aCar.connect('notify::fuel', myCallback) </a><a id="notify" name="notify"><img src="resources/2.png" alt="2" border="0" />
+ 14 aCar.set_property('fuel', 5.0)
+ 15
+ 16 if __name__ == '__main__':
+ 17 test()</a>
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="calloutlist">
+ <table summary="Callout list" border="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#notify">
+ <img src="resources/2.png" alt="2" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>Here we are connecting <tt>myCallback</tt> to the notify
+ signal of the object <tt>aCar</tt> but <span class="emphasis"><em>only</em></span> when the property changed is
+ <tt>fuel</tt>.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#one-less-if">
+ <img src="resources/1.png" alt="1" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>That's why we don't need to check if the property changed
+ is the <tt>fuel</tt> property.</p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e479" name="d0e479">Some warnings when using GObject properties in
+ Python</a></h2>
+ </div>
+ </div>
+
+ <div class="sect2" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h3 class="title"><a id="d0e482" name="d0e482">Properties with
+ long names</a></h3>
+ </div>
+ </div>
+
+ <p><a id="d0e482" name="d0e482">When naming a property with more than
+ one word you have to be careful with the character used to separate
+ the words. GObject translates all the underscore characters to hyphen
+ characters so if you have a property called <tt>background_color</tt>,
+ its internal and valid name will be <tt>background-color</tt>. The
+ places where you have to be careful about this are the
+ <tt>do_get_property()</tt> and <tt>do_set_property()</tt> methods and
+ the signal connection calls. Let's see an</a> <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/long-names.py" target="_top">example:</a></p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 class Style(gobject.GObject):
+ 6 __gproperties__ = { <a id="gproperties-long-names" name="gproperties-long-names"><img src="resources/1.png" alt="1" border="0" />
+ 7 'foreground_color' : (gobject.TYPE_STRING, 'foreground color',
+ 8 'string that represents the foreground color',
+ 9 'black', gobject.PARAM_READWRITE),
+ 10 'background_color' : (gobject.TYPE_STRING, 'background color',
+ 11 'string that represents the background color',
+ 12 'white', gobject.PARAM_READWRITE),
+ 13 }
+ 14
+ 15 def __init__(self):
+ 16 gobject.GObject.__init__(self)
+ 17 self.foreground_color = 'black' </a><a id="python-long-names" name="python-long-names"><img src="resources/2.png" alt="2" border="0" />
+ 18 self.background_color = 'white'
+ 19
+ 20 def do_get_property(self, property):
+ 21 if property.name == 'foreground-color': </a><a id="gobject-real-names" name="gobject-real-names"><img src="resources/3.png" alt="3" border="0" />
+ 22 return self.foreground_color
+ 23 elif property.name == 'background-color':
+ 24 return self.background_color
+ 25 else:
+ 26 raise AttributeError, 'unknown property %s' % property.name
+ 27
+ 28 def do_set_property(self, property, value):
+ 29 if property.name == 'foreground-color':
+ 30 self.foreground_color = value
+ 31 elif property.name == 'background-color':
+ 32 self.background_color = value
+ 33 else:
+ 34 raise AttributeError, 'unknown property %s' % property.name
+ 35
+ 36 gobject.type_register(Style)</a>
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="calloutlist">
+ <table summary="Callout list" border="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#gproperties-long-names">
+ <img src="resources/1.png" alt="1" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>See how we name our properties: we use underscores to
+ separate the words.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#python-long-names">
+ <img src="resources/2.png" alt="2" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>Note that in Python <tt>foreground-color</tt> is not a
+ valid name so we have to use <tt>foreground_color</tt>.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#gobject-real-names">
+ <img src="resources/3.png" alt="3" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>Here we see how GObject has transformed our names to its
+ internal names, which use hyphens instead of
+ underscores.</p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <p>Note that you can use long names like <tt>backgroundColor</tt>
+ (this means capitalizing the first letter of every word but the first
+ one) to avoid this problem.</p>
+ </div>
+
+ <div class="sect2" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h3 class="title"><a id="d0e530" name="d0e530">Subclassing other
+ GObject derivates</a></h3>
+ </div>
+ </div>
+
+ <p><a id="d0e530" name="d0e530">One very common thing you probably
+ want to do when using GTK+ is subclassing a widget (or any other
+ GObject subclass) and you should know one issue about this: If you
+ define custom properties or signals in your new class you can't call
+ the superclass <tt>__init__</tt> method in your <tt>__init__</tt>
+ method or it will overwrite your property definitions. You should call
+ the <tt>__gobject_init__</tt> method instead.</a></p>
+
+ <p><a id="d0e530" name="d0e530">This leads us to the next question:
+ <span class="emphasis"><em>what if I really need to call the
+ superclass's <tt>__init__</tt> method?</em></span> Well, then there is
+ a design bug either in your class, or in GTK+. Recently I created a
+ subclass of <tt>gtk.ListStore</tt> to make my custom
+ <tt>gtk.TreeView</tt> model. In C you can create an empty
+ <tt>GtkListStore</tt> and then you can add some columns to it with
+ another function call. But in Python there is no wrapper for this
+ function so you need to set the column types in the constructor for
+ <tt>gtk.ListStore</tt>. This means you can't define custom properties
+ in your own subclasses of <tt>gtk.ListStore</tt>. Don't worry about
+ this, there is already a</a> <a href="http://bugzilla.gnome.org/show_bug.cgi?id=123037" target="_top">bug report</a> in the PyGTK bugzilla and usually their
+ maintainers fix the bugs pretty fast.</p>
+ </div>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e570" name="d0e570">Creating your own signals</a></h2>
+ </div>
+ </div>
+
+ <p><a id="d0e570" name="d0e570">The other thing you probably want to use
+ when subclassing GObject is define custom <span class="emphasis"><em>signals</em></span>. You can create your own signals that
+ can be emitted so users of your class can connect to them.</a></p>
+
+ <p><a id="d0e570" name="d0e570">When a signal is emitted a set of
+ <span class="emphasis"><em>closures</em></span> will be executed. A
+ closure is an abstraction of the callback concept. A closure is the
+ callback itself (a function pointer), the user data (it will be the last
+ parameter to the callback) and another function for cleanup issues,
+ which will not be discussed in this document.</a></p>
+
+ <p><a id="d0e570" name="d0e570">For the sake of this article you don't
+ really need to know the difference between a callback and a closure so
+ both terms will be used. But be advised that this is not totally
+ correct.</a></p>
+
+ <p><a id="d0e570" name="d0e570">As we said before, when a signal is
+ emitted, a set of closures will be executed. One of them is the same one
+ for all the instances of this class and hence its name: the <span class="emphasis"><em>class closure</em></span>, and the other ones are custom
+ user callbacks. Note that not all the signals need to have a class
+ closure because it is optional.</a></p>
+
+ <p><a id="d0e570" name="d0e570">The GObject signal system is a very
+ flexible (and complex) one so you can change the order in which your
+ callback is executed very easily. Let's see the states in which a signal
+ goes so you can understand what you can do:</a></p>
+
+ <div class="orderedlist">
+ <ol type="1">
+ <li>
+ <p><span class="emphasis"><a id="d0e570" name="d0e570"><em>RUN_FIRST</em></a></span><a id="d0e570" name="d0e570">. If there is a class closure for this signal and it was
+ created with the <tt>SIGNAL_RUN_FIRST</tt> flag it is executed
+ now.</a></p>
+ </li>
+
+ <li>
+ <p><span class="emphasis"><a id="d0e570" name="d0e570"><em>HANDLER_RUN_FIRST</em></a></span><a id="d0e570" name="d0e570">. All the non blocked closures connected with the
+ <tt>GObject.connect</tt> family of functions are executed
+ now.</a></p>
+ </li>
+
+ <li>
+ <p><span class="emphasis"><a id="d0e570" name="d0e570"><em>RUN_LAST</em></a></span><a id="d0e570" name="d0e570">. If there is a class closure for this signal and it was
+ created with the <tt>SIGNAL_RUN_LAST</tt> flag it is executed
+ now.</a></p>
+ </li>
+
+ <li>
+ <p><span class="emphasis"><a id="d0e570" name="d0e570"><em>HANDLER_RUN_LAST</em></a></span><a id="d0e570" name="d0e570">. All the non blocked closures connected with the
+ <tt>GObject.connect_after</tt> family of functions are executed
+ now.</a></p>
+ </li>
+ </ol>
+ </div>
+
+ <p><a id="d0e570" name="d0e570">There are other states like
+ EMISSION_HOOK and RUN_CLEANUP which you can't use from Python so they
+ won't be explained here.</a></p>
+
+ <p><a id="d0e570" name="d0e570">I think this is enough theory for now so
+ let's jump into some real</a> <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/car4.py" target="_top">code</a>. We can use the signal concept to improve our car
+ class. We can have an <tt>engine-started</tt> signal that will be
+ emitted when the car's engine is started so other parts of the car can
+ connect to this signal and do something useful.</p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 class Car(gobject.GObject):
+ 6 __gproperties__ = {
+ 7 'fuel' : (gobject.TYPE_FLOAT, 'fuel of the car',
+ 8 'amount of fuel that remains in the tank',
+ 9 0, 60, 50, gobject.PARAM_READWRITE)
+ 10 }
+ 11
+ 12 __gsignals__ = { <a id="gsignal-dictionary" name="gsignal-dictionary"><img src="resources/1.png" alt="1" border="0" />
+ 13 'engine-started' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ 14 (gobject.TYPE_FLOAT,))
+ 15 }
+ 16
+ 17 def __init__(self):
+ 18 gobject.GObject.__init__(self)
+ 19 self.fuel = 50
+ 20
+ 21 def do_get_property(self, property):
+ 22 if property.name == 'fuel':
+ 23 return self.fuel
+ 24 else:
+ 25 raise AttributeError, 'unknown property %s' % property.name
+ 26
+ 27 def do_set_property(self, property, value):
+ 28 if property.name == 'fuel':
+ 29 self.fuel = value
+ 30 else:
+ 31 raise AttributeError, 'unknown property %s' % property.name
+ 32
+ 33 def do_engine_started(self, remaining_fuel): </a><a id="class-closure" name="class-closure"><img src="resources/2.png" alt="2" border="0" />
+ 34 print 'The engine is ready and we have still %f of fuel' % self.fuel
+ 35
+ 36 def start(self): </a><a id="sample-emit" name="sample-emit"><img src="resources/3.png" alt="3" border="0" />
+ 37 self.emit('engine-started', self.get_property('fuel'))
+ 38
+ 39 gobject.type_register(Car)</a>
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="calloutlist">
+ <table summary="Callout list" border="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#gsignal-dictionary">
+ <img src="resources/1.png" alt="1" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>The <tt>__gsignals__</tt> dictionary is a class property
+ where you define the signals of your car. In our example we
+ just have one signal, the <tt>engine-started</tt>. The format
+ to define a signal is the following:</p>
+
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p>The key is the name of the signal, in our case,
+ <tt>engine-started</tt></p>
+ </li>
+
+ <li>
+ <p>The value is a tuple which describes the signal and
+ has the following elements:</p>
+
+ <div class="itemizedlist">
+ <ul type="circle">
+ <li>
+ <p>The first one is the signal's flags, which
+ defines when the class closure of this signal will
+ be invoked. It can have the following values:</p>
+
+ <div class="itemizedlist">
+ <ul type="disc">
+ <li>
+ <p><tt>gobject.SIGNAL_RUN_FIRST</tt></p>
+ </li>
+
+ <li>
+ <p><tt>gobject.SIGNAL_RUN_LAST</tt></p>
+ </li>
+ </ul>
+ </div>
+
+ <p>See the signal's states above to understand
+ these constants. Note that no matter there are
+ four different signal states you can only set two
+ different flags here since these are the only
+ states that affect the <span class="emphasis"><em>class closure</em></span>, which is
+ what we are defining here. The other two states
+ are meaningful when working with user defined
+ callbacks</p>
+
+ <p>Note that usually
+ <tt>gobject.SIGNAL_RUN_LAST</tt> is more flexible
+ since it allows the users of your class to connect
+ callbacks that will be executed before or after
+ the class closure is executed. If you use
+ <tt>gobject.SIGNAL_RUN_FIRST</tt> your users will
+ only be able to connect callbacks that will be
+ executed after the class closure is executed.</p>
+
+ <p>There is another flag called
+ <tt>gobject.SIGNAL_ACTION</tt> which is useful is
+ you are trying to use key bindings with your
+ signal. For example if you want that everytime the
+ user press a key your signal is emitted, you need
+ to add this flag to the signal definition.</p>
+ </li>
+
+ <li>
+ <p>The second one is the type of the return value
+ of the signal. In our case it's
+ <tt>gobject.TYPE_NONE</tt> since the signal does
+ return nothing.</p>
+ </li>
+
+ <li>
+ <p>The third and last one is a tuple which
+ indicates the type of each parameter of the
+ signal. In our case we have a single parameter for
+ the signal which is of type float. As you can
+ guess, our signal will have the fuel property as
+ the first parameter.</p>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#class-closure">
+ <img src="resources/2.png" alt="2" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>This method is optional but if it exists it will be
+ executed when the class closure for our signal is executed. It
+ will be invoked each time the <tt>engine-started</tt> signal
+ is emitted and in the order we defined with the
+ <tt>gobject.SIGNAL_RUN_LAST</tt> parameter. The name of this
+ method starts with <span class="emphasis"><em>do_</em></span>
+ and then the name of the signal, with hyphens (which are
+ illegal in Python functions) converted to underscore
+ characters</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#sample-emit">
+ <img src="resources/3.png" alt="3" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>Here we provide a custom method to start the engine. It
+ emits the signal <tt>engine-started</tt> with the
+ <tt>fuel</tt> property as its only parameter</p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e723" name="d0e723">Using your signals</a></h2>
+ </div>
+ </div>
+
+ <p><a id="d0e723" name="d0e723">Now that we have our own signal we can
+ connect callbacks to it to make it a little bit more</a> <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/car5.py" target="_top">useful:</a></p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 from car4 import Car
+ 6
+ 7 def myCallback(obj, remaining_fuel, data=None): <a id="regular-callback" name="regular-callback"><img src="resources/1.png" alt="1" border="0" />
+ 8 print '***** Beginning of User callback *****'
+ 9 print 'The engine is starting and we still have %f of fuel' % remaining_fuel
+ 10 print '***** End of User callback *****'
+ 11
+ 12 def lastCallback(obj, remaining_fuel, data=None): </a><a id="last-callback" name="last-callback"><img src="resources/2.png" alt="2" border="0" />
+ 13 print '***** Callback connected with connect_after *****'
+ 14 obj.set_property('fuel', remaining_fuel - 10)
+ 15 print 'Now we have %f of fuel' % obj.get_property('fuel')
+ 16 print '***** End of this callback *****'
+ 17
+ 18 def test():
+ 19 aCar = Car()
+ 20 aCar.connect('engine-started', myCallback) </a><a id="callback-connection" name="callback-connection"><img src="resources/3.png" alt="3" border="0" />
+ 21 aCar.connect_after('engine-started', lastCallback)
+ 22
+ 23 aCar.start()
+ 24
+ 25 if __name__ == '__main__':
+ 26 test()</a>
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="calloutlist">
+ <table summary="Callout list" border="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#regular-callback">
+ <img src="resources/1.png" alt="1" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>This first callback will be invoked before the class
+ closure because our signal was created with the
+ <tt>RUN_LAST</tt> flag.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#last-callback">
+ <img src="resources/2.png" alt="2" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>This callback will be invoked after the class closure
+ because it will be connected with the <tt>connect_after</tt>
+ method.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#callback-connection">
+ <img src="resources/3.png" alt="3" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>These are the methods that we use to connect our callbacks
+ to the signal.</p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ <div class="sect1" xml:lang="en" lang="en">
+ <div class="titlepage">
+ <div>
+ <h2 class="title" style="clear: both;"><a id="d0e754" name="d0e754">Overriding the class closure</a></h2>
+ </div>
+ </div>
+
+ <p><a id="d0e754" name="d0e754">Now that you know what the class closure
+ is, you may want to override it. Suppose you want to subclass the
+ <tt>Car</tt> class with a <tt>LuxuryCar</tt> class and you want to do
+ something more when the engine is started. In this particular case when
+ you subclass a Python class with another Python class there is nothing
+ special with this. Let's see an</a> <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/luxurycar.py" target="_top">example:</a></p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gobject
+ 4
+ 5 from car4 import Car
+ 6
+ 7 class LuxuryCar(Car):
+ 8 def do_engine_started(self, remaining_fuel):
+ 9 Car.do_engine_started(self, remaining_fuel)
+ 10 print 'Welcome to the Luxury Car'
+ 11
+ 12
+ 13 if __name__ == '__main__':
+ 14 luxuryCar = LuxuryCar()
+ 15 luxuryCar.start()
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <p>Note that since you are not defining new properties or signals you
+ don't have to call <tt>gobject.type_register(LuxuryCar)</tt></p>
+
+ <p>But, what if you want to override the class closure of a GTK+ Widget?
+ The GTK+ library is written in C and most of the functions that
+ implement the class closure for the signals of the widgets are not
+ public. This among other consequences means that they are not accessible
+ to the PyGTK bindings.</p>
+
+ <p>Now suppose you want to create a special kind of <tt>gtk.Entry</tt>
+ that will not allow the user to paste anything into it. In the regular
+ <tt>gtk.Entry</tt> the class closure of the 'paste_clipboard' signal has
+ the function that handles the paste behavior. So our class need to
+ override this class closure. <a href="http://userpage.chemie.fu-berlin.de/%7Echrbecke/gobject-tutorial/evilentry.py" target="_top">This</a> is the code you need to write:</p>
+
+ <table bgcolor="#d9eefc" border="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <pre class="programlisting"> 1 import pygtk
+ 2 pygtk.require('2.0')
+ 3 import gtk
+ 4 import gobject
+ 5
+ 6 class EvilEntry(gtk.Entry):
+ 7 __gsignals__ = {
+ 8 'paste_clipboard' : 'override' <a id="signal-override" name="signal-override"><img src="resources/1.png" alt="1" border="0" />
+ 9 }
+ 10
+ 11 def __init__(self):
+ 12 gobject.GObject.__init__(self)
+ 13
+ 14 def do_paste_clipboard(self): </a><a id="new-class-closure" name="new-class-closure"><img src="resources/2.png" alt="2" border="0" />
+ 15 print "You tried to paste something but you can't!! muHAHAHA"
+ 16
+ 17 gobject.type_register(EvilEntry)
+ 18
+ 19 if __name__ == '__main__':
+ 20 win = gtk.Window()
+ 21 win.connect('destroy', lambda e: gtk.main_quit())
+ 22
+ 23 entry = EvilEntry()
+ 24 entry.show()
+ 25 win.add(entry)
+ 26 win.show()
+ 27
+ 28 gtk.main()</a>
+</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <div class="calloutlist">
+ <table summary="Callout list" border="0">
+ <tbody>
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#signal-override">
+ <img src="resources/1.png" alt="1" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>This time the value of this signal entry is the string
+ <span class="emphasis"><em>override</em></span>. This means we
+ are going to override the class closure of the
+ 'paste_clipboard' signal</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top" width="5%"><a href="#new-class-closure">
+ <img src="resources/2.png" alt="2" border="0" /></a></td>
+
+ <td align="left" valign="top">
+ <p>This will be the method that will be executed by the new
+ class closure. Its name is composed by do_ plus the signal
+ name.</p>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <p>Note that in this particular case you could have done the same thing
+ in another way: connect a callback to the 'paste_clipboard' signal and
+ call stop_emit_by_name in this callback. But you can do it only because
+ the 'paste_clipboard' signal is defined as a <tt>RUN_LAST</tt> signal
+ allowing the user callback code to be executed <span class="emphasis"><em>before</em></span> the class closure. What if the signal
+ is defined as <tt>RUN_FIRST</tt>? Then, there is no way to modify the
+ default behavior unless you override the class closure.</p>
+
+ <p>I know it's hard to find a good use of overriding the class closure
+ but you can find several ones of it looking in the <a href="http://diacanvas.sourceforge.net/" target="_top">DiaCanvas</a> library. This library is build in top of
+ GnomeCanvas and it's very useful if you want to draw diagrams. There is
+ a class called <tt>PlacementTool</tt> which is used when the user clicks
+ on the canvas and he/she is creating new items. You can override the
+ class closure of the 'button-press' and 'button-release' signals if you
+ want to do special things when creating items (as I needed to do some
+ time ago :)</p>
+ </div>
+
+ <div class="bibliography">
+ <div class="titlepage">
+ <div>
+ <h2 class="title"><a id="d0e821" name="d0e821">Bibliography</a></h2>
+ </div>
+ </div>
+
+ <div class="biblioentry">
+ <p><span class="author"><a id="d0e821" name="d0e821">Mathieu
+ Lacage.</a></span> <span class="title"><a id="d0e821" name="d0e821"></a><i><a href="http://www.le-hacker.org/papers/gobject/index.html" target="_top">The Glib Object system v0.8.0</a></i>.</span> (FIXME: dead link 2009-09-17)</p>
+ </div>
+
+ <div class="biblioentry">
+ <p><span class="author">Jan Weil.</span> <span class="title"><i><a href="http://www.daa.com.au/pipermail/pygtk/2003-August/005609.html" target="_top">PyGTK GObject Properties Mini HOWTO</a></i>.</span></p>
+ </div>
+
+ <div class="biblioentry">
+ <p><span class="author">The GTK+ guys.</span> <span class="title"><i><a href="http://library.gnome.org/devel/gobject/unstable/index.html" target="_top">GObject Reference Manual</a></i>.</span></p>
+ </div>
+
+ <div class="biblioentry">
+ <p><span class="author">James M. Cape.</span> <span class="title"><i><a href="http://ignore-your.tv/software/libgtcpsocket/docs/index.html" target="_top">GTcpSocket Library Manual</a></i>.</span> (FIXME: dead link 2009-09-17)</p>
+ </div>
+ </div>
+ </div>
+</body></html>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]