The Whole PyGTK FAQ

Search FAQ1 What's new2 FAQ index3 Whole FAQ4 Roulette5 Add entry6

Last changed on Thu Aug 10 11:52:51 2006 BRT

(Entries marked with ** were changed within the last 24 hours; entries marked with * were changed within the last 7 days.)


1. General information and availability


2. Changes from 1.2 to 1.3/2.0


3. Signal handling


4. Themes, fonts and styles


5. Basic Objects: GObject, GtkWidget and other critters


6. Widget subclasses and user signals: GObject


7. Labels: GtkLabel


8. Images: GtkImage, GtkPixmap, GdkPixbuf


9. Buttons: GtkButtons


10. Windows: GtkWindows and GtkDialogs


11. Menus: Gtk*Menu and Gtk*MenuItem GtkToolbar


12. Simple Containers: GtkBoxes, GtkTable, GtkFixed, GtkAlignment


13. Lists and Trees: GtkList/TreeView


14. Editables: GtkEntry, GtkCombo, GtkText, GtkSpinButton, GtkTextView


16. GtkOptionMenu, GtkComboBox, GtkComboBoxEntry


17. GtkNoteBook


18. GtkDrawingArea


19. Other widgets


20. The GTK Mainloop and Threading


21. Win32 and PyGTK


22. libglade


23. Miscellaneous questions


24. Deprecated List Widgets: GtkList, GtkCList, GtkCTree and others


1. General information and availability


1.1.367 What is PyGTK?

PyGTK (a.k.a python-gtk or gtk-python) is a set of bindings to the GTK+ user interface toolkit for the Python language. The main site to look for more information on these bindings is [www.pygtk.org]368 . There, new releases, news, reference docs, tutorials, applications built on top of it and other information can be found.

Python is an interpreted language with a very clean syntax, high-level data structures, dynamic typing, object oriented characteristics and generally acceptable performance. For more information on Python see [www.python.org]369

GTK+ is a graphical user interface toolkit, which includes user interface components (hereafter called by the usual name widgets) and a framework for handling events that are produced upon these components. For more information on GTK+ see [www.gtk.org]370

A binding is code (usually a library) that allows you to access functions that were coded in another language. In our case, GTK+ was written in C, and applications written in C can use native GTK+. For a Python program to be able to create applications using the GTK+ framework, a special library has to be used. This library is PyGTK.

Edit this entry371 / Log info372 / Last changed on Tue Oct 12 20:29:25 2004 by pachi (pachi-at-mmn-arquitectos-com)


1.2.373 Where can I get PyGTK?

The reference site to track PyGTK releases and news is [www.pygtk.org]374

That site's Downloads section has links to the proper sources for pygtk binaries and sourcecode. Anyhow, here there are some of those links:

Linux and Unix users can pick up the source code off the main site which is [ftp.gtk.org]375 .

If you would like to obtain the CVS version of the current stable code, you can check it out from cvs.gnome.org, module gnome-python/pygtk and tag gtk-gnome-1-2. See the question 1.3 for more information on how to use CVS to pull pygtk.

PyGTK has a number of optional dependencies you must have installed before compiling if you want to use them. For PyGTK2:

For PyGTK0.6:

Edit this entry387 / Log info388 / Last changed on Tue Oct 12 20:13:39 2004 by pachi (pachi-at-mmn-arquitectos-com)


1.3.389 How do I get the very latest PyGTK source code [from CVS]

PyGTK is kept in gnome CVS; instructions for accessing the repository are available from [developer.gnome.org]390 and the anonymous (no password)repository root is:

  :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome
The module name for PyGTK is "pygtk". The module name for gnome-python is "gnome-python", so to check it out, type:

  cvs -d :pserver:anonymous@anoncvs.gnome.org:/cvs/gnome co -d pygtk gnome-python/pygtk
Please note that there are currently a few lines of development of GTK+:

Please note that to use PyGTK you rely on recent code for GTK+ , GLib, atk, pango, Python 2.3. How recent exactly these dependencies need to be depends largely on the current target for the PyGTK development team. In general, CVS HEAD will use the latest CVS, but ask on the mailing list if problems arise.

Edit this entry391 / Log info392 / Last changed on Thu Aug 4 17:59:19 2005 by Johan Dahlin (johan-at-gnome-org)


1.4.393 What is the password to change and add FAQ entries?

Just email kiko@async.com.br394 , and I'll send you a message with the password. There are no special requirements or qualifications that you must have; basically, being willing and able to work on the FAQ entries is enough.

We only use the password to allow a minimum of control over FAQ changes, and you are of course invited to help maintain it.

Edit this entry395 / Log info396 / Last changed on Sat Jul 20 13:40:50 2002 by Christian Reis (kiko-at-async-com-br)


1.5.397 How do I get support for PyGTK [mailing lists, IRC]?

[www.pygtk.org]398 is the reference site for the PyGTK bindings and there you can find more help and resources.

The standard way to get some support is to join the PyGTK mailing list. You can sign up using a webform at [www.daa.com.au]399 The mailing list is searchable via Gmane: [news.gmane.org]400

We also run a channel for pygtk support on IRC. This channel is run on server irc.gnome.org and it's called #pygtk. Stop by and say hello once in a while.

If you want to check out existing bug reports for pygtk, you can use the query interface at [bugzilla.gnome.org]401 to query for bugs reported against the gnome-python module. I've added two links for easy queries here:

Open bugs (UNCONFIRMED, NEW or ASSIGNED): [bugzilla.gnome.org]402

All bugs ever reported: [bugzilla.gnome.org]403

Additional information and support is available from the Python GTK+/GNOME Wiki: [taoriver.net]404

Edit this entry405 / Log info406 / Last changed on Thu Oct 21 10:08:00 2004 by Christian Robottom Reis (kiko-at-async-com-br)


1.6.407 Eeek, I found a bug in PyGTK. Where do I report it?

Okay, you found a bug. The standard procedure is:

a) Test against the latest CVS version of PyGTK, if you can. This helps catch errors that have already been fixed but haven't migrated into a release. Remember to test against the CVS branch you are using (0.6.x versus 1.99.x).

b) If you are unsure it's a bug, make a request discussing it on the mailing list, or present it to the IRC channel.

c) File a new bug on the pygtk product at GNOME Bugzilla [bugzilla.gnome.org]408 Remembering the bug number will help when referencing the bug through email. Bugs make remembering problems a lot easier by making sure problems are uniquely identified in a simple and focused way.

Remember, a great deal of help can be provided by a good bug report. Including a testcase will make fixing MUCH easier, and if that's impossible, listing the exact steps to reproduce will help too.

d) If you can, write some code to fix the bug and attach a patch in the unified diff format against current CVS (cvs diff -urNp will do the job) to the bug reported. After the patch has been reviewed and approved by someone on the PyGTK developer team, it can be checked in to CVS -- usually a member of the team will check it in for you if you don't have a CVS account on cvs.gnome.org. The next release will include the fix.

More information on bugzilla, the bug tracking tool GNOME uses, can be found in the Using Bugzilla section of the Bugzilla manual: [www.trilobyte.net]409

Edit this entry410 / Log info411 / Last changed on Thu Feb 12 17:46:46 2004 by Christian Reis (kiko-at-async-com-br)


1.7.412 Where are the reference manuals?

John Finlay has done amazing work in producing a reference manual for PyGTK2. It's available at [www.moeraki.com]413 (I don't think there are printable versions available, but it's said to be possible to build a PDF file from the xml sources.).

The last html version of that manual (and a tarball) is always linked in the documents section on [www.pygtk.org]414

That has been for long a recurrent question in the mailing list, which is this FAQ was originally created.

The most complete functional reference for the GTK+ and GDK libraries lives at [www.gtk.org]415 , and it covers the native C bindings. The mapping from the C API to Python is quite straightforward, and the reference is actually quite thorough.

The source code contains examples that are quite helpful (specially testgtk.py, which includes many widgets and features) in the examples/ directory. The gtk.py file itself is a worthy reference (praise to Python's readability there) and many times will solve a prototype, api or parameter question.

There are automatically generated docs for pygtk2 available at: [www.gnome.org]416 While not always up to date or complete, they give an overview of the classes involved.

pygtk2 additionally includes docstrings for many of the classes and methods available; it will probably become the definitive reference material as it is easier to be kept up to date.

Edit this entry417 / Log info418 / Last changed on Tue Oct 12 20:36:40 2004 by pachi (pachi-at-mmn-arquitectos-com)


1.8.419 I need PyGTK/libglade compiled for [insert Unix OS here]!

Very basically, grab source from links in questions 1.2 or 1.3, and do a

 cd /usr/src/pygtk-0.9.9 # we wish :-)
 ./configure
 make 
 make install
For Redhat 7.1, James Henstridge himself said:

You may as well compile it yourself. Just make sure you have the python2-devel RPM installed on your system, along with the -devel rpms for gtk+, glib, and the other modules you want to be able to use. Then run the following commands:

  PYTHON=/usr/bin/python2 ./configure --prefix=/usr
  make
  make install

Edit this entry420 / Log info421 / Last changed on Thu Jan 31 19:53:53 2002 by kiko (kiko-at-async-com-br)


1.9.422 Are there any PyGTK tutorials available?

The official tutorials are hosted at [www.pygtk.org]423 -- there are both HTML versions and tarballs for download. This entry lists a few articles published, but there is a list kept better up to date at [www.pygtk.org]424

(People looking for a GObject tutorial should take a peek at FAQ 6.1436.)

Edit this entry437 / Log info438 / Last changed on Wed Jul 21 14:33:56 2004 by Christian Robottom Reis (kiko-at-async-com-br)


1.10.439 I have multiple copies of python but pygtk only works with one of them!

Python stores all its extension modules in a directory $(prefix)/lib/pythonX.Y where X.Y is the major and minor version of the release. This is to guard against changes to the Python C API between releases. As with all other extension modules, one version must be compiled for each python version.

If you built pygtk for one copy of python on your system (or if you are using packages from your distribution), it will probably not be available on the others.

You will probably need to build pygtk for the other python installations. To do this, set the PYTHON environment variable to the full path of the alternative python before running pygtk's configure script. For example to build pygtk for the python 2.x distributed with Red Hat 7.x, do the following:

  PYTHON=/usr/bin/python2 ./configure --prefix=/usr
  make
  make install

Edit this entry440 / Log info441 / Last changed on Wed Feb 13 12:47:48 2002 by James Henstridge (james-at-daa-com-au)


1.11.442 How do I extend PyGTK (or the art of wrapping)

In order to make a new wrapper for PyGTK, you can use this FAQ as a guideline or checklist. Don't miss out FAQ 6.3443 which has a link to an online article, additionally.

Let's call the library "foo" (how original)

1) foo.defs.

   h2defs.py /usr/include/foo-1.0/*.h > foo.defs
2) foomodule.c

3) foo.override

4) Makefile.am

  AUTOMAKE_OPTIONS=1.5

  INCLUDES = $(PYTHON_INCLUDES) $(FOO_CFLAGS)

  # foo module
  pyexec_LTLIBRARIES = foomodule.la
  foomodule_la_LDFLAGS = -module -avoid-version -export-symbols-regex initfoo
  foomodule_la_LIBADD = $(FOO_LIBS)
  foomodule_la_SOURCES = foomodule.c
  nodist_foomodule_la_SOURCES = foo.c
  foo.c: foo.defs foo.override
  CLEANFILES = foo.c
  EXTRA_DIST = foo.override

  .defs.c:
        (cd $(srcdir)\
         && $(PYTHON) codegen/codegen.py \
            --override $*.override \
            --prefix py$* $*.defs) > gen-$*.c \
        && cp gen-$*.c $*.c \
        && rm -f gen-$*.c

 ---
 Should be enough for you to get started
5) configure.in

  PKG_CHECK_MODULES(FOO, foo >= 1.2,,)
  AC_SUBST(FOO_CFLAGS)
  AC_SUBST(FOO_LIBS)
Finally, copy autogen.sh and hopefully you'll have most functions wrapped.

Eventually you'll have to wrap a few functions by hand, functions that the code generator cannot handle. Mostly functions with inout params (**) and GSList/GList parameters.

Edit this entry444 / Log info445 / Last changed on Mon Jun 28 11:34:07 2004 by Christian Reis (kiko-at-async-com-br)


1.12.446 Where can I find the API documentation ?

James Finlay has written an excellent API documentation for PyGTK and you'll be able to find them online at [www.pygtk.org]447 There are tarballs of the docs available at the same location.

Edit this entry448 / Log info449 / Last changed on Fri Jul 16 11:01:06 2004 by Christian Robottom Reis (kiko-at-async-com-br)


1.13.450 Where can I get gnome-python?

All versions of gnome-python are available from [ftp.gnome.org]451

Edit this entry452 / Log info453 / Last changed on Sat Dec 28 17:05:38 2002 by Christian Reis (kiko-at-async-com-br)


1.14.454 How do I compile pygtk or gnome-python from CVS?

You need the GTK+ 2.x libraries, as you'd expect (see FAQ 21.2455). There are three packages you want to build:

You should run

 ./autogen.sh
 make
 make install
in each of these, in that order. If you want to build from CVS, you might want to look at a build script. James recommends jhbuild (also in GNOME CVS).

If you want to install them to a separate prefix, eg if you don't have write access to /usr/local, use --prefix as an argument to autogen.sh or configure, eg:

  ./configure --prefix /home/user/prefix
And then, don't forget to set PYTHONPATH before running the program, eg:

  export PYTHONPATH=/home/user/prefix/lib/python2.3/site-packages
Then you can finally run your program.

For additional information on how to use configure, see the INSTALL file which is included in the source tarball or cvs.

Edit this entry456 / Log info457 / Last changed on Tue Nov 23 13:57:28 2004 by Johan Dahlin (johan-at-gnome-org)


1.15.458 How do I tell what version of PyGTK I'm running?

To find out the current version of PyGtk, use gtk.pygtk_version:

 >>> gtk.pygtk_version
 (2, 2, 0)
Or, if you'd like to find out the Gtk+ version, use gtk.gtk_version:

 >>> gtk.gtk_version
 (2, 4, 0)

Edit this entry459 / Log info460 / Last changed on Sat May 22 07:50:58 2004 by Johan Dahlin (johan-at-gnome-org)


1.16.461 I wrote a patch for PyGTK that fixes bug X, or implements feature Y, what do I do?

The best way to make sure your patch is reviewed and evaluated is to file a bug on Gnome's bugzilla server, specifying the gnome-python product, pygtk component. The link to file a new bug directly is here: [bugzilla.gnome.org]462

Patches should be sent in the unified diff format (the -u flag). A good set of flags is -urNp -- look up man cvs if you're curious. It's a good idea to produce the patch against the CVS version -- see FAQ 1.3463 for information on getting pygtk from CVS.

Patches sent to the mailing list may be reviewed and checked in, but they may also be deleted without reading when the maintainers are too busy. Use bugzilla to be on the safe side and make sure your work is not wasted.

Edit this entry464 / Log info465 / Last changed on Thu Feb 12 17:48:07 2004 by Christian Reis (kiko-at-async-com-br)


1.17.466 How do I search Bugzilla for PyGTK bugs

Go to [bugzilla.gnome.org]467 and in the Product box select 'pygtk'. You may then specify the version, OS and any other relevant information.

If I am trying to do a general query, it helps to "select all" in these boxes by clicking on the first entry and then shift clicking on the last entry. You may also want to activate all the 'Status' entries to see resolved bugs, etc.

Once you have configured all these parameters, go to the Text information section, enter your search terms in the Description or Summary boxes, and click 'Submit Query'.

Edit this entry468 / Log info469 / Last changed on Tue May 25 12:26:39 2004 by Johan Dahlin (johan-at-gnome-org)


1.18.470 My programs configure says: No package 'pygtk-2.0' found

That's because the configure script can't find the installed version of pygtk-2.0.

If you build pygtk on your own, from source, then you need to write the following before running the configure script:

  export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
Or, replace /usr/local with the prefix you installed pygtk to. /usr/local is however the default and most commonly used one.

If you did not install it from source then it means that you forgot to install the devel/dev package. For Red Hat based distributions (Fedora, SuSe, Mandrake etc) you need to install pygtk2-devel and for debian based distributions you need to install pythonX.Y-gtk2-dev, where X.Y stands for the python version you're using.

Edit this entry471 / Log info472 / Last changed on Tue Jun 1 11:26:34 2004 by Johan Dahlin (johan-at-gnome-org)


1.19.473 Is there a PyGTK for MacOS X?

While there is no native MacOS X support, PyGTK itself runs fine if you are using Apple's X11 server. If you are running Mac OS X 10.3 (Panther) or above X11 is available as an optional feature from the install CDs. In addition the X11 server can be downloaded from [www.apple.com]474 . Unfortunately Apple doesn't have an obvious link to the older versions for Mac OS X 10.2, but VersionTracker has a link: [www.versiontracker.com]475

You can get the gtk libraries under OS X via darwinports from [darwinports.opendarwin.org]476

Daniel Macks and Ben Hines <bhines at alumni dot ucsd dot edu> have also put work into making packages available via Fink on the unstable tree: GNOME at [fink.sourceforge.net]477 and pygtk 2 specifically at [fink.sourceforge.net]478

Edit this entry479 / Log info480 / Last changed on Mon Nov 22 10:03:38 2004 by Michael Twomey (micktwomey-at-gmail-com)


1.20.481 Can I use PyGTK to build closed-source applications?

PyGTK is licensed under the LGPL license so it's perfectly legal to build non-open-sourced applications; two examples of closed source applications that are built using PyGTK are WingIDE and Point2Play. Note however that the fact that the program will be written in Python does present challenges in distributing the software and restricting access to source code. Some information on this topic can be found at [www.experts-exchange.com]482 -- but also note that information on decompiling python bytecode can be found at [www.crazy-compilers.com]483

Edit this entry484 / Log info485 / Last changed on Fri Feb 25 11:30:55 2005 by Christian Reis (kiko-at-async-com-br)


1.21.486 Does PyGTK have timers?

The answer is yes! The function you are looking for is gobject.timeout_add()

See [nkour.blogspot.com]487 for a very easy example on how to use timers in PyGTK

Edit this entry488 / Log info489 / Last changed on Tue Jun 14 14:15:43 2005 by Nikos Kouremenos (kourem-at-gmail-com)


2. Changes from 1.2 to 1.3/2.0


2.1.490 How do I install PyGTK-2 and PyGTK-0 side by side in the same system?

It used to be that if you installed PyGTK-2 and PyGTK-0.x in a same version of Python, the applications that required PyGTK-0.x would stop working. This happened because Python would import PyGTK-2 preferentially, and the names of the modules are the same: 'gtk'.

(There are three different ways detailed to solve this problem, but I will not recommend methods 2 and 3 unless you are unable to upgrade to a version that supports method 1).

For PyGTK >= 0.6.10, gnome-python >= 1.4.3 or pygtk2 >= 1.99.13 ONLY! (See faq 2.5491)

(Note that RedHat 8.0 ships versions PRIOR to these, you will need to either upgrade the system packages, or use method 2 if you want to install PyGTK-0 and PyGTK-2 together on RH8.)

James has added to pygtk a mechanism that allows installation of both pygtk and pygtk2 to work side by side. This method should be transparent - you can install both versions and simply require one or the other for each program you need (the default being the one you install last), as per faq 2.4492. It is implemented by using a pygtk.pth file that indicates which is the default (which one `import gtk' uses) version.

Note that pygtk.pth only works if you use the *default python install path* - if you specify a --prefix to configure it will not work and you will *have to use method 2*!

You can install the two conflicting versions to a different prefix. When configuring pygtk2, use something like:

 ./configure --prefix=/usr/local/gtk2/
All pygtk2 files will be installed in this case to

 /usr/local/gtk2/lib/pythonX.Y/site-packages/
With X.Y replaced by the major and minor numbers in your python version. You will then need to adjust PYTHONPATH (or sys.path) to look at the correct version for the program you want to run. If it requires pygtk2, you could use something like:

 export PYTHONPATH=/usr/local/gtk2/lib/pythonX.Y/site-packages/:$PYTHONPATH

You can change PyGTK-2.x's module name to something else. Thomas Leonard has released a patched version that renames the module name to gtk2, available publically at [west.dl.sourceforge.net]493 See [rox.sourceforge.net]494 for more information. To use this version, change the first line of your PyGTK-2 programs from

 import gtk
to

 import gtk2 as gtk
This module is not up to date, however, and this is the least recommended method.

Edit this entry495 / Log info496 / Last changed on Wed Nov 6 15:54:29 2002 by Christian Reis (kiko-at-async-com-br)


2.2.497 What are the major changes in PyGTK-2 for GTK+ 2.2?

The new PyGTK-2 is not fully compatible with the old one. There are a few things you will need to do to convert your app:

 - GtkText (replaced by GtkTextBuffer/GtkTextView)
 - GtkTree and GtkTreeItem (replaced by GtkTreeView and GtkTreeModel)

Overall, PyGTK-2 should be a much nicer PyGTK to program with. If you are working on new code, it would be best to use PyGTK-2 instead of 0.6.x.

What's more, there is even some documentation for PyGTK-2, available at [www.gnome.org]498

Edit this entry499 / Log info500 / Last changed on Mon Jan 6 11:48:00 2003 by Florin Iucha (florin-at-iucha-net)


2.3.501 Is there a checklist of changes to migrate an application from PyGTK-0 to PyGTK-2?

Well, the start of one, thanks to LordVan ([www.lordvan.com]502 )

  import pygtk
  pygtk.require('2.0')
  import gtk
 * use import gtk instead
 * from gtk import *
 * s/mainloop/gtk.mainloop/g # and other functions calls like 'mainquit'
 * s/Gtk/gtk./g
 * s/Gtk//g
 -         win = GtkWindow(title="Foo bar baz")
 +         win = gtk.Window()
 +         win.set_title("Foo bar baz")
 -         label = GtkLabel(label="Foobar")
 +         label = gtk.Label("Foobar")
 -         self.text = GtkText()
 +         self.textbuffer = gtk.TextBuffer(None)
 +         self.text = gtk.TextView()
 +         self.text.set_buffer(self.textbuffer)

 -         self.text.insert_defaults( use_var )
 +         self.textbuffer.insert_at_cursor( use_var,len(use_var) )

  entry = gtk.Entry()
  font_desc = pango.FontDescription('monospace')
  entry.modify_font(font_desc)

  entry = gtk.Entry()
  entry.realize()
  win = entry.window

  drawingarea.window.draw_point()

 gc.set_clip_rectangle((x, y, width, height))

 option_menu=tree.get_widget("optionmenu1")
 sometext=option_menu.get_children()[0].get()

Edit this entry503 / Log info504 / Last changed on Mon Aug 2 11:17:40 2004 by Christian Robottom Reis (kiko-at-async-com-br)


2.4.505 If I installed PyGTK-0 and PyGTK-2 in parallel (using pygtk.pth) how do I indicate which one my script should use?

The new versions of PyGTK (see faq 2.1506) provide a pygtk module in which you can call a method require() that allows you to request one version or the other:

 pygtk.require("1.2") # for pygtk-0
and

 pygtk.require("2.0") # for pygtk2
Note that you should do this before importing the gtk or gnome modules:

 # To require 2.0 
 import pygtk
 pygtk.require("2.0")
 import gtk, gtk.glade, gnome, gnome.ui
or:

 # To require 1.2
 import pygtk
 pygtk.require("1.2")
 import gtk, libglade, gnome, gnome.ui
If this simply doesn't work, please visit FAQ 2.6507 for the nitty-gritty.

Edit this entry508 / Log info509 / Last changed on Thu Jan 2 16:50:53 2003 by Christian Reis (kiko-at-async-com-br)


2.5.510 Which versions of PyGTK support parallel install using the pygtk.pth method?

James Henstridge and Johan Dahlin implemented parallel install support in versions:

 - pygtk-0.6.10
 - gnome-python-1.4.3
 - pygtk2-1.99.13
So any version equal to or later than that is fine. Note that 0.6.10 and 1.4.3 had bugs in it, and you should upgrade to 0.6.11 and 1.4.4 if possible.

Note that these versions are more recent than the version shipped in RedHat 8.0, so RH8.0 does NOT support parallel install using method 1 described in faq 2.4511.

Edit this entry512 / Log info513 / Last changed on Sun Dec 7 22:53:45 2003 by Scott Tsai (scottt958-at-yahoo-com-tw)


2.6.514 FAQ 2.4 sucks and doesn't work. Truthfuly, how do I require a specific version of PyGTK (or When do I need to use pygtk.require())?

It depends (doesn't that always suck?).

If you installed pygtk to a non-standard directory (i.e., not in your python installation's site-packages directory), you will need to manually set pythonpath accordingly, and take care of python versions youself (checking pygtk_version, for instance). If you installed it into a standard directory, read below.

We have now a concept of a `default pygtk version'. This is the version that you get if you do a simple 'import gtk' in Python. Precisely which is the default version varies:

To *make sure* you get the right version, you can use:

  import pygtk
  pygtk.require("1.2") # or 2.0 etc
Which I recommend for maximum cross-site functionality. HOWEVER, not all versions of pygtk offer the pygtk module (again, see faq 2.5516). So to do the right thing, you need to wrap that in a try/except clause, and use a check for the previous versions. Something like the following should work if you want to make sure you have version 1.2:

 # Make sure we have version 1.2. Swap for 2.0 as necessary.

 def get_gtk():
   print """You need to get version 0.6 of PyGTK for this to work. You 
            can get source code from http://ftp.gnome.org/pub/gimp/gtk/python/v1.2/ """
   raise SystemExit

 try:
   import pygtk
   pygtk.require("1.2")
 except ImportError:
   try:
     import gtk   
   except ImportError:
     get_pygtk()
   if not hasattr(gtk, "GtkWindow"): # renamed in version 2.0
     get_pygtk()
 except AssertionError:
   get_pygtk()

  import gtk # we KNOW this is 1.2 at this point
  [...]
[The whole pygtk.pth handling has shown itself to be something of a mess, unfortunately, and a separate gtk2 namespace might have saved us some trouble, IMHO. - Kiko]

Edit this entry517 / Log info518 / Last changed on Thu Jan 2 16:54:39 2003 by Christian Reis (kiko-at-async-com-br)


2.7.519 What happened to the GTK and GDK constants/symbols?

The GTK_* constants have been mapped to gtk.* constants, and the GDK_* constants to gtk.gdk.*. The one caveat is that python identifiers can't start with a number. As is done in a few other Python extension modules, pygtk will prefix these constants with an underscore.

So GDK_2BUTTON_PRESS is wrapped as gtk.gdk._2BUTTON_PRESS, while GDK_BUTTON_PRESS is gtk.gdk.BUTTON_PRESS (no underscore).

One exception is the keysyms constants. They are accesed through gtk.keysyms.KEY. To see the legal values of KEY just do a

import gtk print dir(gtk.keysyms)

Edit this entry520 / Log info521 / Last changed on Tue Feb 4 17:01:21 2003 by Lorenzo Gil Sanchez (loren-at-fedro-ugr-es)


2.8.522 For some users import libglade (or GDK) is working and for some users it's not

It's possible that at the top of your script you have #!/usr/bin/env python as the script interpreter line. This searches the path for python, instead of hardcoding it to particular place, which is useful. However, some systems have been found with multiple versions of Python, one of which works with GTK1 and one of which only works with GTK2.

Figure out which one is working for your users, and change their script interpreter or path to use that one.

Edit this entry523 / Log info524 / Last changed on Tue Jan 7 16:56:51 2003 by Dave Aitel (dave-at-immunitysec-com)


2.9.525 FAQ 2.4, 2.6 and etc etc all suck. Python still doesn't find the version of pygtk I want.

Well, if all else fails:

 strace -eopen python <scriptname.py>
will let you know where python is looking for the pygtk files. Knowing that, you can tweak PYTHONPATH, --prefix, require() and other assorted nasties to get your versioning correct.

Don't write to the mailing list complaining, because we all know it's hard to make it work. You'll have to debug yourself. Next time complain when a solution that brings endless hassle to installers is implemented!

Edit this entry526 / Log info527 / Last changed on Thu Sep 23 02:30:49 2004 by Christian Robottom Reis (kiko-at-async-com-br)


2.10.528 How do I get my 1.2 gladefiles to work with 2.0?

James Henstridge says:

There is a program included with libglade 2.0.x called libglade-convert that will do a pretty good job at converting the interface file to the new format. You should be able to edit the file in glade 1.1 after that.

Dave notes that you will probably have to redo all your dialog boxes, since they are going to be converted without some of the GTK 2 things, such as the correct active area interface and GTK 2 button images. You'll also have to redo your trees and lists to conform with GTK 2. A moderately sized project will take around 8 hours to do this to. Even if you don't "make install" libglade 2.0.x, you can use the Python file included (but renamed) in the distribution.

Edit this entry529 / Log info530 / Last changed on Mon Mar 31 14:42:08 2003 by Dave Aitel (dave-at-immunitysec-com)


3. Signal handling


3.1.531 When I connect to a signal, my handler gets called but reports "XXX takes no arguments (1 given)"

Signal callbacks have specific signatures. This means that when a signal is emitted, it will send to the callback function a number of parameters. The first parameter is the widget which generated the event, and the rest vary depending on what signal is being emitted.

To handle a callback, your function signature, therefore, must take this into account. Often you don't even want to use any of the arguments, just trigger an action on a certain signal; an easy way to do this is using a variable argument list (*args) and ignoring them in your method:

  def on_win_delete(*args):
    print "Deleted, and who cares why"

  w = gtk.Window()
  w.connect("delete-event", on_win_delete)
If you are attaching to a method, be sure to provide the usual self in the method definition, and specifying self.on_foo_signal as the function to attach to.

Edit this entry532 / Log info533 / Last changed on Mon Nov 7 11:24:31 2005 by Johan Dahlin (johan-at-gnome-org)


3.2.534 How do I detect that a mouse or keyboard event has been triggered?

Q: I'm interested in writing a program similar to an x screen saver. It watches for user keystrokes, every time it receives one, it restarts a timer. How can I detect whenever the user hits a key or moves the mouse?

The correct way is to hook to some of the basic event signals and then act upon receiving them. The signals you want to look for are:

 - mouse motion
 - key presses
 - button presses
However, many widgets don't have their event masks properly set, so they will ignore these events. The following example shows how it should be done for a GtkWindow, adding the necessary event masks, and then hooking to the signals. Note that you would have to alter the wakeup function to handle the timer operations you would need for a screensaver.

 def wakeup(widget, event):
     print "Event number %d woke me up" % event.type

 w = gtk.Window()

 w.add_events(gtk.gdk.KEY_PRESS_MASK |
              gtk.gdk.POINTER_MOTION_MASK |
              gtk.gdk.BUTTON_PRESS_MASK | 
              gtk.gdk.SCROLL_MASK)

 w.connect("motion-notify-event", wakeup)
 w.connect("key-press-event", wakeup)
 w.connect("button-press-event", wakeup)
 w.connect("scroll-event", wakeup)

 w.show()

 gtk.main()
[Please note I don't really know how the scrollwheel works, and the event types it generates are wierd, but this code will work for the wheel spin too.]

Edit this entry535 / Log info536 / Last changed on Mon Nov 7 13:12:01 2005 by Johan Dahlin (johan-at-gnome-org)


3.3.537 I connected to some signals but nothing happens. Why?

There are a couple of issues here.

The first is that some GTK+ widgets do not by nature receive events of any nature - GtkLabel comes to mind as an example. (The technical reason behind this is that they do not have their own X window, but use the one belonging to their parent widget. An X window is not the same as a GTK+ window, mind you; X windows on Unix systems are wrapped by GDK's GdkWindow, which is a lower-level creature). These widgets are listed at [www.moeraki.com]538 , and discussed further in gtkmm's tutorial: [www.gtkmm.org]539 . If you want to receive events for one of these widgets, you should add a GtkEventBox around it, and listen for events on that box.

 l = gtk.Label("I want events.")
 e = gtk.EventBox()
 e.add(l)
 e.add_events(gtk.gdk.POINTER_MOTION_MASK)
 e.connect("motion-notify-event", handle_event)
Additionally, to receive signals, the widget's event mask must be set accordingly. In the answer to FAQ 3.2540, for instance, we had to adjust it to receive pointer motion events (among others) - if we didn't, motion_notify_event would never be emitted.

The event masks are defined in the gdk module; they are constants whose name ends in "_MASK". They map directly to X11 masks, and there is a reference to what each X11 mask is at [tronche.com]541

The functions that adjust the masks are:

 widget.set_events() 
and

 widget.add_events()
the second one only adding to the widgets mask, the first one in effect replacing the original mask (* though I believe the "factory supplied" mask is not replaced, but added to, even in the case of set_events()).

In the specific case of the key_press_event, the GTK+ event queue treats this signal specially to manage the widget keyboard focus.When it sees key events targetted at any subwindow within the toplevel, they are redirected to the toplevel GtkWindow. The key_press_event handler for the toplevel window checks to see if the key event corresponds to an accelerator/mnemonic (and activates the appropriate widget if so), or passes the key event on to the widget with focus. In short: if you want a global keyhandler, attach it to your application's GtkWindow(s).

Finally, understanding how the signal propagation system works is also helpful when you run into a tricky situation - you should check out FAQ 3.11542 which has more information on this.

Edit this entry543 / Log info544 / Last changed on Mon Nov 7 13:12:58 2005 by Johan Dahlin (johan-at-gnome-org)


3.4.545 I've fiddled with the mask but nothing happened. Why?

One common error is to confuse gdk event TYPEs with MASKs. The type number indicates precisely which gdk event was generated, but it is not directly related to the event mask:

<jamesh_> yeah. A number of the masks cover multiple events and some events are selected by different masks

All event mask constants end with _MASK, and that is a good rule to remember. When doing add_events, you do NOT want (see, no _MASK!):

 widget.add_events(gtk.gdk.MOTION_NOTIFY | gtk.gdk.BUTTON_PRESS)
This is the correct command:

 widget.add_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK)
(This example is particularly tricky because using BUTTON_PRESS will actually enable the pointer motion mask; this happens because the of the numeric constants used. Remember _MASK.)

Edit this entry546 / Log info547 / Last changed on Mon Nov 7 13:13:27 2005 by Johan Dahlin (johan-at-gnome-org)


3.5.548 Which widgets are unable to receive events or be styled?

In question 3.3, I said that certain widgets didn't have associated X windows, and for that reason were unable to handle events or be styled and coloured. These widgets are (add a Gtk in front if they look unfamiliar):

 Alignment
 AspectFrame
 Arrow
 Bin
 HBox
 VBox
 Frame
 Image
 Label
 Pixmap
 ScrolledWindow
 HSeparator
 VSeparator
 Table

Edit this entry549 / Log info550 / Last changed on Thu Feb 12 10:31:52 2004 by Christian Reis (kiko-at-async-com-br)


3.6.551 I attach a callback to a signal, but I keep getting an error: "TypeError: object of type X is not callable"

When connecting an event handler, you must provide the function name. A common mistake is to pass a call instead of the name. In other words, you should not add parenthesis after the function name.

 #
 # WRONG
 button = gtk.GtkButton(label="Quit")
 button.connect("clicked", gtk.main_quit())
As you can see, gtk.main_quit() is a call, not the function name. The correct way to do it would be:

 # RIGHT
 button = gtk.Button(label="Quit")
 button.connect("clicked", gtk.main_quit)
Always remember to use gtk.main_quit() instead of gtk.mainquit() since the last one is deprecated.

Edit this entry552 / Log info553 / Last changed on Mon Nov 7 13:15:05 2005 by Johan Dahlin (johan-at-gnome-org)


3.7.554 While my callback is executing, nothing is refreshed in the application windows!

If you have a long-running callback, or one that modifies the application windows during its execution, you will notice that the windows of your app freeze for the duration of the callback. This is by design: all gtk events (including window refreshing and updates) are handled in the mainloop, and while it has branched to process your callback, it can't handle window update events.Therefore nothing will happen in the application windows.

The trick here is to realize where your callback can take a while to return, or where it is dynamically changing the window contents, and add a section like this in the body of your callback handler:

 while gtk.events_pending():
   gtk.main_iteration(False)
This tells gtk to process any window events that have been left pending. If your handler has a long loop, for instance, inserting this snippet as part of the loop will avoid it hanging the window till the callback has finished.

More eloquently, in the words of the great Malcolm Tredinnick, 'this requires using what should be called "Secret Technique #1 For Making Your Application Look Responsive"(tm):

If you want to avoid freezes in your application while you are doing large amounts of work in the background, remember to call gtk.mainiteration() from time to time.'

Of course, if your callback has a single instruction that takes a long time to process, this isn't an option. There is no easy alternative to solve this problem, as far as I can see. Doug Quale remarks on how this applies even to idle_add()ed functions:

Idle functions are scheduled when gtk+ doesn't have any other work to perform, but gtk+ doesn't preempt them. Each idle function will run to completion once it's started.

Note that running a mainiteration inside an idle, io (input_add) or timeout handler is generally considered `a bad idea' because it doesn't work very well. If you really need to do so, check FAQ 20.1555.

Moreover if during the computation you want to lock the GUI (no operation can be performed) without making all the widget insensitive you can use the other secret tecnique called "Yeti"... [1]

 import gtk
 from time import sleep

 def response(widget, response_id):
     if response_id != gtk.RESPONSE_APPLY:
         gtk.main_quit()
     else:
         i=0
         n=1000

         progress = dialog.get_data("progress")
         progress.set_text("Calculating....")
         progress.grab_add()

         while i < n:
             sleep(0.005)
             progress.set_fraction(i/(n - 1.0))
             i += 1

             while gtk.events_pending():
                 gtk.main_iteration_do(False)

         progress.set_fraction(0.0)
         progress.set_text("")
         progress.grab_remove()

 dialog = gtk.Dialog("Modal Trick", None, 0, (gtk.STOCK_EXECUTE,  gtk.RESPONSE_APPLY, 
                         gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))

 dialog.connect("response", response)
 dialog.connect("destroy", gtk.main_quit)

 box = dialog.get_child()

 widget = gtk.CheckButton("Check me!")
 box.pack_start(widget, False, False, 0)

 widget = gtk.Entry()
 box.pack_start(widget, False, False, 0)

 adj = gtk.Adjustment(0.0, 0.0, 100.0, 1.0, 10.0, 0.0)
 widget = gtk.HScale(adj)
 box.pack_start(widget, False, False, 0)

 widget = gtk.ProgressBar()
 box.pack_start(widget, False, False, 0)

 dialog.set_data("progress", widget)

 dialog.show_all()
 gtk.main()
This way the GUI does not freeze and you cannot interact with widgets, if you like you can unlock one widget (e.g. you want to give the chance to block the long process) using gtk.grab_add() on that widget.

[1] [mail.gnome.org]556

Edit this entry557 / Log info558 / Last changed on Sat May 6 11:16:01 2006 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


3.8.559 I want my callback to execute, but not the default callback (or, how to I stop GTK from doing the default action when doing X)?

Many times, you are customizing behaviour of a widget, or changing a policy in GTK, and the default action it does it not what you want. To get around this, we rely on a fundamental point in GTK: that GTK, as well as applications, mainly uses signals to get things done in the interface.

The process to disable a default action is:

An example of this usage was reported by Graham Ashton. He had customized a keypress handler for a window, but every time the user triggered the Alt-arrow combination he was handling, the focus moved around between the widgets in the interface (as is the default behaviour).

The solution was simply calling window.emit_stop_by_name("key_press_event") and returning True.

Edit this entry560 / Log info561 / Last changed on Mon Nov 7 13:15:30 2005 by Johan Dahlin (johan-at-gnome-org)


3.9.562 When creating a new signal, how do I define one of the signal arguments as Python data?

[ pygtk 2.0 ]

When you add your signal using gobject.signal_new(), use gobject.TYPE_PYOBJECT as the type for the argument being passed in:

    gobject.signal_new("signal", ClassName,
                       gobject.SIGNAL_RUN_LAST,
                       gobject.TYPE_NONE,
                       (gobject.TYPE_PYOBJECT,))
And then you can emit the signal with Python objects:

    mydict = {}
    mydict["foo"] = "bar"
    class_instance.emit("signal", mydict)
And get them when you connect on the other side:

    def signal_cb(instance, mydict):
        print mydict["foo"]

    class_instance.connect("signal", signal_cb)

Edit this entry563 / Log info564 / Last changed on Wed Nov 6 16:12:30 2002 by Christian Reis (kiko-at-async-com-br)


3.10.565 How do I specify user data to a signal?

Easy:

 widget.connect("my_signal", handler, userdata [, ...])
As you can see, you can pass as many items as userdata; the function will receive the same number of user data arguments.

Edit this entry566 / Log info567 / Last changed on Wed Nov 6 16:10:43 2002 by Christian Reis (kiko-at-async-com-br)


3.11.568 How do signals and events propagate in GTK+?

Though there is a section on this in the GTK+ tutorial at [www.gtk.org]569 it doesn't clearly describe the difference in propagation behaviour between simple signals, events and keyboard events. James offers a more complete answer:

A single signal emission will only call handlers attached to the object it was emitted on. The propagation of events up the heirachy is acheived by emitting the signal a number of times.

For events such as the button presses and motion events, the event is delivered first to the widget the event occurred in. It will emit the appropriate event signal. If the event signal returns false (indicating that the event hasn't been handled), then a signal will be emitted on the parent. This continues all the way up to the toplevel if no one handles the event.

Keyboard events are handled differently. When your window receives a keyboard event, it is first dispatched to the toplevel window, which will check if it matches any keyboard shortcuts. If the key press doesn't match a shortcut, then the event is dispatched to the child widget that currently has focus.

Edit this entry570 / Log info571 / Last changed on Wed Nov 13 07:40:34 2002 by Christian Reis (kiko-at-async-com-br)


3.12.572 Why does handling expose events break drag-n-drop?

If you are calling

  queue_draw_area(x_beg, y_beg, x_end, y_end) 
in your expose_event handler, don't. It seems to break event propagation which causes drag and drop to not work any more.

Edit this entry573 / Log info574 / Last changed on Mon Aug 30 17:38:57 2004 by Christian Robottom Reis (kiko-at-async-com-br)


3.13.575 How do I pass extra data to a signal handler?

The signal connection methods connect() and connect_after() take an optional third parameter that can be used to supply extra data to a signal handler callback. Any Python object can be passed so you can use a list, tuple or dictionary if you want to pass multiple extra values. Since the signal handler function will receive the widget that emitted the signal as its first parameter, often it's convenient to pass a second related widget as the extra data.

Suppose you have a dialog with an entry widget. If you want the dialog response handler to do something with the entry value, you could connect to the response signal like this

     dialog.connect('response', on_dialog_response, entry)
This lets you easily access methods of the entry widget in the signal handler, perhaps to get the text in the entry

     def on_dialog_response(widget, response, entry):
         if response == gtk.RESPONSE.ACCEPT:
             print 'Accepting', entry.get_text()
Something that might trip you up especially if you are new to Python programming is that you probably don't want to try to pass the entry text to the signal handler like this

    # probably wrong!
    dialog.connect('response', on_dialog_response, entry.get_text())
The get_text() method is executed when the signal is connected so this would pass a constant value as the extra data. Usually you will want the signal handler to see the current state of the entry widget.

Edit this entry576 / Log info577 / Last changed on Mon Aug 30 20:35:12 2004 by Doug Quale (quale1-at-charter-net)


3.14.578 How to construct my own "fake" gtk.gdk.Event?

It's very easy. Let's go create a keypress event that is the same as if the user has pressed Ctrl+Enter:

 event = gtk.gdk.Event(gtk.gdk.KEY_PRESS)
 event.keyval = gtk.keysyms.Return
 event.state = gtk.gdk.CONTROL_MASK
 event.time = 0 # assign current time

 widget_that_should_accept_signal.emit('key_press_event', event)
the last line "passes" the signal to the widget we want to handle this fake event.

Edit this entry579 / Log info580 / Last changed on Tue Mar 14 21:09:13 2006 by Nikos Kouremenos (kourem-at-gmail-com)


4. Themes, fonts and styles


4.1.581 How do I change font properties on gtk.Labels and other widgets?

Easy:

 label = gtk.Label("MyLabel")
 label.modify_font(pango.FontDescription("sans 48"))
This method applies to all widgets that use text, so you can change the text of gtk.Entry and other widgets in the same manner.

Note that, some widgets are only containers for others, like gtk.Button. For those you'd have to get the child widget. For a gtk.Button do this:

  if button.get_use_stock():
     label = button.child.get_children()[1]
  elif isinstance(button.child, gtk.Label):
     label = button.child
  else:
     raise ValueError("button does not have a label")

Edit this entry582 / Log info583 / Last changed on Thu Sep 1 14:46:30 2005 by Johan Dahlin (johan-at-gnome-org)


4.2.584 Why don't my style changes apply only to the widget I requested it from?

Ricardo Lenzi writes:

get_style() returns an object what aways have the current style of widget. If you want to save an static style, use get_style().copy() instead:

 style = widget.get_style().copy()
This has some pretty odd effects. If you are creating a window with many gtk.Label's, for instance, and you alter the actual style object (not a copy() if it), all widgets will eventually change style (when they are redrawn by GTK+).

Edit this entry585 / Log info586 / Last changed on Thu Dec 16 13:13:23 2004 by Johan Dahlin (johan-at-gnome-org)


4.3.587 My user defined styles get overridden by the default theme!

Christian Storgaard said:

I have succesfully changed the bg colour of some buttons in my program by the use of styles. But..

As soon as my beautiful greenish colour has been painted onto the buttons, my default pixmap theme paints it over with it's gradient grey.

How do I stop this?!

I know I can stop it by choosing a different engine (like notif), but I want to use the default engine... See the prob?

XXX: NEEDS ANSWER

Edit this entry588 / Log info589 / Last changed on Thu Jan 31 21:22:29 2002 by kiko (kiko-at-async-com-br)


4.4.590 How do I change the background color of my application's dialog?

XXX: Use a gtkrc theme, or specify a style.

Edit this entry591 / Log info592 / Last changed on Sat Feb 9 14:47:25 2002 by kiko (kiko-at-async-com-br)


4.5.593 How do I use the style object?

Each widget has an associates style object that can be manipulted. The basic method is get_style(), which returns a GtkStyle object, and the associated set_style(style_object).

The style is shared between widgets of the same type (XXX: is this true?). To change the style of only one widget in your application, the style object offers a copy() method, which returns a new copy of the GdkStyle, which can me changed and set_style() back to the desired widget.

All attributes of a style can be get and set independently by direct access. The most important attributes of style are the colours (see faq 4.6594):

And the font and bg_pixmap attributes.

Edit this entry595 / Log info596 / Last changed on Thu Sep 12 00:14:50 2002 by Christian Reis (kiko-at-async-com-br)


4.6.597 How do I change the colour of a widget (or how do I get a GdkColor)?

Important! See also FAQ 4.16598.

There is some confusion about GdkColor and how it is created. There are both the GdkColor() class and colour_alloc() that seem to do the right thing, but they are both duds (as far as I can tell).

The right way of creating a colour is getting the colormap from the widget and using it to allocate a new colour using the GtkColorMap's alloc method:

 e = gtk.GtkEntry()
 map = e.get_colormap()
 colour = map.alloc_color("red") # light red
This way you end up with a red GdkColor in the variable colour. Apart from the X11 rgb.txt names, you can also use hex triplets:

 colour = map.alloc_color("#FF9999") # light red
See FAQ 4.8599 for more information on alloc_color.

The next step is understanding how to manipulate GtkStyle's colour attributes, which are actually dictionaries: each attribute maps a number of different gtk constants that indicate states:

So, to change the default border of our entry above to red:

 style = e.get_style().copy()
 style.bg[gtk.STATE_NORMAL] = colour
 e.set_style(style)
Final hint: the default colour for a GtkEntry background is gray84.

Edit this entry600 / Log info601 / Last changed on Sat Feb 4 04:41:20 2006 by John Pye (john-pye-at-student-unsw-edu-au)


4.7.602 How do I get a Graphics Context, or GdkGC?

Use the new_gc() method of GdkWindow (not GtkWindow, notice):

 gdkwin = widget.window
 gc = gdkwin.new_gc()
The widget must be realized. Then you are free to set the gc's background/foreground, etc. More information on the GdkGC is available at [www.moeraki.com]603

Edit this entry604 / Log info605 / Last changed on Mon Dec 5 20:43:16 2005 by László Monda (mondalaci-at-gmail-com)


4.8.606 How does the alloc() method to the GdkColormap work?

gdk.Colormap.alloc_color can take a number of formats:

 cmap = widget.get_colormap()
 color = cmap.alloc_color("#FFCCAA")
 color = cmap.alloc_color("red")
 color = cmap.alloc_color(0, 0, 65535)
Note that the third format uses a tuple to specify the individual values for Red, Green and Blue (RGB), each item being an integer from 0 to 65535 (corresponding, therefore, to 0x0-0xFF).

Complete reference documentation on GdkColormap is available at [www.moeraki.com]607

Edit this entry608 / Log info609 / Last changed on Thu Dec 16 13:04:16 2004 by Johan Dahlin (johan-at-gnome-org)


4.9.610 How do I use pango instead of GdkFont for font handling in a GtkDrawingArea?

Create a font description with pango. You will then need a pango layout for the text you want to display. You have to tell the layout which font description to use and draw it with the draw_layout() method instead of the draw_text() method.

 import pango

 # create a font description
 font_desc = pango.FontDescription('Serif 12')

 # create a layout for your drawing area
 layout = darea.create_pango_layout('hello pango!')

 # tell the layout which font description to use
 layout.set_font_description(font_desc)

 # draw the text with the draw_layout method
 darea.window.draw_layout(gc, x, y, layout)
You can find out about the size of the text by using the get_pixel_size() method from your pango layout object. e.g.:

 # get the pixel size of a layout
 text_width, text_height = layout.get_pixel_size()

Edit this entry611 / Log info612 / Last changed on Tue Jun 24 11:57:22 2003 by Christian Reis (kiko-at-async-com-br)


4.10.613 How can I use Unicode (or other format) strings in my PyGTK application, or, why do I get a UTF-8 warning when using a string?

If you application generates unicode strings, using them in PyGTK widgets without being transformed to UTF-8 will raise a warning:

 WARNING **: Invalid UTF8 string passed to pango_layout_set_text()
This indicates the error very clearly; strings passed into PyGTK widget methods (in fact, any method which uses pango to manipulate the string) must be converted to UTF-8 format. Luckily, this is trivial in Python using the unicode string object's encode() method:

  unistr = unicode("your iso 8859-15 text", "iso8859-15")
  utfstr = unistr.encode("utf-8")

Edit this entry614 / Log info615 / Last changed on Thu Jan 26 18:45:40 2006 by Patrick K. O'Brien (pobrien-at-orbtech-com)


4.11.616 How can I create a new pango context()

Q: How can I create a new, or copy an existing, pango context? I am currently using the context returned by widget.get_pango_context(), but I can't work out how to make a new one. If I use the one attached to the widget I have to restore everything after every use.

A: widget.create_pango_context() should give you a new one.

Note that pango.Context() doesn't work: PangoContext is really an abstract interface. There are currently context implementations for core X fonts (already removed from the HEAD branch), Xft, Win32 and freetype. Widget.create_pango_context() will create a context appropriate for use with that widget, so you don't need to worry about these details.

Edit this entry617 / Log info618 / Last changed on Wed Sep 17 12:32:43 2003 by Christian Reis (kiko-at-async-com-br)


4.12.619 How do I get antialiased fonts in GTK+?

The original core font rendering engine in XFree86 didn't support AA fonts. However, for GTK+ 2.0 onwards, the Xft font rendering backend can be used to render antialiased fonts. To select it using GTK+2.0, use:

 export GDK_USE_XFT=1 
It's on by default on 2.2 onwards, and in 2.4 the core engine is no longer used by GTK+.

Note that the Xft backend is much better at producing scaled versions of the fonts. The reason is that the core X font system, when you use scalable fonts, will render the entire set of glyphs as bitmaps at the requested size when you open the font (which isn't fast or a good use of memory -- it quite large for big point sizes or fonts with large coverage, such as with Asian fonts).

Edit this entry620 / Log info621 / Last changed on Wed Sep 17 13:03:57 2003 by Christian Reis (kiko-at-async-com-br)


4.13.622 Does PyGTK support TrueType fonts?

If your X server does, the answer is yes. X requires the freetype module be loaded to be able to handle TTF fonts, but all post-4.0 servers include the module by default.

Note that the way the font is rendered is handled by the rendering backend; see FAQ 4.12623 for more information.

Edit this entry624 / Log info625 / Last changed on Wed Sep 17 12:58:53 2003 by Christian Reis (kiko-at-async-com-br)


4.14.626 What units does pango use to define sizes and widths?

Pango uses a constant called pango.SCALE to convert between pixels and pango's native unit. You can use pango.PIXELS() to convert from the native unit back to pixels, or just divide.

Edit this entry627 / Log info628 / Last changed on Sat Oct 25 15:34:18 2003 by Christian Reis (kiko-at-async-com-br)


4.15.629 Can I find out how long (wide) a string is in a certain font?

In PyGTK2, you can use pango calls to find out how wide a string will be, using the pango context of the widget that contains (or that will contain) your text:

   context = widget.get_pango_context()
   metrics = context.get_metrics('font name, 12')
   width = pango.PIXELS(metrics.get_approximate_char_width() * n_chars)
(See FAQ 4.14630 to understand how PIXELS() works)

For a monospaced font, this should be quite accurate. You can then use widget.set_size_request() if you would like to set that width as the minimum width for the widget/view.

In PyGTK-0.6, you can ask the font directly how long a given string is going to be, as well as how high. Retrieve the font object from the style, and then query it with the string in question:

  font = widget.get_style().font

  h = font.height(my_string)
  w = font.width(my_string)
The methods return pixel counts. You can then set the size manually to any function of those parameters. For instance, to make a widget twice as wide and as high as the string you measured with, use:

  widget.set_usize(w*2, h*2)
[Credit: Andrew Reid <Andrew-dot-Reid-at-nist-dot-gov>]

Edit this entry631 / Log info632 / Last changed on Sat Oct 25 15:36:22 2003 by Christian Reis (kiko-at-async-com-br)


4.16.633 How do I change the background and colour of an Editable (GtkEntry, GtkTextView and friends)?

You must change the 'base' and 'text' parts of the widget's style. You can also edit the 'foreground' property. Some useful shorthand methods to change those style properties inherited from gtk.Widget are:

  widget.modify_fg(state, color)
  widget.modify_bg(state, color)
  widget.modify_base(state, color)
  widget.modify_text(state, color)
Windowless widgets such as gtk.Label, gtk.Button, gtk.Paned, gtk.Frame, etc, (see FAQ 3.5634) despite inheriting from gtk.Widget don't allow changing its background and base color as those properties don't exist for them. If you want to get them you need to insert the widget inside a gtk.EventBox which adds this properties. Example:

    import gtk

    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.connect("destroy", gtk.mainquit)

    label = gtk.Label("one, two, testing...")
    eb = gtk.EventBox()
    eb.add(label)
    eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))
    window.add(eb)

    window.show_all()
    gtk.main()

Edit this entry635 / Log info636 / Last changed on Mon Nov 7 13:19:02 2005 by Johan Dahlin (johan-at-gnome-org)


4.17.637 Why does FontSelection's set_font_name return False?

It needs to be added to a window before the font lists are populated.

  >>> w = gtk.Window()
  >>> f = gtk.FontSelection()
  >>> f.get_font_name()
  'Sans 10'
  >>> f.set_font_name('Sans 12')
  False
  >>> w.add(f)
  >>> f.set_font_name('Sans 12')
  True
Once added to the window, the result will indeed be True.

Edit this entry638 / Log info639 / Last changed on Mon Nov 7 13:19:16 2005 by Johan Dahlin (johan-at-gnome-org)


4.18.640 How do I change GtkMenubar.shadow_type (or other style properties)?

GtkMenubar.shadow-type and other style properties are read only. The only way you can change it is by passing in new rc strings. Something like this should do it:

    style "menubar-style" { 
        GtkMenuBar::shadow_type = etched-in 
    }

    class "GtkMenuBar" style "menubar-style"
In this case, possible shadow_types are:

  none, in, out, etched-in, etched-out
In general to find out what you can parse you have to check the enum, eg: [pygtk.org]641 s

Which can be passed on to gtk.rc_parse_string (or put in a file and then passed to gtk.rc_parse).

Edit this entry642 / Log info643 / Last changed on Sun Oct 31 12:30:00 2004 by Christian Robottom Reis (kiko-at-async-com-br)


4.19.644 Can I pass strings of unicode instance to gtk or do I need to convert them to utf8?

No you don't have do manually convert your strings in utf8. PyGTK will do this for you.

    label.set_text(u'abc')
So the above is indeed valid and not only to labels but to any widget.

Edit this entry645 / Log info646 / Last changed on Mon Nov 7 13:19:35 2005 by Johan Dahlin (johan-at-gnome-org)


5. Basic Objects: GObject, GtkWidget and other critters


5.1.647 I want to understand this "data" object that is used in the set_*_data() and get_*_data() calls.

The GObject methods set_data() and get_data() allow you to attach an arbitrary reference to a GObject (or any derived class) instance keyed by a string. In other words, you can attach any number of references to any GObject and retrieve them with the strings you set() them with. This is a very helpful but often overlooked feature of GTK+, and it can come in handy.

For example, you can attach to a GtkLabel the instance it represents and a list of of versions using the following code:

 l = gtk.Label()
 l.set_data("object-name", some_object)
and then retrieve the data using:

 >>> some_object = l.get_data("object-name")
There are also related methods associated with the CList/CTree, set/get_row_data(), and GnomeIconList's set/get_icon_data(). These methods don't index on string, but instead on position in their internal arrays.

Edit this entry648 / Log info649 / Last changed on Mon Nov 7 13:19:46 2005 by Johan Dahlin (johan-at-gnome-org)


5.2.650 How do I check if a widget is currently sensitive?

In pygtk, you get properties by calling the get_property() method:

  if widget.get_property('sensitive') == 0:
    print "I'm insensitive!"
Note: In ancient versions of pygtk (0.6.x) you could access them using a dictionary interface, this was removed in the 2.x series.

Edit this entry651 / Log info652 / Last changed on Tue Nov 16 15:02:49 2004 by Johan Dahlin (johan-at-gnome-org)


5.3.653 Where is get_state() in PyGTK 0.6.x?

James Henstridge points out that there is no get_state() function in gtk 1.2.

And therefore no way to wrap it in pygtk. There are actually a number of state constants defined in gtk:

 gtk.STATE_ACTIVE
 gtk.STATE_NORMAL
 gtk.STATE_SELECTED
 gtk.STATE_INSENSITIVE
 gtk.STATE_PRELIGHT     
but they are to be used with set_state(). In pygtk2, get_state() is implemented and wrapped.

Edit this entry654 / Log info655 / Last changed on Tue May 25 12:29:53 2004 by Johan Dahlin (johan-at-gnome-org)


5.4.656 How do I catch right-click, middle-click and double-click on my widget?

All widgets that receive events (see FAQ 3.3657) can attach to button_press_event to 'listen' for button presses. It may be necessary to alter the event mask for certain widgets (gtk.Window, for instance):

 window.add_events(gtk.gdk.BUTTON_PRESS_MASK)
You can easily capture a specific button press pattern by checking event.button and comparing event.type with the constants defined in gtk.gdk for multiple button presses. To do this, connect a handler like this one to "button_press_event" on your widget:

 def button_clicked(widget, event):
     # which button was clicked?
     if event.button == 1:
         print "left click"
     elif event.button == 2:
         print "middle click"
     elif event.button == 3:
         print "right click"

     # was it a multiple click?
     if event.type == gtk.gdk.BUTTON_PRESS:
         print "single click"
     elif event.type == gtk.gdk._2BUTTON_PRESS:
         print "double click"
     elif event.type == gtk.gdk._3BUTTON_PRESS:
         print "triple click. ouch, you hurt your user."
Note that it seems that, at least in PyGTK 0.6.x (confirm for 2.x), spawning a modal dialog when handling a double-click event causes a strange focus bug. I've experienced this personally, but this message confirms the problem: [mail.gnome.org]658 To work around it, I changed the modality using idle_add(win.set_modal, 1) before calling mainloop, but it's a very ugly fix.

Edit this entry659 / Log info660 / Last changed on Mon Nov 7 13:20:48 2005 by Johan Dahlin (johan-at-gnome-org)


5.5.661 How do I capture keypresses, and how do I perform a certain action depending on the key pressed?

You can capture the generic key_press_event in any widget that has the key press mask set or in the top level window that the widget is displayed in. Key events are sent to the top level window before they are sent to the child widget that currently is the focus widget. As a basic example:

 def on_key_press_event(widget, event):
   keyname = gtk.gdk.keyval_name(event.keyval)
   print "Key %s (%d) was pressed" % (keyname, event.keyval)

 w = gtk.Window()
 w.connect('key_press_event', on_key_press_event)
If you want to block a specific key from being catched by a widget, just return True in the key_press_event signal handler.

Which will print out the key pressed for that window. To use a specific handler for each key pressed, you can set something up like this:

  def on_key_press(self, widget, event):
    keyname = gtk.gdk.keyval_name(event.keyval)
    func = getattr(self, 'keypress_' + keyname, None)
    if func:
      return func()

  def keypress_A(self):
    print "A was pressed!"

  def keypress_B(self):
    print "B was pressed!"
To capture Control, Alt and Shift combinations, you need to use the gtk.gdk symbols CONTROL_MASK, MOD[1-5]_MASK and SHIFT_MASK and do a binary AND to event.state:

 def on_key_press(widget, event):
   keyname = gtk.gdk.keyval_name(event.keyval)
   print "Key %s (%d) was pressed" % (keyname, event.keyval)
   if event.state & gtk.gdk.CONTROL_MASK:
     print "Control was being held down"
   if event.state & gtk.gdk.MOD1_MASK:
     print "Alt was being held down"
   if event.state & gtk.gdk.SHIFT_MASK:
     print "Shift was being held down"

 w = gtk.Window()
 w.connect('key_press_event', on_key_press)

Edit this entry662 / Log info663 / Last changed on Tue Nov 16 15:09:08 2004 by Johan Dahlin (johan-at-gnome-org)


5.6.664 How do I change the cursor for a certain widget?

Changing the cursor is remarkably easy in pygtk:

To change it for a button,

 def realize_cb(widget):
   b.window.set_cursor(watch)

 b = gtk.Button()
 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 b.connect("realize", realize_cb)
And to change it back to normal:

 b.window.set_cursor(None)
To make an invisible cursor (aka hide the cursor), you can use this code:

 pix_data = """/* XPM */
 static char * invisible_xpm[] = {
 "1 1 1 1",
 "       c None",
 " "};"""
 color = gtk.gdk.Color()
 pix = gtk.gdk.pixmap_create_from_data(None, pix_data, 1, 1, 1, color, color)
 invisible = gtk.gdk.Cursor(pix, pix, color, color, 0, 0)

 b.window.set_cursor(invisible)
To change it for a label, which lacks its own gdk.Window, for instance:

 boat = gtk.gdk.Cursor(gtk.gdk.BOAT)

 b = gtk.EventBox()
 l = gtk.Label()
 b.add(l)
 b.window.set_cursor(boat)
Note that the widget may already define a cursor: for instance, GtkEntry defines an I-bar for the cursor. X allows you to set a cursor on each gdk.Window, and if a window doesn't have a cursor associated with it, it gets the parent window's cursor.

To change the cursor for all the widgets, you'd need to recurse into all child widgets and set_cursor() on their gdk.Windows. However, there seems to be a workaround that can be implemented using some gdk.Window functions. For details, read: [www.daa.com.au]666 (yes, that patch was checked in and those functions are available)

It is also worth noticing that some widgets are composed of multiple X windows. gtk.Entry is an example -- see FAQ 14.3667 (you can use the gdk.Window's children() method to get its child windows). Another example is TextView, described in FAQ 14.15668.

The constants for icons defined in gtk.gdk are:

 X_CURSOR            ARROW                BASED_ARROW_DOWN
 BASED_ARROW_UP      BOAT                 BOGOSITY
 BOTTOM_LEFT_CORNER  BOTTOM_RIGHT_CORNER  BOTTOM_SIDE
 BOTTOM_TEE          BOX_SPIRAL           CENTER_PTR
 CIRCLE              CLOCK                COFFEE_MUG
 CROSS               CROSS_REVERSE        CROSSHAIR
 DIAMOND_CROSS       DOT                  DOTBOX
 DOUBLE_ARROW        DRAFT_LARGE          DRAFT_SMALL
 DRAPED_BOX          EXCHANGE             FLEUR
 GOBBLER             GUMBY                HAND1
 HAND2               HEART                ICON
 IRON_CROSS          LEFT_PTR             LEFT_SIDE
 LEFT_TEE            LEFTBUTTON           LL_ANGLE
 LR_ANGLE            MAN                  MIDDLEBUTTON
 MOUSE               PENCIL               PIRATE
 PLUS                QUESTION_ARROW       RIGHT_PTR
 RIGHT_SIDE          RIGHT_TEE            RIGHTBUTTON
 RTL_LOGO            SAILBOAT             SB_DOWN_ARROW
 SB_H_DOUBLE_ARROW   SB_LEFT_ARROW        SB_RIGHT_ARROW
 SB_UP_ARROW         SB_V_DOUBLE_ARROW    SHUTTLE
 SIZING              SPIDER               SPRAYCAN
 STAR                TARGET               TCROSS
 TOP_LEFT_ARROW      TOP_LEFT_CORNER      TOP_RIGHT_CORNER
 TOP_SIDE            TOP_TEE              TREK
 UL_ANGLE            UMBRELLA             UR_ANGLE
 WATCH               XTERM                CURSOR_IS_PIXMAP
Also if you plan to do anything time consuming and want to use the watch cursor you have to be careful that you don't starve the gui thread before it can change the cursor, e.g.

 ## This Will Not Work ##
 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gtk_window.set_cursor(watch)
 time.sleep(10)             # your time consuming operation here
 gtk_window.set_cursor()
instead call the time consuming in an idle callback (or in a different thread if you absolutely have to)...

 def idle_cb(gtk_window):
    time.sleep(10)             # your time consuming operation here
    gtk_window.set_cursor()

 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gobject.idle_add(idle_cb, gtk_window)

Edit this entry669 / Log info670 / Last changed on Thu May 4 21:13:44 2006 by blaize (blaize-at-itee-uq-edu-au)


5.7.671 How can I tell my program that the cursor should jump to a specific widget?

If you have the name of the widget, simply call grab_focus() on it:

 entry = gtk.Entry()
 [...]
 entry.grab_focus()

Edit this entry672 / Log info673 / Last changed on Tue Nov 16 15:10:51 2004 by Johan Dahlin (johan-at-gnome-org)


5.8.674 What signal is triggered when I change a widget's sensitivity?

The state_changed signal is emitted, and the callback receives an extra parameter which is the previous state of the widget (this is apparently undocumented).

Edit this entry675 / Log info676 / Last changed on Thu Sep 19 22:04:09 2002 by Christian Reis (kiko-at-async-com-br)


5.9.677 How do I find out the size of a widget?

Use the GtkWidget's allocation attribute, which contains a geometry tuple. Note that the widget must be shown (you may get around calling only realize on that specific widget when using libglade):

  >>> win = gtk.Window()
  >>> win.realize() # or win.show()
  >>> rect = win.allocation
Would return a gdk.Rectangle, which can be accessed by using:

  >>> rect.width, rect.height, rect.x and rect.y
or just convert it to a four sized tuple:

  >>> t = tuple(rect)
Meaning the widget is at the top left of the window, and is 158x22 pixels in size (the default size of a gtk.Entry, by the way)

To find out how high or wide a widget is (or would be) based on a string size and a font, see FAQ 5.16678

Edit this entry679 / Log info680 / Last changed on Sat Feb 26 22:20:28 2005 by Nikos Kouremenos (kourem-at-gmail-com)


5.10.681 How do I focus a widget? How do I focus it before its toplevel window is shown?

Use the widget's grab_focus() method. Note that the widget must be added to a window or dialog before calling grab_focus, since (perhaps a bit unexpectedly) the focused widget is a property of a *toplevel window* and not its child widgets. In other words:

 e = gtk.Entry()
 e.show()
 e.grab_focus()
 w = gtk.Window()
 w.add(e) # oh-oh, added after grab_focus()
 w.show()
would NOT work, but

 e = gtk.Entry()
 w = gtk.Window()
 w.add(e)
 e.grab_focus() # called after add
 w.show_all() # no need for e.show() in this case
will work as expected (using idle_add() to call grab_focus() is naughty and we know that python hackers are never naughty :-P ).

Edit this entry682 / Log info683 / Last changed on Tue Nov 16 15:13:24 2004 by Johan Dahlin (johan-at-gnome-org)


5.11.684 My callback is getting a gtk.gdk.Event object, but I need an EventExpose!

Event is in fact a GdkEventExpose, it's just called gtk.gdk.Event to make things a bit easier for the code generator.Everything except the region member in the GdkEventExpose struct is wrapped. So you can access the event's area, for instance:

 event.area.x

Edit this entry685 / Log info686 / Last changed on Tue May 25 12:28:41 2004 by Johan Dahlin (johan-at-gnome-org)


5.12.687 How do I check if a widget is mapped? And realized? And visible? [...]

All gtkWidget's have a number of flags that indicate their state. PyGTK offers a method that can be used together with a number of gtk symbols to retrieve this state from the widget.

In PyGTK the method is called flags(), and it doesn't take arguments, so you must perform the binary AND yourself:

 # To check if `widget' is mapped:
 if widget.flags() & gtk.MAPPED:
    print "MAPPED!"
There are a number of flags you can test for. The following are defined in the gtk namespace:

 # gtk.Object
 DESTROYED
 FLOATING
 CONNECTED
 CONSTRUCTED

 # gtk.Widget
 TOPLEVEL
 NO_WINDOW
 REALIZED
 MAPPED
 VISIBLE
 SENSITIVE
 PARENT_SENSITIVE
 CAN_FOCUS
 HAS_FOCUS
 CAN_DEFAULT
 HAS_DEFAULT
 HAS_GRAB
 RC_STYLE
 COMPOSITE_CHILD
 BASIC
 APP_PAINTABLE
 RECEIVES_DEFAULT

Edit this entry688 / Log info689 / Last changed on Tue Nov 16 15:15:53 2004 by Johan Dahlin (johan-at-gnome-org)


5.13.690 While calling get_property(), I get an "invalid property id" warning. Why?

When using get_property(), you need to make sure the property you are using is not set as write-only. An example of such a property is GtkContainer::child, which isn't readable. The warning when trying to read it is something like:

  (:2640): Gtk-WARNING **: ../../gtk/gtkcontainer.c:874: invalid property
           id 3 for "child" of type `GParamObject' in `GtkButton'
Pretty much all instances of write-only properties in GTK are ones that set some other property, but take a different format. For instance, setting the "markup" property on a gtk.CellRendererText object is equivalent to setting the "text" and "attributes" properties to appropriate values, however "markup" is not readable.

The GtkContainer "child" property looks more like a convenience. Setting the property adds the widget to the container. However, GtkContainer can have multiple children, so it isn't clear what should be returned when reading it.

Edit this entry691 / Log info692 / Last changed on Fri Sep 19 19:49:33 2003 by Christian Reis (kiko-at-async-com-br)


5.14.693 How can I discover what properties and signals a GObject supports?

A GObject can support properties, which are used every now and them. They are quite useful for C programmers, since you don't need to do anything extra to make them available to language bindings. For gtk.Widget objects, they usually represent an internal state of some kind, for example the text of a widget, the padding of the border, etc.

There are several methods to find out what properties and signals are supported in a GObject. First of all, you have the two introspection methods, so for properties use this:

  >>> gobject.list_properties(obj)
and for signals:

  >>> gobject.signal_list_names(obj)
Where obj is an instance or a type, which has the disadvantage of not showing a description or other detailed information, but can be used by programs, like gui builders or others. A better method for programmers is the help() method.

  >>> help(obj)
Where obj also is an instance or a type, it gives you more detailed information.

If the type is in gobject, atk, pango, gdk or gtk, the reference manual is preferred, check it out here:

[www.pygtk.org]694

Edit this entry695 / Log info696 / Last changed on Tue Nov 16 15:33:31 2004 by Johan Dahlin (johan-at-gnome-org)


5.15.697 How do I access one of these properties in a GObject?

Use the get_property method:

  >>> w = gtk.Window()
  >>> w.set_title('My Window')
  >>> w.show_all()
  >>> print w.get_property('modal')
  False
  >>> print w.get_property('title')
  'My Window'

Edit this entry698 / Log info699 / Last changed on Tue Nov 16 15:26:39 2004 by Johan Dahlin (johan-at-gnome-org)


5.16.700 What's the difference between a property and an attribute?

In the Pygtk reference documentation there are a section for properties and another one for attributes for most of the widgets.

A property is a GObject property and can be read and write with the GObject.get_property (propname) and GObject.set_property (propname, value) methods.

An attribute is a mapping to the C struct of the GObject and can be read from and (sometimes) written to directly. For example:

 adj = gtk.Adjustment(value=0, lower=0, upper=100, step_incr=1, page_incr=10, page_size=10)
 adj.value = 4.0

Edit this entry701 / Log info702 / Last changed on Wed Dec 8 09:02:25 2004 by Gustavo Carneiro (gjc-at-inescporto-pt)


5.17.703 Do I need to handle reference counting for GObjects? What about for other objects in PyGTK/gnome-python?

At the Python level, all reference counting should be taken care of by PyGTK and gnome-python themselves; there is no need to ref()/unref() GObjects in python code. If you encounter a reference counting problem, most likely it is a bug in the code, with the following exception:

Note that while gnome-vfs objects are not based on GObject, and implement their own reference counting, it's the same from the point of view of Python code: nothing needs to be done. A significant difference in gnome-vfs objects is that they do not allow the programmer to add new attributes or subclass them. Also, they don't have reference cycles, so they are deallocated without help from the garbage collector.

Bonobo objects are GObject based, but they require manual reference counting. There are well defined rules for ownership semantics in remote calls: [developer.gnome.org]705 . However, for in-process bonobo API calls, there are no rules, and you have to be very careful with the ownership of the references obtained on a per API function basis. Unfortunately the API itself is underdocumented, so...

Edit this entry706 / Log info707 / Last changed on Thu Nov 18 13:13:02 2004 by Gustavo Carneiro (gjc-at-inescporto-pt)


5.18.708 Focusing a widget after when selecting an item from Treeview

The problem with selecting a widget when you click on a gtk.Treeview is that gtk.Treeview steals the focus back.

The solution is to add a timeout. This is how we do it:

    # Connect Treeview with cursor-changed signal
    treeview.connect("cursor-changed", self.timeoutFocus, focusme)

    # The callback function: 
    # focusme is the widget that will be focused
    def timeoutFocus(self,widget, focusme):
       gobject.timeout_add(10, lambda: focusme.grab_focus())
and that's all folks!

Edit this entry709 / Log info710 / Last changed on Mon Nov 7 13:21:52 2005 by Johan Dahlin (johan-at-gnome-org)


5.19.711 How can I listen to events from the scroll wheel on my mouse?

To listen for events that your scroll wheel sends you need to connect to the signal 'scroll-event'. The event structure has a direction attribute which will be one of:

  gtk.gdk.SCROLL_UP, 
  gtk.gdk.SCROLL_DOWN, 
  gtk.gdk.SCROLL_LEFT, 
  gtk.gdk.SCROLL_RIGHT
Example:

  def on_button_scroll_event(button, event):
    if event.direction == gtk.gdk.SCROLL_UP:
       print "You scrolled up"

  b = gtk.Button()
  b.connect('scroll-event', on_button_scroll_event)

Edit this entry712 / Log info713 / Last changed on Wed Feb 15 17:19:14 2006 by Johan Dahlin (johan-at-gnome-org)


6. Widget subclasses and user signals: GObject


6.1.714 What is the canonical reference on widget (and GObject) subclassing and property overriding?

Lorenzo Gil Sanchez wrote a killer document that explains the good, bad and ugly of subclassing GObject and defining your own signals and properties. It's currently available at [www.sicem.biz]715

Edit this entry716 / Log info717 / Last changed on Tue Jun 29 09:54:29 2004 by Christian Reis (kiko-at-async-com-br)


6.2.718 When subclassing a widget (or a GObject), why are the additional signals I define not usable?

When subclassing a GObject, make sure to call the constructor

  gtk.DrawingArea.__init__(self)
Note, that the old syntax (__gobject_init__) is deprecated and should not be used. Note, that gobject.GObject.__init__ should only be called if you subclass the actual gobject.GObject class.

If you get a "signal XXX cannot be used for action emissions" message, it's also likely that you missed adding gobject.SIGNAL_ACTIONS to the signal flags in the signal definition.

Read more about GObject subclassing in Lorenzo's tutorial at [www.sicem.biz]719

Edit this entry720 / Log info721 / Last changed on Tue Dec 6 11:29:57 2005 by Fabian Sturm (f-at-rtfs-org)


6.3.722 How do I wrap a GObject in Python?

If you'd like to use a GObject-derived class in your python programs, or just plain want to understand better how the pygtk2 wrapper works, Ross Burton wrote an excellent tutorial for IBM Developerworks that's available at [www-106.ibm.com]723

It takes you throught the steps of generating the wrapper, customizing and compiling it, and then using it from Python. See also FAQ 1.11724 for a walkthrough of the process.

Edit this entry725 / Log info726 / Last changed on Sat Mar 29 02:19:46 2003 by Christian Reis (kiko-at-async-com-br)


6.4.727 How can I draw on top of a subclassed widget?

Note, this is only accurate for PyGTK 2.6 or later.

First, subclass the type properly and make sure the constructor is chained to properly:

 class MyButton(gtk.Button):
    def __init__(self):
      gtk.Button.__init__(self)
Secondly, override the expose-event virtual method, it will be called as soon as the widget is asked to redraw it self

    def do_expose_event(self, event):
The first thing we want to do here, is to call the gtk.Button code, to draw something which looks like a button. It's simple, just chain up to the expose_event of the button itself:

     retval = gtk.Button.do_expose_event(self, event)
At this point, the button is drawn. Now you can make your own "drawings" on top of the widget.

    self.window.draw_ ....()
Finally return the same return value as we got from the parents call

    return retval
Don't forget to register the type:

 gobject.type_register(MyButton)

Edit this entry728 / Log info729 / Last changed on Mon May 23 14:31:08 2005 by Johan Dahlin (johan-at-gnome-org)


23.33.730 Using metaclasses in GObject subclasses.

When subclassing from a gtk.Object and a class which uses a metaclass this error will appear:

   TypeError: Error when calling the metaclass bases
       metaclass conflict: the metaclass of a derived class must be a  (non-strict) subclass of the metaclasses of all its bases
In order to correct this you have to do the following:

 class Foo:
     __metaclass__ = MetaFoo

 # This will throw an error
 class Bar(Foo, gtk.Object):
     pass

 # This will not throw an error
 class GMetaFoo(MetaFoo, gobject.GObjectMeta):
     pass

 class Bar(Foo, gtk.Object):
     __metaclass__ = GMetaFoo
So, you must create a new metaclass that extends both the metaclass gobject.GObjectMeta and the metaclass used in the other class.

Edit this entry731 / Log info732 / Last changed on Mon Nov 7 13:22:21 2005 by Johan Dahlin (johan-at-gnome-org)


7. Labels: GtkLabel


7.1.733 How can I use mnemonics for my GtkLabel?

Matt Wilson says:

 label = gtk.Label('_Change the above color') 
 label.set_property("use-underline", gtk.TRUE)

Edit this entry734 / Log info735 / Last changed on Tue May 25 12:30:49 2004 by Johan Dahlin (johan-at-gnome-org)


7.2.736 Where is GtkLabel.get_text()?

I don't know why the API is inconsistent, but the GtkLabel provides the method get() instead of get_text().

 l = gtk.GtkLabel("foobar")
 print l.get() # prints "foobar"
In PyGTK-2 you can use get_text() method:

 >>> l = gtk.Label("foobar")
 >>> print l.get_text()
 foobar
 >>> 
and also get() method still works:

 >>> print l.get()
 foobar

Edit this entry737 / Log info738 / Last changed on Fri Dec 31 13:50:22 2004 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


7.3.739 How do I make a GtkLabel font larger or bold?

If you are using pygtk-0, you need to load a different font (using the XLFD and load_font()) and set that font to your label:

 bold =  "-adobe-helvetica-bold-r-normal-*-*-120-*-*-p-*-iso8859-1"
 big  =  "-adobe-helvetica-medium-r-normal-*-*-180-*-*-p-*-iso8859-1"

 s = label.get_style().copy()
 font = gtk.load_font(bold) # or big if you want big.
 s.font = font
 label.set_style(s)
If you are using pygtk-2, this is much easier, using pango. You can do things like:

 label.set_use_markup(gtk.TRUE)
 # weights
 label.set_markup('normal text, <b>bold text</b>, <i>italic text</i>')
 # size; 38000 = 38pt (use pt size * 1000)
 label.set_markup('<span size="38000">big text</span>, normal text')
or even:

 label = gtk.Label("<b>N</b>ame")
 label.set_use_markup(True)
See [developer.gnome.org]740 for more information on pango's span attributes.

Edit this entry741 / Log info742 / Last changed on Thu Feb 19 13:30:37 2004 by Christian Reis (kiko-at-async-com-br)


7.4.743 How do I left, center, right, top, bottom, middle align a GtkLabel?

The GtkLabel has a justification attribute, but it only applies to *multi-line* labels. To change the position of a single-line label you should change it's alignment.

Use the label's set_alignment feature, which already does everything for you:

 l = gtk.Label("Text goes here")
 l.set_alignment(xalign=1, yalign=0.5) 
If you are using Glade, the labels already come with presets of xalign=0.5, yalign=0.5, and they can be changed in the widget tab of the properties dialog.

Edit this entry744 / Log info745 / Last changed on Mon Nov 7 13:23:20 2005 by Johan Dahlin (johan-at-gnome-org)


7.5.746 How do I change a Label's background color, or why doesn't my Label receive any signals?

As GtkLabels don't have their own X window (see FAQ 3.3747 and FAQ 3.5748) they use their parent's window to draw on and receive events. That means it's not possible for GtkLabel to have a different background property or to handle events separately from those of the parent window.

This also happens to other windowless widgets.

If you want to provide such features to a label (or windowless widgets) you need to add the label to a gtk.EventBox in order to assign it a window and thus have some more properties (such as background) and the ability to catch its own signals.

You can even nest gtk.EventBoxes, with some border width, to get colored frames.

See FAQ 4.16749 for an example

Edit this entry750 / Log info751 / Last changed on Thu Mar 4 21:43:29 2004 by Rafael Villar Burke (pachi-at-mmn-arquitectos-com)


7.6.752 [pygtk2] How do I render a label in a button or menuitem with an underscore in its label?

Normally an underscore in a button label (set using something like the following)

 gtk.Button("_New order")
will underline the character "N", and will set an accelerator for the N key. If you want to literally print an underscore, use either double underscores:

 gtk.Button("Foo__bar")
or set_use_underline(0):

 button = gtk.Button("Foo_bar")
 button.set_use_underline(0)
The same approach works as expected for menuitems. There is GTK+ documentation covering this at [developer.gnome.org]753

(The question remains of why would you want to do such a thing.)

Edit this entry754 / Log info755 / Last changed on Thu Mar 25 13:27:10 2004 by Christian Reis (kiko-at-async-com-br)


7.7.756 I set my labels to use_markup in glade-2. Why don't they markup the contents I set?

Marking up the contents of a label is a bit tricky. There are two things to wrap your head around:

 label.set_property("use-markup", False)
 label.set_property("label", "foo")
while label.set_markup("<i>bar</i>") is roughly equivalent to:
 label.set_property("use-markup", True)
 label.set_property("label", "<i>bar</i>")

Edit this entry757 / Log info758 / Last changed on Thu Nov 18 09:08:32 2004 by Gustavo Carneiro (gjc-at-inescporto-pt)


7.8.759 How can I change the behavoir of a label without using pango markup?

You can set the property "attributes" of gtk.Label:

here is a little example:

 import gtk
 import pango
 w = gtk.Window()
 w.connect("destroy", lambda w: gtk.main_quit())
 l = gtk.Label("some VERY_BOLD ITALIC text")
 k = gtk.Label("some normal text")
 PLIST = pango.AttrList()
 BOLD = pango.AttrWeight(pango.WEIGHT_HEAVY, 0, -1)
 ITALIC = pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)
 PLIST.insert(BOLD)
 PLIST.insert(ITALIC)
 l.set_property("attributes", PLIST)
 v = gtk.VBox()
 v.pack_start(l)
 v.pack_start(k)
 w.add(v)
 w.show_all()
 gtk.main()
You first create a pango.AttrList filled by all the attributes you want to change, then you apply it on the "attributes" property.

Edit this entry760 / Log info761 / Last changed on Mon May 9 15:49:01 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


8. Images: GtkImage, GtkPixmap, GdkPixbuf


8.1.762 How do I load a pixmap from a file into my application UI?

Follow the sample program:

 from gtk import *
 w=GtkWindow()
 pix, mask=create_pixmap_from_xpm(w, None, "logo.xpm")
 mypixmap=GtkPixmap(pix,mask)
 w.add(mypixmap) 
 w.connect("destroy", mainquit)
 w.show_all()
 mainloop()
If you want to change the current image of a GtkPixmap use:

 pix, mask=create_pixmap_from_xpm(w, None, "logo2.xpm")
 mypixmap.set(pix, mask)

Edit this entry763 / Log info764 / Last changed on Sat Jun 12 11:15:42 2004 by Christian Reis (kiko-at-async-com-br)


8.2.765 What about loading other image formats besides XPM, like JPEG or PNG?

In PyGTK2 the gtk.Image widget supports multiple formats. You can simply use:

 w = gtk.Window()
 image = gtk.Image()
 image.set_from_file(filename)
 w.add(image)
 w.show_all()
In PyGTK-0 you need to use gdkpixbuf to load non-xpm image formats. gdkpixbuf is a separate module, and you use it create a GdkPixbuf, which can be converted into a GdkPixmap, which can be in turn converted to a GtkPixmap (with its mask if transparent). An example follows:

 import gtk
 import gdkpixbuf

 w=gtk.GtkWindow()

 img=gdkpixbuf.new_from_file("images/logo.gif")
 gdkpix, mask = img.render_pixmap_and_mask() # Create a GdkPixmap object
 gtkpix = gtk.GtkPixmap(gdkpix, mask)
 w.add(gtkpix)
 w.show_all()
 gtk.mainloop()
Note that you can also use GdkPixbufs in PyGTK2. They are useful for manipulating images in-memory; for instance, for scaling and blitting imagedata (with an alpha channel). In that case, to load it into a GtkImage widget, you'd use something like:

 pixbuf = gtk.gdk.pixbuf_new_from_file(imagefilename)
 image = gtk.Image()
 image.set_from_pixbuf(pixbuf) 
to get the same results.

Edit this entry766 / Log info767 / Last changed on Thu Jul 24 11:11:53 2003 by Christian Reis (kiko-at-async-com-br)


8.3.768 How do I convert a Numeric array to a Pixbuf object?

If you don't want to resort to PIL, PyGTK-2 can be compiled with Numeric support. You can then create a Pixbuf by modifying the array returned by accessing the 'pixel_array' attribute of an existing pixbuf.

Assuming that you have a (n,m,3) or (n,m,4) shape 'b' type array of RGB or RGBA values called 'data', you would do this:

 w,h = data.shape[:2]
 hasalpha = data.shape[3] == 4
 p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, hasalpha, 8, w, h)
 p.pixel_array[:] = data # see below
Special note: the pixel_array attribute of the Pixbuf is read-only in the sense that you can't do 'p.pixel_array = data'. But it's not immutable, so you can still change it's contents, which is what the [:] slice assignment above does.

Note however that modifying the pixel data of some GdkPixbufs will cause a segfault (ones that are backed by a const string, such as the stock icons). Pixbufs you create yourself are safe to modify.

(There was a bug which could cause crashes; see [bugzilla.gnome.org]769 for details -- it was fixed in CVS HEAD in Aug 2003)

(Tim Evans)

Edit this entry770 / Log info771 / Last changed on Wed Dec 15 12:07:31 2004 by Steve Chaplin (stevech1097-at-yahoo-com-au)


8.4.772 Is there a resource leak? Why do I run out of memory using Pixbuf?

The answer is "Interesting GC behaviour" in Python. Apparently finalizers are not necessarily called as soon as an object goes out of scope. My guess is that the python memory manager doesn't directly know about the storage allocated for the image buffer (since it's allocated by the gdk) and that it therefore doesn't know how fast memory is being consumed. The solution is to call gc.collect() at some appropriate place.

For example, I had some code that looked like this:

  for image_path in images:
     pb = gtk.gdk.pixbuf_new_from_file(image_path)
     pb = pb.scale_simple(thumb_width, thumb_height, gtk.gdk.INTERP_BILINEAR)
     thumb_list_model.set_value(thumb_list_model.append(None), 0, pb)
This chewed up an unacceptably large amount of memory for any reasonable image set. Changing the code to look like this fixed the problem:

  import gc

  for image_path in images:
     pb = gtk.gdk.pixbuf_new_from_file(image_path)
     pb = pb.scale_simple(thumb_width, thumb_height, gtk.gdk.INTERP_BILINEAR)
     thumb_list_model.set_value(thumb_list_model.append(None), 0, pb)
     del pb
     gc.collect()

Edit this entry773 / Log info774 / Last changed on Tue May 11 07:24:51 2004 by Steve Chaplin (stevech1097-at-yahoo-com-au)


8.5.775 How do I to display an image from data (using a drawable or Image widget)?

The examples below assume you have the height, width and imagedata attributes available in the local scope.

The first example uses any gdk.Drawable's draw_rgb_image() method:

  # 0,0 are the coordinates for the top left corner; this 
  # renders an image flush at this corner.
  drawable.draw_rgb_image(gc, 0, 0, width, height, gtk.gdk.RGB_DITHER_NONE, imagedata)         
Note that draw_rgb_image() has an optional rowstride argument. This argument is the length of *one row* of data in your buffer. See [www.pygtk.org]776 for more information.

(Ionutz Borcoman)

The next example creates a pixbuf from an Image using the gtk.gdk.pixbuf_new_from_data method. image can be any PIL Image object using RGB or RGBA mode.

 image = Image.open('foo.png')
 IS_RGBA = image.mode=='RGBA'
 gtk.gdk.pixbuf_new_from_data(
            image.tostring(), # data
            gtk.gdk.COLORSPACE_RGB, # color mode
            IS_RGBA, # has alpha
            8, # bits
            image.size[0], # width
            image.size[1], # height
            (IS_RGBA and 4 or 3) * image.size[0] # rowstride
            ) 
Note that you need to specify rowstride for this method. Setting rowstride to 3 * width should work for an RGB image. Setting it to 4 * width should work for an RGBA image.

(Tom Hinkle)

The next example uses Numeric (which allows for further image manipulation), and will will work with RGB and RGBA images:

  import Numeric, gtk

  data = Numeric.fromstring(imagedata, 'b')
  data.shape = (height, width, -1)
  p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, i.mode == 'RGBA', 8, w, h)
  p.pixel_array[:] = data

  im = gtk.Image()
  im.set_from_pixbuf(p)
(Tim Evans)

Edit this entry777 / Log info778 / Last changed on Sat Jun 25 15:21:21 2005 by Tom Hinkle (Thomas_Hinkle-at-alumni-brown-edu)


8.6.779 How do I resize a gtk.Image?

You can use GdkPixbuf's scale_simple method (exemplified below for the my.jpg file, scaling to 150x150 px):

  im =gtk.Image()
  pixbuf = gtk.gdk.pixbuf_new_from_file("my.jpg")
  scaled_buf = pixbuf.scale_simple(150,150,gtk.gdk.INTERP_BILINEAR)
  im.set_from_pixbuf(scaled_buf)
  im.show()
(Jeff Bowden)

Edit this entry780 / Log info781 / Last changed on Wed Jan 21 09:20:45 2004 by Christian Reis (kiko-at-async-com-br)


8.7.782 What if I want to add a PIL image to a drawable?

You can use the size property and tostring() method of the PIL Image object to obtain the width, height and binary contents of the image. Then use any of the the solutions in FAQ 8.5783; the example below renders on an Image from a gdk.Pixmap, but any drawable could be used in place of the Pixmap:

  import PIL.Image, Numeric, gtk

  i = PIL.Image.open('foo.png')
  w, h = i.size
  imagestr = i.tostring()

  im = gtk.Image()
  pixmap = gtk.gdk.Pixmap(self.im.window, width, height, depth)

  gc = self.im.style.fg_gc[gtk.STATE_NORMAL]
  # 0,0 are the coordinates for the top left corner; this 
  # renders an image with no border.
  pixmap.draw_rgb_image(gc, x, y, w, h, gtk.gdk.RGB_DITHER_NONE, buff)        

  im.set_from_pixmap(pixmap, None)
To convert back from a GTK+ image type to a PIL Image, see FAQ 8.14784.

Edit this entry785 / Log info786 / Last changed on Mon May 30 14:04:17 2005 by Christian Reis (kiko-at-async-com-br)


8.8.787 Does somebody know what all these image/pixmap classes are?

GTK and GDK offer a number of classes that support drawing images.

Edit this entry789 / Log info790 / Last changed on Mon Jun 14 16:19:01 2004 by Christian Reis (kiko-at-async-com-br)


8.9.791 How do I flip an image horizontally or vertically?

There is no ready-made API for this; you can flip a GdkPixbuf by manipulating its buffer. This may be a performance problem if done exclusively through Python (though manipulating it using Numeric is a faster alternative). Another alternative is using PIL, which is easily used in combination with PyGTK.

David Hugh-Jones submitted an [unoptimized] example function that flips a pixbuf:

  def flip_pixbuf(pb):
    bps = pb.get_bits_per_sample()
    rs = pb.get_rowstride()
    pix = pb.get_pixels()

    newpix = ""
    x = rs
    pixstride = pb.get_n_channels() * bps/8 

    while x <= len(pix):
        newrow = ""
        y = pixstride
        row = pix[x - rs: x]

        while y <= len(row):
            sample = row[y - pixstride: y]
            newrow = sample + newrow
            y += pixstride

        newpix += newrow
        x += rs

    return gtk.gdk.pixbuf_new_from_data(newpix,
                                        pb.get_colorspace(),
                                        pb.get_has_alpha(), 
                                        bps,
                                        pb.get_width(),
                                        pb.get_height(), 
                                        rs)
In PyGTK-0, when GdkImlib was compiled in, it was a matter of using flip_image_horizonal() and flip_image_vertical().

Edit this entry792 / Log info793 / Last changed on Thu Jul 1 10:09:14 2004 by Christian Reis (kiko-at-async-com-br)


8.10.794 Is it possible to use SVG icons and images in PyGTK?

Yes; PyGTK supports svg icons very well via GdkPixbuf. The following example will open a simple widgetless window and render an SVG image (from the file 'my_imagefile.svg') as its icon the top left corner:

  w = gtk.Window()
  pixbuf = gtk.gdk.pixbuf_new_from_file('my_imagefile.svg')
  w.set_icon(pixbuf)
Apart from setting icons, you can use all functionality available to GdkPixbufs.

(Dennis Craven)

You can also do:

  img = gtk.Image()
  img.set_from_file('my_imagefile.svg')
NOTE: In Windows gtk doesn't support SVG, because Windows and SVG don't get along together very nicely atm.

Edit this entry795 / Log info796 / Last changed on Fri Apr 1 11:28:17 2005 by Nikos Kouremenos (kourem-at-gmail-com)


8.11.797 How do I get a Pixbuf of a stock icon?

GtkWidget has a render_icon() method that comes in handy here:

    pixbuf = dialog.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
    dialog.set_icon(pixbuf)
(Doug Quale)

Edit this entry798 / Log info799 / Last changed on Fri Nov 19 11:29:01 2004 by Christian Robottom Reis (kiko-at-async-com-br)


8.12.800 How do I register stock icons from an image file?

If you want to register a filename with the stock_id 'my-image', do something like this:

  factory = gtk.IconFactory()
  pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
  iconset = gtk.IconSet(pixbuf)
  factory.add('my-image', iconset)
  factory.add_default()
David M. Cook provides us with a way of registering more than one icon at a time and load from a file those that are found not to be stock icons, which is useful to many applications:

  def register_iconsets(icon_info):
      iconfactory = gtk.IconFactory()
      stock_ids = gtk.stock_list_ids()
      for stock_id, file in icon_info:
          # only load image files when our stock_id is not present
          if stock_id not in stock_ids:
              pixbuf = gtk.gdk.pixbuf_new_from_file(file)
              iconset = gtk.IconSet(pixbuf)
              iconfactory.add(stock_id, iconset)
      iconfactory.add_default()

  register_iconsets([('gnome-stock-mic', 'gnome-stock-mic.png'),
                     ('gnome-stock-midi', 'stock_midi.png')])

Edit this entry801 / Log info802 / Last changed on Mon Feb 14 06:59:24 2005 by Gabriel Munoz (munozga-at-gmail-com)


8.13.803 How can I use an image as background in a gtk.Window?

iconsdir = './icons'
imagename = 'image.png'

win = gtk.Window()
path = os.path.join(iconsdir, imagename)
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
pixmap, mask = pixbuf.render_pixmap_and_mask()
width, height = pixmap.get_size()
del pixbuf
win.set_app_paintable(gtk.TRUE)
win.resize(width, height)
win.realize()

win.shape_combine_mask(mask, 0, 0)  # make it transparent
win.window.set_back_pixmap(pixmap, gtk.FALSE)
del pixmap

Edit this entry804 / Log info805 / Last changed on Thu Mar 3 20:55:34 2005 by Nikos Kouremenos (kourem-at-gmail-com)


8.14.806 How do I convert a pixbuf to a PIL Image?

Use the pixbuf's get_pixels() in conjunction with Image's fromstring(): (the Image's frombuffer() works too, doesnt seem to matter much)

  import gtk
  import Image

  def pixbuf2Image(pb):
    assert(pb.get_colorspace() == gtk.gdk.COLORSPACE_RGB)
    dimensions = pb.get_width(), pb.get_height()
    stride = pb.get_rowstride()
    pixels = pb.get_pixels()
    mode = pb.get_has_alpha() and "RGBA" or "RGB"
    return Image.frombuffer(mode, dimensions, pixels,
                            "raw", mode, stride, 1)

  pb = gtk.gdk.pixbuf_new_from_file("foo.jpg")
  im = pixbuf2Image(pb)
  im.save("welldone.jpg", "JPEG", quality=80)
(Johan Dahlin, Danny M)

Edit this entry807 / Log info808 / Last changed on Mon May 30 15:37:20 2005 by Danny Milosavljevic (danny_milo-at-yahoo-com)


8.15.809 How can I get the data of a gtk.Image and save it in an external file?

it's very easy

    pixbuf = img.get_pixbuf()
    pixbuf.save(filename, "jpeg", {"quality":"100"})
where img is a gtk.Image() of course

Edit this entry810 / Log info811 / Last changed on Tue Jun 7 13:13:53 2005 by Nikos Kouremenos (kourem-at-gmail-com)


8.16.812 How to show data that I already own from outside, in a gtk.Image?

In certain situations it is possible that data is already in a program, e.g. loaded from a URL, partially loaded from a large file or loaded from EXIF data. In this case it is possible to load this data into a Pixbuf without writing it to a file first, using a PixbufLoader (documentation at [www.pygtk.org]813 ) which exists specifically for this purpose.

Some example code:

    import urlib
    f = urllib.urlopen(url_to_image)
    data = f.read()
    pbl = gtk.gdk.PixbufLoader()
    pbl.write(data)
    pbuf = pbl.get_pixbuf()
    pbl.close()
    img.set_from_pixbuf(pbuf)
where img is an instance of gtk.Image

Edit this entry814 / Log info815 / Last changed on Thu Jun 30 16:04:02 2005 by Johannes Spielmann (johannes-spielmann-at-shezi-de)


8.17.816 How to make a colorful image grayscale without using PIL?

the hint is to use pixbuf's saturate_and_pixelate method with the right arguments.

 import gtk

 pixbuf = gtk.gdk.pixbuf_new_from_file('image.png')
 pixbuf2 = pixbuf.copy()
 pixbuf.saturate_and_pixelate(pixbuf2, 0.0, False)

 pixbuf2.save('image_grayscale.png', 'png')
thanks to federico

Edit this entry817 / Log info818 / Last changed on Thu Jan 12 20:04:43 2006 by Nikos Kouremenos (kourem-at-gmail-com)


8.18.819 How blend (composite) two images together?

You should use the method 'composite' of gtk.gdk.Pixbuf. It takes a bunch of parameters. The first parameter is both the second pixbuf to composite with the first one, and also the destination where the resulting image will be stored (the original pixbuf image data is destroyed in the process). The last parameter is a transparency level, from 0 to 255, where 127 means to blend the images 50% from each source.

Obligatory example:

 pixbuf = gtk.gdk.pixbuf_new_from_file("foo.png")
 pixbuf2 = gtk.gdk.pixbuf_new_from_file("bar.png")
 pixbuf.composite(pixbuf2, 0, 0, pixbuf.props.width, pixbuf.props.height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 127)

 ## now pixbuf2 contains the result of the compositing operation
 pixbuf2.save("zbr.png", 'png')
Beware that the destination image has to be at least as large as the first image. Otherwise you might get a cryptic warning like:

  python foo.py foo.py:7: GtkWarning?: gdk_pixbuf_composite: assertion `dest_x >= 0 && dest_x + dest_width <= dest->width' failed
You can also do this using just cairo: (PyGTK 2.8+)

 import cairo

 s1 = cairo.ImageSurface.create_from_png('foo.png')
 s2 = cairo.ImageSurface.create_from_png('bar.png')

 ctx = cairo.Context(s1)
 ctx.set_source_surface(s2, 0, 0)
 ctx.paint()

 s1.write_to_png('result.png')

Edit this entry820 / Log info821 / Last changed on Sun Jan 29 14:58:56 2006 by Nikos Kouremenos (kourem-at-gmail-com)


8.19.822 How can I make a stock icon the default icon? *

If one of the stock icons[1] matches your application, you can make this the default icon (e.g. used by the window manager).

     def __init__(self):
         self.window=gtk.Window(gtk.WINDOW_TOPLEVEL)
         icon=self.window.render_icon(gtk.STOCK_FIND, 
                                      gtk.ICON_SIZE_DIALOG)
         gtk.window_set_default_icon(icon)

[1] [www.pygtk.org]823

Edit this entry824 / Log info825 / Last changed on Thu Aug 10 11:52:51 2006 by Thomas Guettler (guettli+pygtkfaq-at-thomas-guettler-de)


9. Buttons: GtkButtons


9.1.826 How does one group radio buttons to allow only one concurrent button to be depressed?

gtk.RadioButton() has a group parameter that defaults to None. The first button in the group is the group parameter for the remaining buttons. So you would do something like:

 w = gtk.Window()
 v = gtk.VBox()
 b1 = gtk.RadioButton(label="Cows")
 b2 = gtk.RadioButton(label="Dogs", group=b1)
 b3 = gtk.RadioButton(label="Mountains", group=b1)
 v.add(b1)
 v.add(b2)
 v.add(b3)
 w.add(v)
 w.show_all()
For PyGTK-1 remember to add "Gtk" on widgets names (gtk.GtkWindow)

Edit this entry827 / Log info828 / Last changed on Sat Jan 1 11:54:15 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


9.2.829 How do I create buttons that contain a pixmap?

The key to answering this is noticing that the GtkButton widget is actually a container, and you can place anything you like in it. So you could do something like:

 w = gtk.GtkWindow()
 button = gtk.GtkButton()
 label = gtk.GtkLabel('foobar')
 pix,mask = gtk.create_pixmap_from_xpm(w,None,'icon.xpm')
 pixmap = gtk.GtkPixmap(pix,mask)
 box = gtk.GtkHBox()
 button.add(box)
 box.add(pixmap)
 box.add(label)
And the button would contain a label and image like:

 (( \o/ foobar ))
Bonus answer: if you are trying to do this in glade, and you don't want one of the stock GTK pixmap buttons, you'll need to use the toolbar control, and add a button to it. You can then control if it presents images or not.

Edit this entry830 / Log info831 / Last changed on Thu Jul 11 10:53:20 2002 by Christian Reis (kiko-at-async-com-br)


9.3.832 PyGTK 0.6.x: The stock pixmap buttons in glade, but they don't show in my buttons? (pygtk0.x)

If you choose to use the stock pixmap buttons in your glade file, you should realize they are provided by gnome, and that gtk has no stock pixmaps to be used. If you would like to use pixmap buttons, you need to enable gnome support, and XXX: hope for the best, as this is untested. :)

Edit this entry833 / Log info834 / Last changed on Tue May 25 12:33:12 2004 by Johan Dahlin (johan-at-gnome-org)


9.4.835 Why is a handler connected to a GtkRadioButton being called twice?

The GtkRadioButton is a bit wierd, because it triggers the clicked signal both when it's selected and when it's unselected (i.e. it is triggered when there is a state transition in it).

In practical terms, this means that if there is a currently selected item (item A) in a radiobutton group and you select another one (item B), a signal clicked will be generated for item A and for item B.

Inside the handler, you can use radiobutton.active to check its state: if it is TRUE, it's been selected, and vice-versa.

Edit this entry836 / Log info837 / Last changed on Fri Sep 20 14:55:09 2002 by Christian Reis (kiko-at-async-com-br)


9.5.838 How do I render a stock button with a different label?

You could try Jan Weil's suggestion:

  gtk.stock_add([(gtk.STOCK_SAVE_AS, "Rename", 0, 0, "")])
See [www.moeraki.com]839 for more info.

Alternatively, if you don't want to override the default stock object, you can get the label child of the stock button and set the text directly. Thanks to Christian Reis for the suggestion!

  button = gtk.Button(stock=gtk.STOCK_CANCEL)
  button.show()

  alignment = button.get_children()[0]
  hbox = alignment.get_children()[0]
  image, label = hbox.get_children()
  label.set_text('Hide')
Doug Quale shames us all by providing a way for you to register your own stock icons, reusing images from existing stock items -- you get accelerators and themeability for free. His code creates three items, create, alter and drop, which use the new, properties and delete icons respectively:

  items = [('pg-create', '_Create', 0, 0, None),
           ('pg-alter', '_Alter', 0, 0, None),
           ('pg-drop', '_Drop', 0, 0, None),]

  # We're too lazy to make our own icons, 
  # so we use regular stock icons.
  aliases = [('pg-create', gtk.STOCK_NEW),
             ('pg-alter', gtk.STOCK_PROPERTIES),
             ('pg-drop', gtk.STOCK_DELETE),]

  gtk.stock_add(items)
  factory = gtk.IconFactory()
  factory.add_default()
  style= window.get_style()
  for new_stock, alias in aliases:
      icon_set = style.lookup_icon_set(alias)
      factory.add(new_stock, icon_set)

  # Create the relabeled buttons
  b_create = gtk.Button(stock='pg-create')
  b_alter = gtk.Button(stock='pg-alter')  
  b_drop = gtk.Button(stock='pg-drop')  
Note that the items that were copied froms are still available unchanged.

Edit this entry840 / Log info841 / Last changed on Mon Aug 30 15:09:10 2004 by Christian Robottom Reis (kiko-at-async-com-br)


9.6.842 How do I add tooltips to a ToolButton in a Toolbar?

Just use the set_tooltips() method of the Toolbar, and then set_tooltip on the button itself:

  tooltips = gtk.Tooltips()
  [...]

  toolbar = gtk.Toolbar()
  toolbar.set_tooltips(True)
  [...]

  toolbutton = gtk.ToolButton()
  toolbutton.set_tooltip(tooltips, "hi")
(Danny Milosavljevic)

Edit this entry843 / Log info844 / Last changed on Sun May 15 18:19:06 2005 by Christian Reis (kiko-at-async-com-br)


9.7.845 How do I add a stock icon to a ToggleButton?

If you want to add a stock item to a toggle button, first create a gtk.Image() and use the image_new_from_stock() method to set the stock item and the icon size:

  img = gtk.image_new_from_stock(gtk.STOCK_MEDIA_RECORD,  gtk.ICON_SIZE_BUTTON)
Next, create the stock button. Due to a bug in Gtk, make sure that you specify an empty string. If you don't add an empty string, you will scratch your head until your hair falls out:

  self.recButton = gtk.ToggleButton("")
Finally, set the 'image' property to the image:

  self.recButton.set_property("image", img)
(Jono Bacon)

Edit this entry846 / Log info847 / Last changed on Thu Mar 9 19:18:56 2006 by Christian Reis (kiko-at-async-com-br)


10. Windows: GtkWindows and GtkDialogs


10.1.848 How do I get a GdkWindow from a GtkWindow?

For some things (focus grabs are the example at hand) it is necessary to get the GdkWindow related to your GtkWindow.

 >>> w = gtk.GtkWindow()
 >>> w.realize()
 >>> w.get_window()
 <GdkWindow at 838ec70>

 w = gtk.Window()
 w.realize()
 w.window

Edit this entry849 / Log info850 / Last changed on Mon Feb 3 23:14:51 2003 by Christian Reis (kiko-at-async-com-br)


10.2.851 Where are GtkDialogFlags defined?

Where are GtkDialogFlags defined? I can find them in gtk-types.defs, but I don't know how to access them.

Matt Wilson said They are:

 gtk.DIALOG_MODAL	          If set, the dialog grabs all keyboard events
 gtk.DIALOG_DESTROY_WITH_PARENT	  If set, the dialog is destroyed when its parent is.
 gtk.DIALOG_NO_SEPARATOR	  If set, there is no separator bar above the buttons.

Edit this entry852 / Log info853 / Last changed on Sat Jan 1 12:32:20 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


10.3.854 How do I get my windows to show up where I want?

The short answer is: you don't; in X11, the window manager usually decides where the window is going to show up. However, you can provide hints so it has an idea of where the best place might be. Matt Wilson says:

 The window manager is responsible for placing the window on the screen
 when mapped if it isn't given an exact position.  For dialog boxes, 
 make sure you're passing in the parent window when creating the dialog
 box.  Then GTK will set up the correct hints that would make window
 managers treat the dialog window as a child of its parent.  How the
 window manager decides to treat the placement is configurable in some
 window managers...
If you would like to specify that a dialog is a `sub-window' of a window, for instance, you can use the following commands:

 w = gtk.Window()
 # ...
 d = gtk.Dialog()
 d.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
 d.set_transient_for(w)
When d is displayed, the window manager will know it is a transient for the parent window. By calling set_position it will [usually] be placed centered upon the parent.

(Note that some X11 servers such as Xming appear not to honour these placement settings.)

To do this with a dialog defined in a glade file, you'll need to do something like:

 d = glade_tree.get_widget(dialog_name)
 d.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
 d.set_transient_for(parent_window)
If you want to specify positioning further -- to get a centered dialog, for instance -- you can use other options to the GtkWindow.set_position() method, which is described at [www.moeraki.com]855

You can also save and restore the window position and size. Save the position with:

    (x, y) = w.get_position()
    (w, h) = w.get_size()
Later restoring it with:

    w = gtk.GtkWindow()
    w.move(x, y)
    w.set_size_request(w, h)

Edit this entry856 / Log info857 / Last changed on Fri Feb 24 02:37:05 2006 by John Pye (john-pye-at-student-unsw-edu-au)


10.4.858 How do I make a dialog block the whole application, so the user is forced to answer it?

This is called a modal dialog. Modal dialogs in general are unpleasant things, since they force a question upon the user. Ideally, the application should offer choices to the user non-obtrusively, instead of making demands upon him.

Having said that, there are times where a modal dialog is either necessary or an easy solution. Any window of the application can be set as modal; this will force it to be dismissed before the normal flow of the application is restored. FIXME: window.hide() removes modality?

To make a dialog modal, simply use:

 import gtk
 w = gtk.GtkWindow()
 w.set_modal(gtk.TRUE)
In pygtk2, you can also use:

 w = gtk.Dialog()
 ret = w.run()
 w.hide()
 return gtk.TRUE
where the return value will stop the dialog's contents from being destroyed, see FAQ 10.6859. The gtk.Dialog.rug() method will just start a recursive loop and wait until the dialog emits a "respond" signal. So it is still your responsibility to emit that signals somehow:

 def on dialog_w_okbutton_clicked(*args):
     w.response(response_id)
This response_id will be returned by the gtk.Dialog.run() method.

Edit this entry860 / Log info861 / Last changed on Wed Apr 6 07:15:27 2005 by Floris Bruynooghe (fb102-at-soton-ac-uk)


10.5.862 I click on the close button (X) to close my gtk.Window. It disappears, but the program seems to hang!

If you create a gtk.Window and close it using the window manager (WM) --- in other words, by clicking on a close or X button on the window decorations, or using some other way the WM provides --- the window by default is destroyed. However, the 'gtk.main()' which you invoked to actually display the window is still running. To have the program quit when you close your window, you should connect 'gtk.main_quit()' to its 'delete-event' signal.

 win = gtk.Window()
 win.connect("delete-event", gtk.main_quit) # no parenthesis; you pass functions to connect

Edit this entry863 / Log info864 / Last changed on Sat Apr 29 10:36:06 2006 by Tiago Cogumbreiro (cogumbreiro-at-users-sf-net)


10.6.865 How do I avoid having my gtk.Window instance destroyed when I click on the window's close button? (or, When I redisplay my window, all my child widgets are missing and I get a bunch of Gtk-Critical errors!)

As you saw in FAQ 10.5866, closing a window using the window manager, by default, causes it to be destroyed. In that example, we connected to 'delete-event' to break the mainloop when this happened, but at other times you may want to customize further the behaviour you get.

You can avoid the window's destruction by attaching a callback handler to the 'delete-event' handler in the GtkWindow and having it return 'True':

 win = gtk.Window()

 def on_delete_event(widget, event):
   print "Delete was called but I won't die!"
   return True

 win.connect("delete-event",on_delete_event)
A common thing to do is call the 'hide()' method in the handler.

The 'return True' part indicates that the default handler is _not_ to be called, and therefore the window will not be destroyed.

The actual process of event propagation is not simple to grasp and is better described at [www.gtk.org]867 .

It is important to note that you should not attach to 'destroy-event', as it cannot be overridden (it occurs server-side, and no client callback is triggered). Your window will always be destroyed, and your handler will not be called at all.

For gtk.Dialog its easier: just test the response id from running the dialogue against gtk.RESPONSE_DELETE_EVENT. It will match in time to be able to prevent the widget be destroyed, and there is no need to connect a signal.

For the specific case of GnomeAbout, see FAQ 10.13868.

Edit this entry869 / Log info870 / Last changed on Sat Apr 29 10:36:47 2006 by Tiago Cogumbreiro (cogumbreiro-at-users-sf-net)


10.7.871 How do I change the window manager's icon for a PyGTK Window?

In both PyGTK-0 and PyGTK-2 you can use the set_icon() method of gtk.Window. If you're using glade2, additionally, you can set the icon from the properties dialog for the window.

here an example:

 w = gtk.Window()
 icon = w.render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
 w.set_icon(icon)
 w.show()
 gtk.main()
This will work also on win32.

Edit this entry872 / Log info873 / Last changed on Sun Jan 2 11:16:21 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


10.8.874 How do I get the GtkWindow's title?

In PyGTK 0.6.x use the title property, via getitem:

 >>> w = gtk.GtkWindow()
 >>> w.set_title("foo")
 >>> print w['title']
 foo
In PyGTK 2, use:

 >>> w = gtk.Window()
 >>> w.set_title('foo')
 >>> print w.title
 foo

Edit this entry875 / Log info876 / Last changed on Sat Mar 15 17:20:04 2003 by Christian Reis (kiko-at-async-com-br)


10.9.877 How do I change the buttons on a MessageDialog?

PyGTK2: If you want one of the standard collections (Yes/No, Ok/Cancel...) then you can use one of the constants defined for GtkButtonsType [www.pygtk.org]878 in the gtk.MessageDialog constructor as the fourth argument to the constructor. The constructor format is:

  gtk.MessageDialog(parent, options, type, buttons, message)
If none of the standard choices are appropriate, simply use gtk.BUTTONS_NONE and call gtk.Dialog.add_button(), a little example:

 message = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, "message here")
 message.add_button(gtk.STOCK_QUIT, gtk.RESPONSE_CLOSE)
 resp = message.run()
 if resp == gtk.RESPONSE_CLOSE:
    message.destroy()
PyGTK0.x doesn't have a MessageDialog, and to manipulate a Dialog's buttons you need to rummage through dialog.action_area.

Edit this entry879 / Log info880 / Last changed on Sun Jan 2 11:39:56 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


10.10.881 How do I adjust a ScrolledWindow to adjust to a given child widget?

One common request is to get a ScrolledWindow to adjust to display one of the widgets it contains -- frequently you'd like to adjust the scrollbar to display the widget that receives focus. This is possible by using the set_value method of the ScrolledWindow's adjustment object in conjunction with the child widget's `focus_in_event' signal. An (untested) example follows:

 def focus_in(widget, event, adj):
   alloc = widget.get_allocation()        
   if alloc.y < adj.value or alloc.y > adj.value + adj.page_size:
     adj.set_value(min(alloc.y, adj.upper-adj.page_size))

 scrolled_window = gtk.ScrolledWindow()
 adj = scrolled_window.get_vadjustment()
 # ... create child widget
 child.connect('focus_in_event', focus_in, adj)
This should make the scrollbar adjust automatically whenever child receives focus.

Edit this entry882 / Log info883 / Last changed on Wed Apr 9 13:01:32 2003 by Christian Reis (kiko-at-async-com-br)


10.11.884 How do GtkDialogs work?

To start off, an example and text by George Young:

 dialog = gtk.Dialog('Window Title',
                     parent_window,  # the window that spawned this dialog
                     gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,                       
                     ("Play Now", 77, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
 dialog.vbox.pack_start(gtk.Label('Do you want to play a game?'))
 dialog.show_all()
 result = dialog.run()
 if result == 77:
    play_the_game()
 elif result == gtk.RESPONSE_CLOSE:
    user_just_closed_dialog()
 dia.destroy()
Buttons are specified in the creation of the dialog. Buttons can be standard gtk buttons with cute images like STOCK_CLOSE, or your own strings, e.g. "Play Now". Buttons are specified as a list of (button_appearance, response_integer) pairs. When a button is pressed, the run() member returns the corresponding response value.

The upper part of a Dialog has a gtk.VBox where you can pack your own widgets, e.g. the Label shown above, or a scrolledwindow containing a gtk.TreeStore (which could display a list or a tree). The buttons live in dia.action_area, a gtk.HBox where you can also manually put your own buttons or whatever.

MODAL_DIALOG means you app is locked until a response is made. DIALOG_DESTROY_WITH_PARENT tells the window manager to lose/open/destroy this dialog with your app window -- you usually want this.

Canned response values are:

 GTK_RESPONSE_NONE
 GTK_RESPONSE_REJECT
 GTK_RESPONSE_ACCEPT
 GTK_RESPONSE_DELETE_EVENT
 GTK_RESPONSE_OK
 GTK_RESPONSE_CANCEL
 GTK_RESPONSE_CLOSE
 GTK_RESPONSE_YES
 GTK_RESPONSE_NO
 GTK_RESPONSE_APPLY
 GTK_RESPONSE_HELP
[from pygtk-1.99.16/gtk/gtk-types.defs]

Many canned "stock" button icons are available from ADD to ZOOM_OUT; if you have the gtk source installed, you can use the gtk-demo program which offers a nice "Stock Item and Icon Browse" window.

There is a tutorial page relevant at [www.pygtk.org]885 and a reference page for GtkDialog at [www.pygtk.org]886

For PyGTK2, there is a good example in the examples/pygtk-demo/demos/ subdirectory in your tarball.

Edit this entry887 / Log info888 / Last changed on Tue Oct 5 16:48:38 2004 by Christian Robottom Reis (kiko-at-async-com-br)


10.12.889 How do I make ENTER in an entry box activate the OK signal

It is sometimes useful to be able to hit ENTER in an entry box and have it simulate clicking OK and closing the dialog. The two key steps are calling 'entry.set_activates_default(gtk.TRUE)' on the entry widget and then telling the dialog what the default action is, as in 'dlg.set_default_response(gtk.RESPONSE_OK)'. Here's a complete example:

  dlg = gtk.Dialog('Marker Label')
  dlg.show()

  entry = gtk.Entry()
  entry.show()
  entry.set_activates_default(gtk.TRUE)
  dlg.vbox.pack_start(entry)

  dlg.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  dlg.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
  dlg.set_default_response(gtk.RESPONSE_OK)
  response = dlg.run()

  if response == gtk.RESPONSE_OK:
      label = entry.get_text()
      print label
  dlg.destroy()

Edit this entry890 / Log info891 / Last changed on Thu Jun 12 16:26:58 2003 by John Hunter (jdhunter-at-ace-bsd-uchicago-edu)


10.13.892 When closing the GnomeAbout box (or other GtkDialog subclasses), I get crashes and weird callback behaviour. What up with that?

Normally, when handling closed signals on a window, you should follow the advice in FAQ 10.6893. However, for GnomeAbout, things aren't so simple.

Jon Willeke took the time to point out that in the case of GnomeAbout, to avoid having a window be destroyed when you close it, you need to also connect to the "response" handler. Malcolm Tredinnick offered a more detailed explanation of how this works:

A GtkDialog box has two main signals it implements: 'close' and 'response'. It also inherits the 'delete-event' signal from the GtkWidget class which also has a role to play here.

The 'response' signal is emitted pretty much whenever any action happens that causes the dialog box to finish running. The response signal emission will contain a "response ID" which can be user-defined or any one of the gtk.RESPONSE_* constants in pyGTK. The standard values correspond to things like one of the standard buttons being pushed or the window being destroyed. You can act differently based on the response ID.

The 'delete' signal is emitted whenever the corresponding GtkWidget is deleted in a "strange" (for want of a better word) way. The main case here is when the user closes the window via the window manager (Alt-F4, or clicking on the 'X' button in a typical window manager, for example). In that case, you also get a 'response' signal, so generally you just ignore the 'delete' signal (return gtk.TRUE as has been mentioned elsewhere).

For your standard GtkDialog widget, the only way the 'close' signal is emitted is when the Escape key is pressed. Widgets deriving from GtkDialog may have other buttons that are hooked up to emit 'close', but by default it is only bound to the Escape key (try it and see for the About dialog -- you can close it with Escape and it emits the predicted signal).

Colin Fox posted a summary of the signals he had to connect and the methods he needed to define to make things work as expected:

  def __init__(self, *args):
      # ...
      self.connect("response", on_aboutbox_response)
      self.connect("close", on_aboutbox_close)
      self.connect("delete_event", on_aboutbox_close)

  def on_aboutbox_response(self, dialog, response, *args):
      # system-defined GtkDialog responses are always negative, in which    
      # case we want to hide it
      if response < 0:
        dialog.hide()
        dialog.emit_stop_by_name('response')

  def on_aboutbox_close(self, widget, event=None):
      self.aboutbox.hide()
      return gtk.TRUE
In short, to keep the dialog from destroying itself or crashing you need to define a "delete-event" handler that returns True and define a "response" handler that stops emission of the signal, and, if you want the Escape key to work as expected, you also need to connect to the close signal.

It remains to be seen why you have to emit_stop_by_name() in the response handler -- it might be a GTK+ bug, but nobody alive seems to know the answer.

Edit this entry894 / Log info895 / Last changed on Tue Jan 13 12:40:32 2004 by Christian Reis (kiko-at-async-com-br)


10.14.896 I created a modal dialog, but clicking on the main window covers it!

Short answer -- use:

  dialog.set_transient_for(main_window)
See FAQ 10.3897 for details.

Edit this entry898 / Log info899 / Last changed on Tue Sep 2 14:19:06 2003 by Christian Reis (kiko-at-async-com-br)


10.15.900 How do I get the position of my window in absolute terms (IOW, relative to the root X window)

Use the get_root_origin() method.

The get_position() method returns the position of the window relative to its parent window.

Edit this entry901 / Log info902 / Last changed on Fri Sep 19 20:42:18 2003 by Christian Reis (kiko-at-async-com-br)


10.16.903 How do I start up a window maximized?

Just call maximize() on the window before you enter the main loop.

  win = gtk.Window()
  win.maximize()
  win.show()
  gtk.main()

Edit this entry904 / Log info905 / Last changed on Thu Sep 2 11:13:30 2004 by Christian Robottom Reis (kiko-at-async-com-br)


10.17.906 How do I run a dialog without running another main loop?

GtkDialog.run by default starts another mainloop, and when you entered your input in the dialog you'll get a response returned to the application and the nested main loop is exited.

However, in some cases (for example when integrating with twisted) you do not want to use a nested mainloop, but rather reuse the current one.

So, here is a non blocking version version of GtkDialog.run that reuses the current mainloop:

 def dialog_response_cb(dialog, response_id):
   dialog.destroy()

   if response_id == gtk.RESPONSE_OK:
     print 'OK clicked'

 def dialog_run(dialog):
   if not dialog.modal:
     dialog.set_modal(True)
   dialog.connect('response', dialog_response_cb)
   dialog.show()
Perhaps it would be nicer to subclass GtkDialog and implement a run_nonblocked method, but that is beyond this FAQ entry and left as an exercise for the reader.

Edit this entry907 / Log info908 / Last changed on Wed Feb 23 13:49:48 2005 by Johan Dahlin (johan-at-gnome-org)


10.18.909 Changing a Window's background color

Thanks to Gian Mario Tagliaretti on the PyGTK mailing list:

   import pygtk
   pygtk.require('2.0')
   import gtk

   class FirstWin:
       def __init__(self):
           self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
           color = gtk.gdk.color_parse('#234fdb')
           self.win.modify_bg(gtk.STATE_NORMAL, color)
           #  To change the color again, just modify it again
           self.win.show()

       def main(self):
           gtk.main()

   if __name__ == "__main__":
       first = FirstWin()
       first.main()

Edit this entry910 / Log info911 / Last changed on Wed Apr 20 03:59:57 2005 by Charles Hixson (charleshixsn-at-earthlink-net)


10.19.912 How do I get XID for a GtkWindow? And for the root window?

Easy! Just get the "xid" attribute of its GdkWindow:

  >>> win = gtk.Window()
  >>> print win.window
  None
But it's None! You'd have to wait until the window is visible, or actually until it's realized, see the reference for more information about realize. So, to force a realization of a window, just call the realize() method:

  >>> win.realize()
Now we're ready to go, just fetch the xid:

  >>> print win.window.xid
  58720259L
And now, to do it for the root window, do this:

  >>> root = gtk.gdk.screen_get_default().get_root_window()
  >>> print root.xid
  72L
(Gustavo Carneiro)

Edit this entry913 / Log info914 / Last changed on Mon May 16 12:41:49 2005 by Johan Dahlin (johan-at-gnome-org)


10.20.915 How can I make my window appear in the center of the screen?

To tell the window manager to put the window in the center on the screen you can set a certain window manager hint, there is a convenience method in gtk.Window called set_position which allows you to do this in an easy way:

   window.set_position(gtk.WIN_POS_CENTER)
There are several other hints, to retreive a complete list, please visit the gtk.Window section in the reference manual: [www.pygtk.org]916

Edit this entry917 / Log info918 / Last changed on Sat Jul 9 22:54:39 2005 by Johan Dahlin (johan-at-gnome-org)


10.21.919 How to hide a window when clicking the close button (instead of destroying it)

Let's say you have a gtk.Window called window.

  def hide_window(window, event):
    window.hide()
    return True

  window.connect('delete-event', hide_window)
The important bit is the return True in the callback, that prevents the window from being destroyed !

Edit this entry920 / Log info921 / Last changed on Fri Sep 2 20:18:07 2005 by Raphael Slinckx (raphael-at-slinckx-net)


10.22.922 How can I find out when my GtkWindow is minimized?

Easy.

Connect to the window-state-event signal of the window and check if the window was iconified:

 def window_state_event_cb(window, event):
   if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
      if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
         print 'Window was minimized!'
      else:
         print 'Window was unminimized!'

 window = gtk.Window()
 window.connect('window-state-event', window_state_event_cb)
event.new_window_state can be one of the following:

 gtk.gdk.WINDOW_STATE_WITHDRAWN
 gtk.gdk.WINDOW_STATE_ICONIFIED
 gtk.gdk.WINDOW_STATE_MAXIMIZED 
 gtk.gdk.WINDOW_STATE_STICKY

Edit this entry923 / Log info924 / Last changed on Fri Jan 6 12:46:08 2006 by Johan Dahlin (johan-at-gnome-org)


10.23.925 How can I find out if a gtk.Window is visible?

To check if a gtk.Window is visible you can use the visible property inherited from gtk.Widget.

 self.window = gtk.Window()
 self.window.show()
 self.window.get_property("visible")

Edit this entry926 / Log info927 / Last changed on Fri Jan 27 09:00:59 2006 by Marc (m4rccd-at-yahoo-com)


11. Menus: Gtk*Menu and Gtk*MenuItem GtkToolbar


11.1.928 How do I turn off tearoff menus in libglade?

That is a good question. <jamesh> and <andersca> have both tried to convince me that it is a matter of turning off a preference in ~/.gnome/Gnome:

 [UI_GnomeApp]
 Menubar_detachable=false
 Menus_have_tearoff=false
None of these seem to work for me.

Johan has suggested I turn off Gnome support in the glade files. That doesn't work either.

I currently think this is a problem with libglade itself. Pure PyGTK apps don't have tearoff menus by default (see testgtk.py for an example).

Edit this entry929 / Log info930 / Last changed on Thu Jan 31 20:16:31 2002 by kiko (kiko-at-async-com-br)


11.2.931 How do I pop up a menu with a button click?

You need to attach a callback to "button_press_event" and catch its event object (which is the second parameter). This handler should be something like:

 def popup(widget, event):
   popup_menu.popup(None, None, None, event.button, event.time)
this results in a menu that is floating and you have to call popup_menu.destroy() or reuse the popup_menu.

You are also advised to call popup_menu.attach_to_widget() or at least .set_screen() so your application does not suffer in multiple screens environments.

Callling attach_to_widget() also means that your menu will be destroyed when widget that is being attached to, is destroyed. Popdown that happens by GTK does NOT destroy the menu, so if you want this behaviour, connect to 'deactivate' signal and in callback do widget.destroy()

Don't ask me what the None's are supposed to be. The API dox say:

 GtkWidget *parent_menu_shell,
 GtkWidget *parent_menu_item,
 GtkMenuPositionFunc func,
 gpointer data, 
 guint button,
 guint32 activate_time
But gtk.py does:

 def popup(self, pms, pmi, func, button, time)
So data is probably gone. Everybody uses None, why not you?

Edit this entry932 / Log info933 / Last changed on Fri Apr 7 09:44:20 2006 by Nikos Kouremenos (kourem-at-gmail-com)


11.3.934 How do I find out if a GtkCheckMenuItem is selected (active)?

GtkCheckMenuItem has an "active" attribute, as GtkToggleButton and GtkCheckButton do. So:

 m = menu.get_menu()
 items = m.children()
 # assuming all items are checkitems
 for i in items:
  if i.active:
    print "Item %i is active"

Edit this entry935 / Log info936 / Last changed on Thu Jul 11 13:20:57 2002 by Christian Reis (kiko-at-async-com-br)


11.4.937 I create a menubar with ItemFactory, but it disappears

I had a problem with my menubar not showing. The solution I found was to hold on to a reference to the ItemFactory.

e.g.

   self.item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", accel_group)
This seems to be a garbage collection problem.

Storing a reference to the ItemFactory where I could retrieve it later prevents the garbage collector from tidying it up. A global variable would work too, but of course "global vars are bad".

Edit this entry938 / Log info939 / Last changed on Mon Jan 5 23:06:31 2004 by David Moore (djm-at-linuxsoftware-co-nz)


11.5.940 When specifying items to an ItemFactory, I pass the extra argument for the image but I can't see anything!

You have to remember to set the proper type for the menu element: <StockItem> if you are using a stock image ID, <ImageItem> if you are using a pixbuf image.

For example, using a stock image, assuming popup_stop is the callback function:

 factory = gtk.ItemFactory(gtk.Menu, '<foo_popup'>)
 items = (("/_Stop", None, popup_stop, 0, "<StockItem>",  gtk.STOCK_CANCEL),)
 factory.create_items(items)

Edit this entry941 / Log info942 / Last changed on Thu Feb 19 12:47:05 2004 by Christian Reis (kiko-at-async-com-br)


11.6.943 How do I specify and save accelerators for my menu?

For most GTK+ applications, the user can change menu item accelerators by hovering on them with the mouse pointer and pressing a key combination on the keyboard (that can be switched on/off in .gtkrc-2.0 and gtk themes via gtk-can-change-accels = 0/1 though)

You can save the specified accelerators using gtk.accel_map_save(filename) and gtk.accel_map_load(filename). The stored file uses the accelpaths to associate the stored entry with the menu entry, so be sure to set language independent accelpaths for the menus and menu entries (and include some text prefix to make the windows distinguishable since accel_map_* functions work in app global scope).

XXX: providing a default set of accelerators for an application

Edit this entry944 / Log info945 / Last changed on Mon Nov 29 17:16:35 2004 by Danny Milosavljevic (danny_milo-at-yahoo-com)


11.7.946 How to i put a custom icon and custom label in a gtk.ImageMenuItem

first example:

 item = gtk.ImageMenuItem('Foo')
 img = gtk.Image()
 img.set_from_file('data/myimage.png')
 item.set_image(img)
second example:

 item = gtk.ImageMenuItem('Foo')
 img = gtk.image_new_from_stock(gtk.STOCK_REFRESH, gtk.ICON_SIZE_MENU)
 item.set_image(img)

Edit this entry947 / Log info948 / Last changed on Sun Oct 9 15:46:51 2005 by Nikos Kouremenos (kourem-at-gmail-com)


12. Simple Containers: GtkBoxes, GtkTable, GtkFixed, GtkAlignment


12.1.949 What are the parameters to GtkAlignment.set()

This confused me for a while too, because Glade may trick you into thinking that they aren't what they are. Here it is:

 align.set(xalign, yalign, xscale, yscale)
Where the parameters are:

If you pack a GtkAlignment into a container, be careful to set the scale attributes to 1 or the alignment will not expand to take up the whole space in the parent widget (instead, an empty space will be left in the outer container, and get_allocation() will return bogus values for the GtkAlignment).

Edit this entry950 / Log info951 / Last changed on Sat Oct 12 02:20:53 2002 by Christian Reis (kiko-at-async-com-br)


12.2.952 How does packing work (or how do I get my widget to stay the size I want)

You'll often find when working with containers that the size (and aspect ratio) of your widget isn't quite what you would expect. That's an intentional consequence of the GTK+ box model: the size of the widget is determined by packing: if its container offers it (or not) the possibility to expand and fill space available to it in the interface.

This is often confusing, and a good idea would be to play around a bit with gazpacho or glade to get a feeling for the box model. Essentially, the idea is based on a few key concepts:

                                        Border
    .----------------------------------/---.
    | Window                          H    |
    | .----------------------------------. |
    | | Entry                            | |   
    | '----------------------------------' |
    |                                      |
    '--------------------------------------

    .---------------------------------------------------------.
    | Window                                                  |
    | .--------------------. .------------------------------. |
    | | Entry1             | | Entry2                       | |
    | | packed w/ expand=0 | | packed w/ expand=1           | |
    | '--------------------' '------------------------------' |
    |                                                         |
    '---------------------------------------------------------'
How much each one actually gets is determined by:

This is important to understand when assembling your interfaces, and is the most peculiar thing about GTK+ programming to a newbie; although the packing-based widget geometry is more complex to understand initially than MS-style fixed layouts, it is infinitely superior, because GTK+ windows actually resize properly.

Spend some time experimenting with the "packing" tab in gazpacho/glade and some composite interfaces: it will teach you a lot in very short time.

[*] A cute analogy; in reality fill, expansion, requested sizes, widget expansion semantics, container packing semantics, electron spins and lunar cycles are computed to determine how much space each widget wins.

Edit this entry953 / Log info954 / Last changed on Thu Jul 22 21:15:49 2004 by Christian Robottom Reis (kiko-at-async-com-br)


13. Lists and Trees: GtkList/TreeView


13.1.955 Is there a nice tutorial on using GtkTreeView and GtkTreeModel?

The pyGTK tutorial has an interesting section on TreeViews. Check last version in [www.pygtk.org]956

Lars Wirzenius wrote a very nice guide using Python for all his examples, and it's definitely worth checking out: [liw.iki.fi]957

Edit this entry958 / Log info959 / Last changed on Sun Nov 28 20:24:06 2004 by pachi (pachi-at-mmn-arquitectos-com)


13.2.960 How do the TreeStore and ListStore sequence APIs behave? [PyGTK2]

GtkTreeStore and GtkListStore implement the __getitem__/__setitem__ API. You pass in a tree path as a key and get a "row object" as the value. The row object basically combines a pointer to the tree model and a GtkTreeIter for the row. It in turn looks like a sequence -- one item per column in the model. You can get and set columns in the row through this interface. The best way to explain this is with some examples:

    liststore = gtk.ListStore(str, str, int)   # create list store  
    treestore = gtk.TreeStore(int, str, str)   # and a tree store
    ...   # fill in some rows
    row = liststore[42]   # get the row object for the 42nd row in the list
    print row[2]   # print 3rd column in row
    print liststore[42][2]   # or the two operations can be combined

    # print first column of first child of the second top level node
    print treestore[1,0][0]

    # assignment works too
    liststore[42][2] = 42 

    # you can also assign to the entire row in one go
    treestore[1,0] = (5, 'foo', 'bar')

    # or delete rows
    del liststore[42]
If you have a GtkTreeIter for a row, you can also get the corresponding row object for it with "store[iter]". As well as looking like a sequence, row objects have the following attributes:

    * next: next sibling row object
    * parent: parent row object
    * model: the GtkTreeModel for this row
    * path: the tree path of this row.
    * iter: a GtkTreeIter pointing at this row.
Iteration: tree and list stores implement the Python iteration API. This means that you can easily do things like print the value of the first column for every row in a list store:

    for row in liststore:
        print row[0]
For tree stores, this only iterates over the toplevel of the tree. Each row object has an iterchildren() method that can be used to iterate over the child rows if desired (if you directly iterate over the row, you will get the columns).

Extra optional argument on append/prepend/insert methods: I added an additional optional argument to the insert, insert_before, insert_after, prepend and append methods. If passed, the additional argument is interpreted as a sequence of values of the columns in the new row. For instance:

    liststore.append(('foo', 'bar', 42))
This makes the list store feel a lot more like the standard Python list objects.

Edit this entry961 / Log info962 / Last changed on Wed Apr 9 18:21:05 2003 by Christian Reis (kiko-at-async-com-br)


13.3.963 How do GtkTreePaths work? [PyGTK2]

There is no special wrapper for GtkTreePaths in PyGTK. Since a tree path is really just an ordered list of indices, we represent them as tuples of integers. In places where a GtkTreePath must be passed to GTK, the following Python types will be accepted:

By accepting integers as length-one tree paths, the user can just pass in integers for GtkListStore methods, and think of them as row numbers. They don't even need to think about paths.

Edit this entry965 / Log info966 / Last changed on Mon Sep 29 12:23:10 2003 by Christian Reis (kiko-at-async-com-br)


13.4.967 How do I define columns for a TreeView using TreeViewColumn?

First thing you should do is create a gtk.CellRenderer for the cells of the column you wish to add. There several gtk.CellRenderer subtypes, each one specialized for rendering a specific data type. More info on cell renderers is available at [www.moeraki.com]968 .

Then, you add a column to your tree view. You can instantiate a TreeViewColumn manually:

 col = gtk.TreeViewColumn(title, renderer, property1=column1, ...)
 treeview.insert_column(col, position)
 # note that treeview.append_column() exists too
or by using the TreeView's insert_column_with_attributes() API:

 gtk.TreeView.insert_column_with_attributes(position, title, renderer,
                                            property1=column1, ....)
The parameters are:

Notice that the order and number of columns in a tree view is unrelated to the columns in a tree model. It is not unusual to store extra application data in a hidden column in the tree model. It is only the property=column parameters that truly make the connection between the tree model and the tree view.

And now a simple example:

 COLUMN_NAME = 2              # the third model column holds 'name';
                              # column numbers start at zero, mind you
 renderer = gtk.CellRendererText()
 treeview.insert_column_with_attributes(-1, 'Name', renderer,
                                        text=COLUMN_NAME)
In this example, a text renderer is created. Then a column is added to the treeview, the 'text' attribute of the renderer indicating that the cell contents should be taken from the third column (COLUMN_NAME) of the tree model, in the corresponding row.

(Answer contributed by Gustavo Carneiro)

Edit this entry969 / Log info970 / Last changed on Sun Oct 26 12:37:49 2003 by Christian Reis (kiko-at-async-com-br)


13.5.971 How do I create my own custom TreeModel.

By subclassing GenericTreeModel and implementing the "on_*" methods (e.g. on_get_iter(path) ) of GenericTreeModel. A simple example, treemodel.py, implementing all the required methods of the TreeModel, is included in the pygtk distribution in the examples/pygtk-demos/demos directory: [cvs.gnome.org]972

Some other examples making use of GenericTreeModel:

Edit this entry976 / Log info977 / Last changed on Mon Dec 30 12:53:11 2002 by Dave Cook (dave-at-davidcook-org)


13.6.978 How do I put icons in a TreeView?

You should use a gtk.CellRendererPixbuf as your column renderer. Here is an example that shows a stock icon and a label in two columns:

 (COL_PIXBUF, COL_STRING) = range(2)
 model = gtk.ListStore(gtk.gdk.Pixbuf, str)
 treeview = gtk.TreeView(model)
 model.append([gtk.gdk.Pixbuf('icon.png'), 'This is a string'])

 renderer = gtk.CellRendererPixbuf()
 column = gtk.TreeViewColumn('Icon', cell, pixbuf=COL_PIXBUF)
 treeview.append_column(column)

 renderer = gtk.CellRendererText()
 column = gtk.TreeViewColumn('Text', cell, text=COL_STRING)
 treeview.append_column(column)
Note, that in this example you'll need an filename called icon.png in the current directory. If you wish to use a stock icon, use the render_icon method which you can find on every widget.

Advanced usage, if you want to be able to sgiw the icon and the string in the same column, you'd have to replace the last 6 lines in the above example with the following code:

  column = gtk.TreeViewColumn()
  column.set_title('Icons & Text')
  treeview.append_column(column)

  rendererer = gtk.CellRendererPixbuf()
  column.pack_start(renderer, expand=False)
  column.add_attribute(renderer, 'pixbuf', COL_PIXBUF)

  renderer = gtk.CellRendererText()
  column.pack_start(renderer, expand=True)
  column.add_attribute(renderer, 'text', COL_STRING)

Edit this entry979 / Log info980 / Last changed on Wed Jul 6 09:52:40 2005 by Johan Dahlin (johan-at-gnome-org)


13.7.981 How do I get all the selections in my TreeView.

Until gtk_tree_selection_get_selected_rows is wrapped (see [bugzilla.gnome.org]982 ) one can use this bit of code due to Martin H.:

 selected = []
 selection = treeview.get_selection()
 selection.selected_foreach(lambda model, path, iter, 
                            sel=selected: sel.append(path))
As of at least v2.4 gtk_tree_selection_get_selected_rows is wrapped. The above now becomes:
 selection = treeview.get_selection()
 model, selected = selection.get_selected_rows()

Edit this entry983 / Log info984 / Last changed on Thu Nov 18 12:40:20 2004 by Chris Lambacher (lambacck-at-computer-org)


13.8.985 How do I delete the selected rows in a TreeView?

Grzegorz Adam Hankiewicz offered the following snippet, tested only with single selection TreeViews (for multiple selections, see FAQ 13.25986):

   selection = self.list_view.get_selection() 
   model, iter, = selection.get_selected()
   if iter:
      path = model.get_path(iter)
      model.remove(iter)
      # now that we removed the selection, play nice with 
      # the user and select the next item
      selection.select_path(path)

      # well, if there was no selection that meant the user
      # removed the last entry, so we try to select the 
      # last item
      if not selection.path_is_selected(path):
         row = path[0]-1
         # test case for empty lists
         if row >= 0:
            selection.select_path((row,))
Note that using selected_foreach doesn't seem to work correctly (I think this is becasue you're not allowed to change the selection, or change the model, inside a foreach, but IMBW).

Edit this entry987 / Log info988 / Last changed on Sun May 15 19:04:46 2005 by Christian Reis (kiko-at-async-com-br)


13.9.989 Is there a way to mass-specify columns in ListStore?

If you determine at runtime how many columns a ListStore should have, you can create a list with the column types and then pass them on to the ListStore using *columnlist. You can do list arithmetic to make multiple columns of the same type, too. Example:

 # 4 columns, 1-3 string, 4 int.
 columns = [gobject.TYPE_STRING]*3 + [gobject.TYPE_INT]
 gtk.ListStore(*columns)

Edit this entry990 / Log info991 / Last changed on Wed Nov 6 15:22:59 2002 by Christian Reis (kiko-at-async-com-br)


13.10.992 How do I make a GtkTreeView with editable cells?

This can be done two different ways:

1) Set the "editable" property to True for all the cells in a column:

 renderer = gtk.CellRendererText()
 renderer.connect('edited', cell_edited_callback)
 renderer.set_property('editable', True)
 treeview.insert_column_with_attributes(-1, 'Editable String', renderer, text=0)
or

2) Set the "editable" property to True for individual cells:

The first thing you have to do is include a column of type boolean. It will specify if a row is editable or not.

 model = gtk.TreeStore(str, int, bool)

 iter = model.append()
 model.set_value(iter, 0, 'foo')
 model.set_value(iter, 1, 34)
 model.set_value(iter, 2, True)
Next thing is create the TreeView, Columns and Renderers:

 treeView = gtk.TreeView(model)

 renderer = gtk.CellRendererText()
 column = gtk.TreeViewColumn('column 1', renderer, text=0, editable=2)
 treeView.append_column(column)

 renderer = gtk.CellRendererText()
 column = gtk.TreeViewColumn('column 2', renderer, text=1, editable=2)
 treeView.append_column(column)
And that's all. The important thing is the creation of the column. The values of the properties 'text' and 'editable' are column indexes of the model. So in the first column we are saying that the text property of the renderer should use the index 0 of the model and should use the value of the index 2 for the editable property (which we set it to gtk.TRUE when we added the row)

The process is similar for ToggleButtons, but the property names are different and you need to set up a callback for the toggle signal to make the changes persistent. So let's create a simple model:

 model = gtk.ListStore(bool, bool)
 model.append(row=(True, True))
 model.append(row=(False, False))
This time the first value of the model holds the real data and we use the second boolean type for the 'activatable' status. Let's create the TreeView and the column:

 treeview = gtk.TreeView(model)
 renderer = gtk.CellRendererToggle()
 renderer.connect('toggled', toggled_callback, model)
 column = gtk.TreeViewColumn('test', renderer, active=0, activatable=1)
 treeview.append_column(column)
As you can see we need to setup the toggle_callback, which looks like this:

 def toggled_callback(cell, path, model=None):
     iter = model.get_iter(path)
     model.set_value(iter, 0, not cell.get_active())
This last step is important because otherwise the TreeView won't update the screen and it will look like a non activatable column.

    renderer.connect('toggled', toggled_callback, model, 1)
and update the callbacks declaration to:
 def toggled_callback(cell, path, model=None, col_num=0):

Edit this entry993 / Log info994 / Last changed on Wed Apr 6 19:41:55 2005 by Johan Dahlin (johan-at-gnome-org)


13.11.995 What signal is emitted when a user selects/clicks on a row in a GtkTreeView?

The TreeView has no "select/unselect_row" signals that the good ole CList did. You can however attach to the TreeView selection's "changed" signal:

 def on_selection_changed(selection, ...): 
     model, paths = selection.get_selected_rows()
     if paths:
        # do the thing!

 self.treeView = gtk.TreeView(mymodel)
 selection = self.treeView.get_selection()
 selection.connect('changed', on_selection_changed)
For more information on the GtkTreeSelection object, see the C docs for GTK+: [developer.gnome.org]996

(Lorenzo Gil Sanchez, David Cook)

Edit this entry997 / Log info998 / Last changed on Tue Jun 21 19:37:06 2005 by Christian Reis (kiko-at-async-com-br)


13.12.999 How do I change the color of the alternate row shading on the TreeView widget?

James Henstridge: These settings can be changed in the gtkrc file. Note however that the settings are intended for theme authors. If you set them explicitly for your app, then your app would not fit in with the rest of the apps on the desktop (the user might have specifically picked their theme because they like that shade of grey).

The gtkrc directives would look something like this:

    style "mystyle" {
        GtkTreeView::even_row_color = "xxxx"
        GtkTreeView::odd_row_color = "yyyy"
    }
You could use this to create a custom theme if you don't like how trees display on your desktop.

Edit this entry1000 / Log info1001 / Last changed on Fri Apr 25 01:10:18 2003 by Christian Reis (kiko-at-async-com-br)


13.13.1002 How do I create a lazy TreeView?

A "lazy" TreeView is one in which child rows are not actually appended to the TreeStore row until the user clicks on the expander for that row. The trick is to get the expander to show up without having to add any actual child rows.

An easy way to do this is to append a "blank" child row to each row that you know will have children. Schematically:

 if hasChildren(iter):
     store.append(iter)
Here hasChildren is some function that determines if the iter will actually have children based on the data it contains.

Then in the "row-expanded" handler, check for a NULL value in a column you are sure will never be NULL for actual data:

 def on_row_expanded(view, iter, path):
     store = view.get_model()
     child = store.iter_children(iter)
     if store.get_value(child, 0) is None:
         # append actual rows at iter
Alternatively, you could set some marker value like -1 in a particular column.

Edit this entry1003 / Log info1004 / Last changed on Thu Jun 12 12:11:44 2003 by Dave Cook (dave-at-davidcook-org)


13.14.1005 How do I show different images when a TreeView item is expanded and collapsed.

James Henstridge pointed out the pixbuf_expander_closed and pixbuf_expander_closed column properties, which Doug Quale cooked into an example (derived in part from the one in FAQ 13.61006):

  class silly_list(gtk.TreeView):
    def __init__(self):
        gtk.TreeView.__init__(self)
        self.init_model()
        self.init_view_columns()

    def init_model(self):       
        store = gtk.TreeStore(gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, str)
        # Fill the model with some silly sample data.             
        add_pixbuf = self.get_icon_pixbuf(gtk.STOCK_ADD)
        remove_pixbuf = self.get_icon_pixbuf(gtk.STOCK_REMOVE)
        for p in xrange(10):
            parent = store.append(None, (add_pixbuf, remove_pixbuf,
                                         'Parent %s' % p))
            for c in xrange(5):
                store.append(parent, (None, None, 'Child %s' % c))
        self.set_model(store)

    def get_icon_pixbuf(self, stock):
        return self.render_icon(stock,
                                size=gtk.ICON_SIZE_MENU,
                                detail=None)

    def init_view_columns(self):            
        col = gtk.TreeViewColumn()
        col.set_title('Silly Example')
        render_pixbuf = gtk.CellRendererPixbuf()
        col.pack_start(render_pixbuf, expand=False)
        col.add_attribute(render_pixbuf, 'pixbuf-expander-closed', 0)
        col.add_attribute(render_pixbuf, 'pixbuf-expander-open', 1)
        render_text = gtk.CellRendererText()
        col.pack_start(render_text, expand=True)
        col.add_attribute(render_text, 'text', 2)
        self.append_column(col)
Note: Doug also offered an example which uses the row-expanded and row-collapsed signals, which can be used when more complex behaviour is desired. The following changes should be made in this case:

    def __init__(self):
       # same as above
       self.connect('row-expanded', self.on_row_expanded)
       self.connect('row-collapsed', self.on_row_collapsed)

    def set_row_icon(self, treeiter, stock):
        store = self.get_model()
        store.set(treeiter, 0, self.get_icon_pixbuf(stock))

    def on_row_expanded(self, treeiter, path):
        self.set_row_icon(treeiter, gtk.STOCK_REMOVE)
    on_row_expanded = staticmethod(on_row_expanded)

    def on_row_collapsed(self, treeiter, path):
        self.set_row_icon(treeiter, gtk.STOCK_ADD)
    on_row_collapsed = staticmethod(on_row_collapsed)

Edit this entry1007 / Log info1008 / Last changed on Mon Sep 29 12:21:36 2003 by Christian Reis (kiko-at-async-com-br)


13.15.1009 My TreeView/TreeModel rows represent instances (or any python object), but how can I keep track of them?

Define a extra field in your TreeModel of the following type: gobject.TYPE_PYOBJECT. This field will hold the reference to the instance which the row respesents.

For Example:

 model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)

Now you can set the reference to the instance for a row like this:

 COLUMN_TEXT = 0
 COLUMN_OBJECT = 1

 # the iter is pointing to the row which you want to set
 model.set(iter, COLUMN_TEXT, unicode("Hey", 'iso-8859-1'),   COLUMN_OBJECT, theObject)

Later on if you want to get the Reference to the Instance again:

 COLUMN_TEXT = 0
 COLUMN_OBJECT = 1

 # the iter is pointing to the row which you want to get
 object = model.get_value(iter, COLUMN_OBJECT)

Edit this entry1010 / Log info1011 / Last changed on Wed Feb 11 12:53:43 2004 by Christian Reis (kiko-at-async-com-br)


13.16.1012 My Treeview shows all my strings/text values as numbers in the columns!

You're probably using the type gobject.TYPE_CHAR instead of gobject.TYPE_STRING to define the column in your store. The latter is the correct type for string data.

Edit this entry1013 / Log info1014 / Last changed on Mon Sep 29 11:36:27 2003 by Christian Reis (kiko-at-async-com-br)


13.17.1015 How do I make a popup menu appear when I right-click my TreeView?

Define a handler for the treeview's button_press_event that sets the treeview cursor and calls popup.popup(). Stephen Kennedy provides an example, assuming you have a popup menu stored as self.popup:

  def on_treeview_button_press_event(self, treeview, event):
    if event.button == 3:
        x = int(event.x)
        y = int(event.y)
        time = event.time
        pthinfo = treeview.get_path_at_pos(x, y)
        if pthinfo is not None:
            path, col, cellx, celly = pthinfo
            treeview.grab_focus()
            treeview.set_cursor( path, col, 0)
            self.popup.popup( None, None, None, event.button, time)
        return 1
Note that treeview.get_path_at_pos could return None in the case that the mouse is not over a row when the right button is clicked. You need to decide what your program should do in that case. Perhapse you want a different menu to pop up?

Edit this entry1016 / Log info1017 / Last changed on Sat Dec 31 15:30:08 2005 by Gustavo Carneiro (gjc-at-inescporto-pt)


13.18.1018 Is it possible for a TreeModel to tell a CellRendererToggle that it is in an "in between" (inconsistent) state?

The gtk.CellRendererToggle has an "inconsistent" property, similar to the "active" property. If it is set to True, then the cell will display in the inconsistent state. You can either have a column in your model that maps to the inconsistent property, or use a cell data function to set the property based on some other condition.

The C documentation lists all the CellRendererToggle's properties: [developer.gnome.org]1019

Edit this entry1020 / Log info1021 / Last changed on Mon Sep 29 11:51:45 2003 by Christian Reis (kiko-at-async-com-br)


13.19.1022 How do I change alignment on a specific cell renderer?

To right-align a cell renderer, you can alter the xalign property doing:

 renderer.set_property('xalign', 1.0)
You can add padding in the same fashion adjusting the xpad property.

Another thing to note is that renderers use the normal GTK packing mechanism. If you want one renderer to expand and take up any extra space (or `compete' for it if more than one cell has expand=TRUE), pack it with expand=TRUE, and vice-versa.

Edit this entry1023 / Log info1024 / Last changed on Mon Jan 13 13:59:04 2003 by Christian Reis (kiko-at-async-com-br)


13.20.1025 How do I keep GenericTreeModel from leaking references?

Arjan Molena added a"leak_references" property to GenericTreeModel to turn this behavior off, but in his words, "Turning this feature off (default is on, the old behaviour) will always decrement the refcount on PyObjects. This will prevent memory/refcnt leaks from happening. The Model should ensure that objects which are used as iterators are not destroyed before the iterator is destroyed. This sounds a bit silly, but there are no other way, unless we get to know when a iterator is being removed..."

If you turn off "leak_references" and don't keep careful track of your nodes, you get a good old-fashioned segfault.

One easy way to "ensure that objects which are used as iterators are not destroyed before the iterator is destroyed" is to have your model keep a dictionary or list of tree nodes so that a reference stays around until you explicitly delete it. (See FAQ 13.151026 for another method of keeping track of node references.)

 class MyTreeModel(GenericTreeModel):
      def __init__(self, ...)
 	 GenericTreeModel.__init__(self)
 	 self.set_property("leak_references", 0)
          ...
         self.nodemap = {} # a mapping from paths to nodes
          ...

      def on_get_iter(self, path):
 	 ...
         node = self.nodemap.setdefault(path, MyNodeClass(path, ...))
         return node
Here the dictionary's setdefault method returns self.nodemap[path] if it exists, otherwise the node object is created, added to the dictionary, and returned. Note that the programmer is responsible for deleting these node references when they are no longer needed by the TreeModel.

Edit this entry1027 / Log info1028 / Last changed on Mon Dec 30 21:20:02 2002 by Dave Cook (dave-at-davidcook-org)


13.21.1029 How do I get changes in my TreeModel to show up in my TreeView?

Whenever there are changes in your TreeModel, you need to emit a signal to notify the view of the change. Otherwise, your View content may become stale, in which case refreshing the View manually (via a resize or pointer movement) may show the new data. GenericTreeModel provides 4 methods for notifying the View of Model updates:

You can also emit the signals directly with the gtk.Object emit() method. See the TreeModel API reference for more info on these functions and signals: [developer.gnome.org]1030

Edit this entry1031 / Log info1032 / Last changed on Tue Dec 16 15:24:51 2003 by Christian Reis (kiko-at-async-com-br)


13.22.1033 How do I display a combo box in a Treeview?

In PyGTK 2.6+, there is now a Combo Renderer: [www.pygtk.org]1034

If you want to do it the old way:

Lorenzo Gil Sanchez writes: Currently, you can only do that with C. With Python you can create a custom CellRenderer to render the cells in the way you want. What you can not do in Python is a CellRender with edit capabilities, like a combo box. If you want a CellRenderer to support edition it must implement the CellEditable interface. There is no way to make a Python class to implement a GLib interface with the current PyGTK bindings.

Having said that, Lorenzo did provide a hacked version of a Treeview with Combos; check it out at [www.mail-archive.com]1035

Edit this entry1036 / Log info1037 / Last changed on Sat Sep 3 14:23:49 2005 by Kees Cook (kees-at-outflux-net)


13.23.1038 Why doesn't expand_row() display an expanded row for paths longer than one element?

TreeView.expand_row will expand only the exact row specified by the path. If your tree is deeper than 1 level, this means that even though the row is expanded, its parents might not be. If you want to be sure that the expanded row (specified by the path) is expanded and visible to the end-user, you need to expand all its parents rows using a loop:

  for i in range(len(path))
    treeview.expand_row(path[:i+1], gtk.FALSE)
This will be easier when pygtk wraps gtk+ 2.2 functions because the TreeView.expand_to_path() method will be available.

Edit this entry1039 / Log info1040 / Last changed on Fri Oct 17 02:40:08 2003 by Doug Quale (quale1-at-charter-net)


13.24.1041 How do I transform the value in my model before displaying it in the TreeView?

It's easy to have a gtk.CellRendererText render an integer i from your model, but it's not so easy to render f(i). The solution hinges around gtk.TreeViewColumn.set_cell_data_func, using the original CellRendererText you supply to that column, and setting the renderer's 'text' property.

Here's a quick and dirty example:

  def render_filesize(column, cell, model, iter):
      origstr = cell.get_property('text')
      sizestr = origstr + 'B' # Add a "B" for bytes after value
      cell.set_property('text', sizestr)

  model = gtk.ListStore(str, int)
  view = gtk.TreeView(model)

  column = gtk.TreeViewColumn('File', gtk.CellRendererText(), text=0)
  view.append_column(column)

  size_renderer = gtk.CellRendererText()
  size_renderer.set_property('xalign', 1.0)
  size_column = gtk.TreeViewColumn('Size', size_renderer, text=1)
  size_column.set_cell_data_func(size_renderer, render_filesize)
  view.append_column(size_column)

Edit this entry1042 / Log info1043 / Last changed on Fri Oct 17 01:32:13 2003 by Doug Quale (quale1-at-charter-net)


13.25.1044 How do I delete multiple selections?

Yang Zheng writes: pygtk does not allow treemodel.remove(iter) in the selected_foreach(...) function, so I had to store all the iterators for the selected rows and then go back to delete them. The iterator parameter of the function called by selected_foreach is not the actual treestore row iterator, so I had to get it by using treemodel.get_iter(path). Only then was I abe to use treemodel.remove(iter) to remove the row. Here's my code:

  # list that stores all the iterators of the selected rows
  selectList = []
  # function to get iterator of selected row
  def GetSelectedIter(model,path,iter,rowList):
    selectIter = model.get_iter(path)
    rowList.append(selectIter)

  # get reference to each row 
  selection = watchvar_treeview.get_selection()
  selection.selected_foreach(GetSelectedIter,selectList)
  # actual removal of rows
  for iter in selectList:
    watchvar_treestore.remove(iter)
As of at least v2.4 the above can be simplified somewhat with the use of selection.get_selected_rows:
    selection = treeview.get_selection()
    model, selected = selection.get_selected_rows()
    iters = [model.get_iter(path) for path in selected]
    for iter in iters:
         model.remove(iter)

Edit this entry1045 / Log info1046 / Last changed on Wed Dec 22 14:09:44 2004 by Chris Lambacher (lambacck-at-computer-org)


13.26.1047 How do I perform an action when the user clicks on the title column of a TreeView?

The TreeViewColumn has a "clicked" signal, which you can attach any callback to. More information at [www.moeraki.com]1048

The callback will receive as an argument the clicked column instance, and you can either attach data to the TreeViewColumn or pass user data in when you connect the signal (for example a key or column number). You'll usually do this when adding the columns to the TreeView.

(David Cook)

Edit this entry1049 / Log info1050 / Last changed on Mon Nov 17 12:17:39 2003 by Christian Reis (kiko-at-async-com-br)


13.27.1051 How do I run a command for each TreeModel row, or how does TreeModel.foreach() work?

TreeModel offers a foreach() function that invokes a function for each row in the model. It takes a handler function and an optional user_data argument which allows arbitrary data to be specified to the function. The function receives as parameters: model, path, iter, and when specified, the user_data supplied to foreach().

  def foreach_handler(model, path, iter, user_data):
    # get value from current row, column 1
    val1 = model.get_value(iter, 1)
    print "value is: %s" % val1
    # set user_data ("my value") as value of current row, column 2
    model.set_value(iter, 2, user_data)

  treemodel.foreach(foreach_handler, "my value")
(Yang Zheng)

Edit this entry1052 / Log info1053 / Last changed on Wed Sep 8 04:08:13 2004 by Doug Quale (quale1-at-charter-net)


13.28.1054 When connecting to 'row-inserted', my model value is always None. Why?

Short answer: you should probably be using 'row-changed' instead of 'row-inserted'. Doug Quale elaborates on the rationale behind this below.

This gotcha seems to be almost certain to trip up everyone at some point. When the 'row-inserted' signal is emitted, the model frequently (always?) contains unitialized (empty) rows. The reason for this is kind of odd, but it's a logical consequence of the gtk+ C API.

If you look at the C API, there's no way to add an initialized row to a TreeModel in one step. The available functions like ListStore.append() and ListStore.insert() add new uninitialized rows to the model and you must subsequently use ListStore.set() to set the column values in the row. This seems harmless, but gtk+ emits the 'row-inserted' signal as soon as the empty row is added and confusion and befuddlement ensues in the signal handlers.

Because of this, the 'row-inserted' signal isn't very useful. Most of the time when you might think you want 'row-inserted' you actually want 'row-changed' instead. This will catch the ListStore.set() which almost inevitably follows an insert. Try changing your handler to be called on 'row-changed' instead of 'row-inserted' to see if that works better. Or you can leave the handler as it is and add a new 'row-changed' handler to set the correct row values when they are set in the model.

Edit this entry1055 / Log info1056 / Last changed on Wed Nov 19 11:00:35 2003 by Christian Reis (kiko-at-async-com-br)


13.29.1057 How do I use a python object to store data for all the columns in a row?

Here's an example for how to use a python dict object to store row data:

   def dict_cell_data_func(column, cell, model, iter, col_key):
     text = model.get_value(iter, col_key[0])[col_key[1]]
     cell.set_property("text", text)

   model = gtk.ListStore(object)
   tree_view = gtk.TreeView(model)
   renderer = gtk.CellRendererText()
   column = gtk.TreeViewColumn("Foo", renderer)
   column.set_cell_data_func(renderer, dict_cell_data_func, (0, 'foo'))
   tree_view.append_column(column)

   obj = {'foo': 'foo text'}
   model.append([obj])

Edit this entry1058 / Log info1059 / Last changed on Fri Jan 30 21:09:22 2004 by Jeff Bowden (jlb-at-houseofdistraction-com)


13.30.1060 How do I move rows around in a GtkTreeView?

The trick is getting an iter for the row you want to move to, and then reassigning to another row in the model. An example handler which moves the selected row up follows.

Remember to send in model as the second argument to the connect handler, like this:

 button.connect("clicked", button_clicked_cb, model)
To move a row up one step, define button_clicked_cb like this:

 def button_clicked_cb(button, model):
   selection = model.get_selection()
   model, selected = selection.get_selected()
   assert not selected is None
   path = model.get_path(selected)
   row = path[0]
   assert row > 0
   this = model[row][0]
   prev = model[row-1][0]
   model[row-1][0] = this
   model[row][0] = prev
   selection.select_path(row-1)
This handler assumes you have a 1-column model; if you have more than one column the [0] indexes would have to be changed accordingly. Note also that you may use get_value/set_value instead of the __getitem__/__setitem__ protocol as per FAQ 13.21061.

This handler takes a model, which should be specified as the optional "user_data" argument while connect()ing. You may of course obtain the model reference through other means, such as via an instance variable.

In case you have an iter and need to obtain a corresponding path to it, just use the model's get_path() method, which takes an iter. From this path you can obtain the row id. (There is no iter_prev() method corresponding to the model's iter_next()).

(Doug Quale)

Edit this entry1062 / Log info1063 / Last changed on Tue Jan 27 12:52:12 2004 by Johan Dahlin (johan-at-gnome-org)


13.31.1064 How do I change the color of a row or column of a TreeView?

To change the color of an entire column, you can change the foreground and background properties of the renderer:

 renderer = gtk.CellRendererText()
 renderer.set_property("foreground", "red")
 # ... and use renderer in TreeViewColumn 
To change the color of specific rows or cells in a TreeView, use the foreground and background arguments to GtkTreeViewColumn. The example below demonstrates their usage:

 model = gtk.ListStore(str, str, str, str)
 model.append(("Henrik","Ibsen","green","#23abff"))
 model.append(("Samuel","Beckett","orange","OldLace"))
 model.append(("Thomas","Mann","yellow","peach puff"))
 treeview = gtk.TreeView(model)
 renderer = gtk.CellRendererText()
 treeview.append_column(gtk.TreeViewColumn("First Name", renderer, 
                        text=0, foreground=2, background=3))
 treeview.append_column(gtk.TreeViewColumn("Last Name", renderer,
                        text=1, foreground=3, background=2))
As always with TreeViewColumn, the arguments indicate which field in the module carries the relevant value. For the first column in the first row, for instance, text will come from field 0 ("Henrik"), background colour from field 2 ("#23abff").

(Walter Anger)

Edit this entry1065 / Log info1066 / Last changed on Mon Mar 8 18:27:27 2004 by Christian Reis (kiko-at-async-com-br)


13.32.1067 How do I select [or edit] a row in my TreeView?

Using a path, as per FAQ 13.31068, you can do something like:

 # assuming treeview is instantiated
 sel = treeview.get_selection()
 sel.select_path(path)
If you would like to prepare the row you're targeting for editing (leaving the cursor in edit mode inside a certain cell), note that you don't need to select the row; all you need is to do:

 treeview.set_cursor(path, focus_column, start_editing=True)
where focus_column is the column you'd like to focus the cursor and edit.

Note that the scroll_to_cell() call may come in handy given that the cell you want to edit may not be on-screen. Dave Aitel points out that it may be necessary to place scroll_to_cell in an idle handler after your set_cursor call or it won't work (at least in Redhat9).

Edit this entry1069 / Log info1070 / Last changed on Sun Mar 5 00:30:50 2006 by Phillip Calvin (phillipc-at-toasterlogic-com)


13.33.1071 How do I handle DnD operations in a GtkTreeView?

There are generally two types of DnD operations that can be done regarding a GtkTreeView:

Furthermore, there are two ways to enable DnD for a GtkTreeView:

Note that these functions behave differently:

Using the functions together yields the possibility of dropping external objects onto the column titles but not into the blank area. reorderable() can be used. FAQ 13.341072 includes code examples of these approaches.

Edit this entry1073 / Log info1074 / Last changed on Fri Apr 9 13:21:22 2004 by Christian Reis (kiko-at-async-com-br)


13.34.1075 How do I work with the reorderable() property of GtkTreeview?/The reorderable() property of GtkTreeView is too limited

The use of reorderable() is described in the Reference. On occasions you may find that it is too limited though:

For example, when a reparenting of rows via DnD is needed, reorderable() won't do. For these cases Walter Anger created an example that covers a reorderable GtkTreeView exaustively (more discussion on the topic can be found in the mailing list thread starting at: [www.daa.com.au]1076 ) This example is also useful for a better insight into DnD in GtkTreeViews.

Such a custom made implementation of reorderable() consists of four parts:

Proper setup of the GtkTreeView with the appropriate DnD functions:

 treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
				 [("example", 0, 0)], gtk.gdk.ACTION_COPY)
 treeview.enable_model_drag_dest([("example", 0, 0)],
 				gtk.gdk.ACTION_COPY)
 treeview.connect("drag_data_received", on_dragdata_received_cb)
A callback for generic DnD handling:
 def on_dragdata_received_cb(treeview, drag_context, x, y,
 						    selection, info, eventtime):
         model, iter_to_copy = treeview.get_selection().get_selected()
         temp = treeview.get_dest_row_at_pos(x, y)
         if temp != None:
             path, pos = temp
         else:
             path, pos = (len(model)-1,), gtk.TREE_VIEW_DROP_AFTER
         target_iter = model.get_iter(path)
         if check_row_path(model, iter_to_copy, target_iter):
             iter_copy(model, iter_to_copy, target_iter, pos)
             drag_context.finish(gtk.TRUE, gtk.TRUE, eventtime)
             treeview.expand_all()
         else:
             drag_context.finish(gtk.FALSE, gtk.FALSE, eventtime) 
The treeview.get_dest_row_at_pos(x, y) will be None if you drop the selection on the empty section at the bottom of the TreeView. In that case, set the path and pos from scratch.

A checking function for ancestry and equality of the row:

 def check_row_path(model, iter_to_copy, target_iter):
         path_of_iter_to_copy = model.get_path(iter_to_copy)
         path_of_target_iter = model.get_path(target_iter)
         if path_of_target_iter[0:len(path_of_iter_to_copy)] ==
 	    path_of_iter_to_copy:
             return False
         else:
             return True
And finally the row DnD function:
 def iter_copy(model, iter_to_copy, target_iter, pos):

   	[...retrieve data of the selected row...]

         if (pos == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE) or (pos ==
 	     gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
             new_iter = model.prepend(target_iter, None)
         elif pos == gtk.TREE_VIEW_DROP_BEFORE:
             new_iter = model.insert_before(None, target_iter)
         elif pos == gtk.TREE_VIEW_DROP_AFTER:
             new_iter = model.insert_after(None, target_iter)

 	[...copy over the values of the old row into the new one ...]

         for n in range(model.iter_n_children(iter_to_copy)): 
             next_iter_to_copy = model.iter_nth_child(iter_to_copy, n)
             iter_copy(model, next_iter_to_copy, new_iter,
 		 gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)

 	[...remove old row...]
As said earlier, this implementation allows one to reparent rows via DnD. Of course, when this is not needed, editing out the concerned parts will do just fine.

If you're moving the data instead of copying it, change the .iter_nth_child(iter_to_copy, n) in the last part to be .iter_nth_child(iter_to_copy, 0). As you move items, next siblings all move down.

Edit this entry1077 / Log info1078 / Last changed on Thu Aug 5 23:43:27 2004 by Paul Dickson (dickson-at-permanentmail-com)


13.35.1079 How do I use the TreeModelFilter to process tree/store data automatically?

The TreeModelFilter is not just useful for filtering data from a model; it can be used to synthesize completely new columns that were never in the original model. The example code below generates a filtered version of a ListStore, with 2 string columns, from an original model with only one column of Python objects. This filtered model can then be used in TreeViews and ComboBoxes in the usual fashion. This is a powerful way to abstract your application model (your business objects) from the view (the way they are displayed.) For more info on TreeModelFilter see the PyGTK tutorial (FAQ 1.91080.)

 import gtk

 # A "business object" class.  Instances will be nodes of our TreeStore.
 class Person(object):
     def __init__(self, lastname='', firstname=''):
         self.lastname = lastname
 	 self.firstname = firstname

 # Create some person objects
 people = [['Ellison', 'Larry'], ['Gates', 'Bill'], ['McNealy', 'Scott']]
 nodes = [Person(*names) for names in people]

 # Put the objects in a store.
 store = gtk.ListStore(object) # A store with only Python objects.
 for node in nodes: store.append([node])

 # Here we use a ModelFilter to synthesize values on the fly using the 
 # modify_func callback.  These values can be used for interactive 
 # searches and ComboBoxes, whereas the original store of Python objects would 
 # not be understood as valid strings by gtk.  The original TreeModel is 
 # a "child" of the ModelFiter.

 # obtain a ModelFilter from our store
 filtered = store.filter_new()

 # The modify func is where the values in the ModelFilter are computed from
 # the the objects in the child model.
 def modify_func(model, iter, col, attrs):
     # Convert the filter iter to the corresponding child model iter.
     child_model_iter = model.convert_iter_to_child_iter(iter)
     child_model = model.get_model()
     obj = child_model.get_value(child_model_iter, 0)
     return getattr(obj, attrs[col])

 # Set the modify func, passing in the "virtual" column types.  The
 # last parameter is user data to specify the attributes/properties of the 
 # business objects that we want to display.
 filtered.set_modify_func([str]*2, modify_func, ['lastname', 'firstname'])

 # Callback for printing out nodes.
 def print_node(model, path, iter):
     print [model.get_value(iter, i) for i in range(model.get_n_columns())]

 # Print out the contents of the ModelFilter.
 filtered.foreach(print_node)

 # Modify the original objects directly.
 people = [['van Rossum', 'Guido'], ['Torvalds', 'Linus'], ['Henstridge', 'James']]
 for node, names in zip(nodes, people):
     node.lastname, node.firstname = names

 # Does the ModelFilter track our changes?    
 filtered.foreach(print_node)
(David Cook, John Finlay)

Edit this entry1081 / Log info1082 / Last changed on Mon Jul 5 21:31:47 2004 by Daverz (dave-at-davidcook-org)


13.36.1083 How do I unselect a path in a TreeView?

If all you need to do is query and change the current cursor state, you can use the gtk.TreeView class functions set_cursor() and get_cursor().

However, the gtk.TreeView class functions don't directly let you do more complex selection work, such as unselecting everything in a TreeView, or unselecting anything at all for that matter.

However, a TreeSelection object lets you do that just those sorts of things. You can get the TreeSelection object associated with any Treeview with the TreeView's get_selection() member function.

Every Treeview has one gtk.TreeSelection object associated with it. This object is associated with the TreeView, not its underlying model. (So if a particular model has multiple views, each view will have a separate selection object associated with it.)

As an example, to unselect the path of the current cursor:

  path, focus_column = treeview.get_cursor()

  treeview.get_selection().unselect_path(path)
There are also functions select_range() and unselect_range() to do the (un)selections on ranges of paths.

Edit this entry1084 / Log info1085 / Last changed on Mon Jul 19 06:56:55 2004 by Mark Shewmaker (mark-at-primefactor-com)


13.37.1086 How do I avoid displaying (hide) a certain column in a TreeView?

As with most column operations, just use the appropriate TreeColumn method; in this case, TreeViewColumn.set_visible: [www.pygtk.org]1087

(the great John Finlay)

Edit this entry1088 / Log info1089 / Last changed on Wed Jul 21 14:31:09 2004 by Christian Robottom Reis (kiko-at-async-com-br)


13.38.1090 How do I display pixbufs instead of numbers for integer or boolean values in my treemodel?

This is an example of changing the data type or format of a treemodel column before displaying it. The general technique for these problems is to use a cell data function to modify the value before setting the appropriate cell renderer property to display it. The same idea will work to control the formatting of a text cell, for example to format a number before displaying it.

The cell data function is straightforward. We set the 'pixbuf' cell property to the pixbuf to display or None for a blank column. Replace MODEL_COLUMN_NUMBER with the model column number that provides the value and MY_PIXBUF with the pixbuf you want to display:

    def cell_data_func(tree_column, cell, model, tree_iter):
        if model.get_value(tree_iter, MODEL_COLUMN_NUMBER):
            pixbuf = MY_PIXBUF
        else:
            pixbuf = None
        cell.set_property('pixbuf', pixbuf)
There are several ways to set up a treeview column to use a data function. Here is one example:

    cell = gtk.CellRendererPixbuf()
    treeview.insert_column_with_data_func(-1, 'title xxx', cell,
         cell_data_func)
It's worthwhile to look at the properties provided by each type of cell renderer. CellRendererPixbuf has 'stock-id' and 'stock-size' properties that can be very useful if you want to use stock icons instead of your own pixbufs. To display the stock gtk+ yes and no icons for a boolean model column you can do something like this:

    def cell_data_func(tree_column, cell, model, tree_iter):
        if model.get_value(tree_iter, MODEL_COLUMN_NUMBER):
            stock_id = 'gtk-yes'
        else:
            stock_id = 'gtk-no'
        cell.set_property('stock-id', stock_id)

Edit this entry1091 / Log info1092 / Last changed on Fri Aug 20 20:42:51 2004 by Doug Quale (quale1-at-charter-net)


13.39.1093 I defined a TreeView in glade, how do I manipulate its columns and other properties?

Glade's support for TreeView is somewhat limited: you can only define a "blank" treeview. You must create the columns, set the model and (optionally) set other properties entirely in Python code.

Note that you get hold of your glade-defined treeview using get_widget("treeview1") as you would for any other widget in the glade widget tree. From there on you can use treeview API to add columns, set its model, and manipulate its configuration. An example follows:

  glade = gtk.glade.XML("stuff.glade")
  treeview1 = glade.get_widget("treeview1")

  # add columns:
  C_DATA_COLUMN_NUMBER_IN_MODEL = 0
  cell0 = gtk.CellRendererText()
  col0 = gtk.TreeViewColumn("title", cell0,    
                            text=C_DATA_COLUMN_NUMBER_IN_MODEL)
  treeview1.append_column(col0)

  # set model (i.e. the data it contains)
  store = gtk.TreeStore(gobject.TYPE_STRING)
  treeview1.set_model(store)

  # set reorderable
  treeview1.set_reorderable(True)

  # to add a row see FAQ 13.21094

Edit this entry1095 / Log info1096 / Last changed on Thu Sep 23 00:42:46 2004 by Christian Robottom Reis (kiko-at-async-com-br)


13.40.1097 How do I change the font of a CellRendererText?

If you want to have *all cells* in a column use a specific font use the "font" or "font-desc" properties of the column's cell renderer. See [www.pygtk.org]1098 for details.

  model = gtk.ListStore(str, str)
  tv = gtk.TreeView(model)

  cell = gtk.CellRendererText()
  font = pango.FontDescription('courier bold 12')
  cell.set_property('font-desc', font)
  col = gtk.TreeViewColumn('This column in courier-bold-12!', cell, text=0)
  tv.append_column(col)

  cell = gtk.CellRendererText()
  col = gtk.TreeViewColumn('default font', cell, text=1)
  tv.append_column(col)

  model.append(('cell with changed font', 'cell with default font'))
If you want to have individual cells of a column use a different font, you can have the font attribute set from a model column value:

  model = gtk.ListStore(str, str)
  tv = gtk.TreeView(model)

  cell = gtk.CellRendererText()
  col = gtk.TreeViewColumn('header', cell, text=0, font=1)
  tv.append_column(col)

  model.append(('This text in arial bold 12', 'arial bold 12'))
  model.append(('And this in courier 14', 'courier 14'))
  model.append(('And yet this in mono 12', 'mono 12'))
You can do more complex changes to the font by using pango markup in your text columns. There is a section of the tutorial that covers this in depth: [www.pygtk.org]1099

(John Finlay, examples by Guilherme Salgado)

Edit this entry1100 / Log info1101 / Last changed on Fri Nov 19 01:28:19 2004 by Christian Robottom Reis (kiko-at-async-com-br)


13.41.1102 How do I show a GtkImage (even animations) in a treeview? (subclassing GtkCellRenderer)

Here is a cellrenderer that allows to put a gtk.Image in your TreeStore :

 class CellRendererImage(gtk.GenericCellRenderer):

   __gproperties__ = {
      "image": (gobject.TYPE_OBJECT, "Image",
      "Image", gobject.PARAM_READWRITE),
   }

   def __init__(self):
      self.__gobject_init__()
      self.image = None

   def do_set_property(self, pspec, value):
      setattr(self, pspec.name, value)

   def do_get_property(self, pspec):
      return getattr(self, pspec.name)

   def func(self, model, path, iter, (image, tree)):
      if model.get_value(iter, 0) == image:
         self.redraw = 1
         cell_area = tree.get_cell_area(path, tree.get_column(0))
         tree.queue_draw_area(cell_area.x, cell_area.y, cell_area.width, \

            cell_area.height)

   def animation_timeout(self, tree, image):
      if image.get_storage_type() == gtk.IMAGE_ANIMATION:
         self.redraw = 0
         image.get_data('iter').advance()
         model = tree.get_model()
         model.foreach(self.func, (image, tree))
         if self.redraw:
            gobject.timeout_add(image.get_data('iter').get_delay_time(), \
               self.animation_timeout, tree, image)
         else:
            image.set_data('iter', None)

   def on_render(self, window, widget, background_area,cell_area, \
      expose_area, flags):
      if not self.image:
         return
      pix_rect = gtk.gdk.Rectangle()
      pix_rect.x, pix_rect.y, pix_rect.width, pix_rect.height = \
         self.on_get_size(widget, cell_area)

      pix_rect.x += cell_area.x
      pix_rect.y += cell_area.y
      pix_rect.width  -= 2 * self.get_property("xpad")
      pix_rect.height -= 2 * self.get_property("ypad")

      draw_rect = cell_area.intersect(pix_rect)
      draw_rect = expose_area.intersect(draw_rect)

      if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:

         if not self.image.get_data('iter'):
            animation = self.image.get_animation()
            self.image.set_data('iter', animation.get_iter())
            gobject.timeout_add(self.image.get_data('iter').get_delay_time(), \
               self.animation_timeout, widget, self.image)

         pix = self.image.get_data('iter').get_pixbuf()
      elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
         pix = self.image.get_pixbuf()
      else:
         return
      window.draw_pixbuf(widget.style.black_gc, pix, \
         draw_rect.x-pix_rect.x, draw_rect.y-pix_rect.y, draw_rect.x, \
         draw_rect.y+2, draw_rect.width, draw_rect.height, \
         gtk.gdk.RGB_DITHER_NONE, 0, 0)

   def on_get_size(self, widget, cell_area):
      if not self.image:
         return 0, 0, 0, 0
      if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:
         animation = self.image.get_animation()
         pix = animation.get_iter().get_pixbuf()
      elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
         pix = self.image.get_pixbuf()
      else:
         return 0, 0, 0, 0
      pixbuf_width  = pix.get_width()
      pixbuf_height = pix.get_height()
      calc_width  = self.get_property("xpad") * 2 + pixbuf_width
      calc_height = self.get_property("ypad") * 2 + pixbuf_height
      x_offset = 0
      y_offset = 0
      if cell_area and pixbuf_width > 0 and pixbuf_height > 0:
         x_offset = self.get_property("xalign") * (cell_area.width - \
            calc_width -  self.get_property("xpad"))
         y_offset = self.get_property("yalign") * (cell_area.height - \
            calc_height -  self.get_property("ypad"))
      return x_offset, y_offset, calc_width, calc_height
Don't forget to register this class with:

 gobject.type_register(CellRendererImage)
Then use it as another cellrenderer:

 col = gtk.TreeViewColumn()
 cell = CellRendererImage()
 col.pack_start(cell, False)
 col.add_attribute(cell, 'image', 0)

Edit this entry1103 / Log info1104 / Last changed on Wed May 4 07:36:11 2005 by Nikos Kouremenos (kourem-at-gmail-com)


13.42.1105 How do I show a picture (image) in a treeview background or exist any way how to set treeview (and window with treeview) as transparency ?

R U KIDDING ME?

Edit this entry1106 / Log info1107 / Last changed on Wed May 4 07:33:15 2005 by Nikos Kouremenos (kourem-at-gmail-com)


13.43.1108 Are there tips for improving performance when adding many rows to a Treeview?

Sure.

  model.set_default_sort_func(lambda *args: -1) 
  model.set_sort_column_id(-1, gtk.SORT_ASCENDING)
  view.set_model(None)
  # load data into the model
  view.set_model(model)

 rows = [r for r in model]
sort them using the built-in Python list sort, and reload them. The built-in sort can be quite efficient if you use the 'key' option:

 rows.sort(key=your_sort_key_callable)
See the sorting mini-howto: [wiki.python.org]1110 For the second click on a column, you can use rows.reverse(). The downside of this approach is that you'll have to manage the column sort indicators yourself.

Edit this entry1111 / Log info1112 / Last changed on Mon Jun 12 22:00:19 2006 by Daverz (dave-at-davidcook-org)


13.44.1113 What is TreeRowReference and how to use it?

TreeRowReference can be used when you to 'follow' a position of a row that the user may reorder (eg the path will change).

Everytime you need the path you do tree_row_ref.get_path() and you get the current path

and to create a new tree_row_ref that you can use follow:

 iter = model.append(None, 'LSD')
 path = self.tree.get_path(iter)
 tree_row_ref = gtk.TreeRowReference(tree_model, path)
For extreme situtations you may find these fuctions from the API useful: [pygtk.org]1114

Edit this entry1115 / Log info1116 / Last changed on Fri Jul 22 16:11:28 2005 by Nikos Kouremenos (kourem-at-gmail-com)


13.45.1117 How do I create a custom gtk.CellRenderer?

In order to render custom objects in TreeViews you have to subclass the gtk.GenericCellRenderer class and register it.

The following example shows a CellRenderer for a custom object.

 class CellRendererCustom(gtk.GenericCellRenderer):
        __gproperties__ = {
                "custom": (gobject.TYPE_OBJECT, "Custom",
                "Custom", gobject.PARAM_READWRITE),
        }

        def __init__(self):
                self.__gobject_init__()
                self.custom = None

        def do_set_property(self, pspec, value):
                setattr(self, pspec.name, value)

        def do_get_property(self, pspec):
                return getattr(self, pspec.name)

        def on_render(self, window, widget, background_area, cell_area, expose_area, flags):
                self.custom.draw(window, widget, cell_area.x, cell_area.y)

        def on_get_size(self, widget, cell_area=None):
                return (0, 0, self.custom.get_width(), self.custom.get_height())

 gobject.type_register(CellRendererCustom)
Note that in order to use the custom object in e. g. a ListStore you'll have to subclass it from gobject.GObject and register it properly.

Edit this entry1118 / Log info1119 / Last changed on Thu Apr 13 10:03:17 2006 by Christoph Leuzinger (leuzi-at-trash-net)


14. Editables: GtkEntry, GtkCombo, GtkText, GtkSpinButton, GtkTextView


14.1.1120 How do I make a GtkEntry exactly 5 characters long?

here are three methods; the third method is prone to breakage if the font size is changed.

a) just call

  entry.set_width_chars(5)
or:

b) On older gtk+ only, according to Jamesh; first get a reference to the font used by the entry:

    font = entry.get_style().font
then you can measure a string:

 width = font.width('55555')
then set the width:

 entry.set_usize(width, -1)
although that doesn't take padding or anything into account, and if you pack the widget telling it to expand or fill, it will grow larger than that width (set_usize sets a minimum size).

Note that this must be done at runtime if the size is to adapt to a font selected through themes.

c) On older gtk+ only, measure and set a fixed size in pixels using glade or set_usize. argh.

Edit this entry1121 / Log info1122 / Last changed on Fri May 19 22:13:23 2006 by Danny Milosavljevic (danny-milo-at-gmx-net)


14.2.1123 What is a GtkTextIter, and how do I get one for position X (and other positions)?

James Henstridge and Pier Carteri help us out:

Text iters represent a position in the text buffer. You can create them with a GtkTextBuffer object as follows.

To get an iter for the current line:

  line_iter = text_buffer.get_iter_at_line_offset(linenum, charoffset)
For a specified offset:

  offset_iter = text_buffer.get_iter_at_offset(charoffset)
To get iters at the buffer bounds:

  start_iter = text_buffer.get_start_iter()
  end_iter = text_buffer.get_end_iter()
or in a more compact form:

  start_iter, end_iter = text_buffer.get_bounds()
To get an iter at the current cursor position, do:

  iter_here = text_buffer.get_iter_at_mark(text_buffer.get_insert())
There are a few other text buffer methods for creating iters, but those should be enough most of the time. You can then use iter methods to advance by chars, words or lines, etc:

  iter.backward_char()
  iter.forward_char()

  iter.forward_word_end()
  iter.backward_word_start()

  iter.forward_line()
  iter.backward_line()
See the complete GtkTextIter reference at [www.pygtk.org]1124

Edit this entry1125 / Log info1126 / Last changed on Tue Jan 27 12:48:40 2004 by Johan Dahlin (johan-at-gnome-org)


14.3.1127 How do I change the cursor for a GtkEntry?

The GtkEntry is composed of two GdkWindows, one for the black border around it, and one for the white editable area. To change the cursor for both:

 watch = gtk.cursor_new(GDK.WATCH)
 gdkwin = entry.get_window()
 gdkwin.set_cursor(watch)
 # the gdkwin has a child window, which is for the editable area 
 gdkwin.children[0].set_cursor(watch)
See faq 5.61128 for more on cursor changing.

Edit this entry1129 / Log info1130 / Last changed on Thu Jul 11 12:39:02 2002 by Christian Reis (kiko-at-async-com-br)


14.4.1131 Why does GtkText's insert_text generate critical messages complaining "assertion `index <= TEXT_LENGTH (text)' failed."?

Due to a PyGTK bug in all versions up to 0.6.11, insert_text works with GtkText, but generates GTK critical warnings, even though it is defined for all GtkEditables.

The workaround is to use insert_defaults(), which works and doesn't generate warnings. It has one nasty side-effect: see faq 14.71132

For the original message explaining this, see [www.mail-archive.com]1133

insert_text has been fixed (in the same patch that added the position argument to GtkEditable.insert_text()) in version 0.6.10 and should be used if that version is available.

Edit this entry1134 / Log info1135 / Last changed on Mon Sep 23 17:43:09 2002 by Christian Reis (kiko-at-async-com-br)


14.5.1136 I want to change the text being typed into an entry or textbox, but the original text is also inserted!

A common need is to handle text being inserted into an entry or textbox, but change that text on-the-fly. As an example, Pier Carteri wrote the mailing list asking how he could expand tabs typed into spaces; however, the original tab was still being inserted.

The general solution to this is to use two functions, one as a "proxy" callback that calls emit_stop_by_name() and idle_add()s the real function. It could work something like this:

 def insert_cb(widget, text, length, *args):
    # if you don't do this, garbage comes in with text
    text = text[:length]
    pos = widget.get_position()
    # stop default emission
    widget.emit_stop_by_name("insert_text")
    gtk.idle_add(insert, widget, text, pos)

 def insert(widget, text, pos):
    # the next three lines set up the text. this is done because we
    # can't use insert_text(): it always inserts at position zero.
    orig_text = widget.get_text()
    text = string.replace(text, " ", "<SPACE>")
    new_text = orig_text[:pos] + text + orig_text[pos:]
    # avoid recursive calls triggered by set_text
    widget.signal_handler_block(insert_sig)
    # replace the text with some new text
    widget.set_text(new_text)
    widget.signal_handler_unblock(insert_sig)
    # set the correct position in the widget
    widget.set_position(pos + len(text))

 entry = gtk.GtkEntry()
 signal = entry.connect("insert_text", insert_cb)
Some notes about this approach:

Edit this entry1137 / Log info1138 / Last changed on Mon Jul 22 11:57:42 2002 by Christian Reis (kiko-at-async-com-br)


14.6.1139 Why does the second parameter to insert_text (the `text' parameter) contain garbage?

If you connect to the insert_text signal of an editable, you will notice very quickly that the second parameter contains garbage. The function signature has the following format:

 def on_insert_text(widget, text, len, *args):
   pass
The text parameter will contain garbage, which is no good for us. So you should split the text accordingly using something like:

 text = text[:len]
This is something of a bug in GTK+ that bleeds into PyGTK, says James. "This is not a bug I can correct for (easily). Gtk claims that the text argument to the signal is a G_TYPE_STRING argument, which is accepted to mean "standard NUL terminated C string" everywhere else in gtk+. This is the one handler where they are using G_TYPE_STRING with a non NUL terminated string, so things go weird." (QED)

Edit this entry1140 / Log info1141 / Last changed on Tue Jul 23 01:12:46 2002 by Christian Reis (kiko-at-async-com-br)


14.7.1142 Why isn't GtkText.insert_defaults() generating the signal insert_text

It seems to be a GTK+ bug. You can get away with attaching a callback to the changed signal and then calling changed() manually after insert_defaults() is called:

  text.connect("insert_text", self._insert_text)
  text.connect("changed", self._insert_text)
  text.insert_defaults("GTK+ is broken") # generates no signals :-(
  self.changed()                         # triggers changed()

Edit this entry1143 / Log info1144 / Last changed on Mon Sep 23 17:17:38 2002 by Christian Reis (kiko-at-async-com-br)


14.8.1145 How do I get the currently selected text in a GtkCombo?

The GtkCombo inherits from a GtkHBox, and contains both a GtkEntry and a GtkButton, but it offers a convenience attribute that gets the entry back for you. Since the current selection is held in the GtkCombo's GtkEntry, use something like:

 text = combo.child.get_text()

Edit this entry1146 / Log info1147 / Last changed on Sun Jul 17 19:08:33 2005 by Phillip Calvin (phillipc-at-toasterlogic-com)


14.9.1148 How do I programatically set the max value for a GtkSpinButton?

Steve McClure offered the following answer to Greg Ward:

 # Sets the upper limit from 99...
 adj = GtkAdjustment(1, 1, 99, 1, 1, 1)
 sb = GtkSpinButton(adj, 1, 0)
 # ... to 5
 my_adj = sb.get_adjustment()
 my_adj.upper = 5
 my_adj.set_all(my_adj.value, my_adj.lower, my_adj.upper,
                my_adj.step_increment, my_adj.page_increment, 
                my_adj.page_size)
 # isn't that the darndest API I've seen
set_all() actually applies the changes done to the adjustment's member attributes.

Edit this entry1149 / Log info1150 / Last changed on Thu Mar 20 20:07:16 2003 by Christian Reis (kiko-at-async-com-br)


14.10.1151 How do I scroll a TextView to display the text being inserted?

When inserting text using insert_at_custor(), it may happen that the text inserted surpasses the textview's current viewport, and requires scrolling.

Gustavo Carneiro and Mikoyan wrote in to suggest using the textbuffer's scroll_to_mark() method, which scrolls to a certain point in the buffer. You can use the get_insert() method to return the current insert position right after inserting if you want to make sure you scroll to the end of the text.

  end_iter = text_buffer.get_end_iter()
  text_buffer.insert(end_iter, text)
  text_view.scroll_to_mark(text_buffer.get_insert(), 0)
There is also a simplier method to make sure the text view's cursor is visible:

  text_view.scroll_mark_onscreen(text_buffer.get_insert())

Edit this entry1152 / Log info1153 / Last changed on Tue Jan 27 12:45:07 2004 by Johan Dahlin (johan-at-gnome-org)


14.11.1154 How do I insert colored text into a TextView?

Someone on #pygtk (probably gjc) was nice enough to send me this code snippet when I was trying to make a color coded log window. Keep in mind, that naming a TextTag "blue" is considered bad form - you want to name it after what it represents.

 tag_table = text_buffer.get_tag_table()

 warn_tag = gtk.TextTag("warning")
 warn_tag.set_property("foreground", "blue")
 tag_table.add(warn_tag)

 sob, eob = text_buffer.get_bounds()
 text_buffer.insert_with_tags_by_name(eob, "This is a warning", "warning")

Edit this entry1155 / Log info1156 / Last changed on Tue Jan 27 12:44:22 2004 by Johan Dahlin (johan-at-gnome-org)


14.12.1157 How can I make GtkTextView to always show the last line

Dan Christian writes:

The way that I did it for a scrolling text window is to set a mark at the end of the buffer like this:

 mark = text_buffer.create_mark("end", text_buffer.get_end_iter(), False)
Then (after every text addition), I tell it to scroll to the end, like this:

 text_view.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
The mark will "do the right thing" about where it is in the buffer and how the idle task works.

Edit this entry1158 / Log info1159 / Last changed on Tue Jan 27 12:42:36 2004 by Johan Dahlin (johan-at-gnome-org)


14.13.1160 How do I add items into GtkCombo

This code add one or many items to GtkCombo object named combo

Just add one item like this

 listitem = gtk.ListItem("String 1")
 combo.list.append_items([Listitem])
 listitem.show()
Or if you like you can add two:

 listitem_a = gtk.ListItem("String 2")
 listitem_b = gtk.ListItem("String 3")
 combo.list.append_items([listitem_a, listitem_b])
 listitem_a.show()
 listitem_b.show()

Edit this entry1161 / Log info1162 / Last changed on Tue Jan 27 12:42:01 2004 by Johan Dahlin (johan-at-gnome-org)


14.14.1163 How can get back the strings that I set using Combo.set_popdown_strings()

I don't think it's actually supposed to be done; if you look at the GTK+ C code for set_popdown_strings, it creates list items that contain the labels stuffed with the strings in question. You could iterate through combo.list.children() and then grab the label, which should be the first element of the list item itself (.children()[0]). This is an O(n) operation, however.

However, you have a much simpler alternative: just store the strings yourself, locally.

    def set_combo_strings(self, s):
        self.strings = s
        self.combo.set_popdown_strings(s)
You have self.strings conveniently stored in a python list, and you can get them back whenever you like, at O(1).

Edit this entry1164 / Log info1165 / Last changed on Wed Dec 3 22:20:07 2003 by Christian Reis (kiko-at-async-com-br)


14.15.1166 How do I change the mouse cursor on a TextView (or how do I get the "right" GdkWindow from a TextView)?

As described in FAQ 5.61167, and similarly to the GtkEntry discussed in FAQ 14.31168, the TextView widget is made up of several underlying GdkWindows. The actual text window already has a cursor set on it (the i-beam cursor), but it's not the TextView's main window, which is why using a plain TextView.get_window() call won't work. You need to get the child window:

 child_win = v.get_window(gtk.TEXT_WINDOW_TEXT)
 child_win.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
(Tim Evans)

Edit this entry1169 / Log info1170 / Last changed on Wed Dec 10 18:48:32 2003 by Christian Reis (kiko-at-async-com-br)


14.16.1171 Is there a signal sent when a user hits enter in an editable?

Yes. Connect to signal "activate".

Edit this entry1172 / Log info1173 / Last changed on Sun Feb 8 17:34:22 2004 by Christian Reis (kiko-at-async-com-br)


14.17.1174 What X clipboard do TextView's context menu items use?

They use the default gdk.SELECTION_CLIPBOARD; see the gtk.Clipboard reference at [www.pygtk.org]1175 for details.

Edit this entry1176 / Log info1177 / Last changed on Mon Jun 14 16:37:35 2004 by Christian Reis (kiko-at-async-com-br)


14.18.1178 How do I get the clipboard functions to work properly?

First, get an instance of the default display from the global gtk.gdk.DisplayManager:

 display = gtk.gdk.display_manager_get().get_default_display()
Then get a reference to a gtk.Clipboard object, specifying the CLIPBOARD clipboard (and not PRIMARY):

 clipboard = gtk.Clipboard(display, "CLIPBOARD")
Now your cut/copy/paste callbacks can be written as follows:

 def on_cut_activate(self, obj):
 	textbuffer.cut_clipboard(clipboard, textview.get_editable())

 def on_copy_activate(self, obj):
 	textbuffer.copy_clipboard(clipboard)

 def on_paste_activate(self, obj):
 	textbuffer.paste_clipboard(clipboard, None, textview.get_editable())
Where "textview" is a reference to your gtk.TextView widget and "textbuffer" is a reference to your gtk.TextBuffer.

Note: the functions used in the callbacks are available as of PyGTK 2.4

Edit this entry1179 / Log info1180 / Last changed on Tue Jun 22 15:26:35 2004 by Christian Reis (kiko-at-async-com-br)


14.19.1181 I'm getting a Gtk-CRITICAL messsage: assertion `g_utf8_validate (text, len, NULL)' failed [using insert_*]

The message is only saying that your text string is not well encoded in utf-8 -- this happens, for instance, when using a "regular" python string instead of a unicode one.

Try using unicode objects instead of strings if you're getting these problems -- python will automatically convert to utf-8 for you.

(Gustavo Carneiro)

Edit this entry1182 / Log info1183 / Last changed on Thu Jul 1 10:00:23 2004 by Christian Reis (kiko-at-async-com-br)


14.20.1184 How do I write clipboard callbacks for multiple widgets?

First get an instance of both the CLIPBOARD and PRIMARY selections::

  clipboard = gtk.Clipboard(gtk.gdk.display_get_default(), 'CLIPBOARD')
  clipPrimary = gtk.Clipboard(gtk.gdk.display_get_default(), 'PRIMARY')
Then you can write your copy callback to copy from the PRIMARY selection to the CLIPBOARD::

  def on_copy_activate(self, *extra):
      # If the PRIMARY selection has a listed owner, then it belongs to our app
      if clipPrimary.get_owner():
          selectionText = clipPrimary.wait_for_text()
          if selectionText:
              clipboard.set_text(selectionText, -1)
The cut callback is slightly more complex as we need to clear the highlighted selection as well::

  def on_cut_activate(self, *extra):
      owner = clipPrimary.get_owner()
      if owner:
          # If the widget which owns Primary selection is an Editable, we can
          # use the editable's clipboard functions to do our operations.
          # Otherwise just perform a copy.
          if isinstance(owner, gtk.Editable):
              owner.cut_clipboard()
          else:
              selectionText = clipSelect.wait_for_text()
              if selectionText:
                  clipboard.set_text(selectionText, -1)
The paste callback is different from both the cut and copy callbacks but also quite simple. The important thing is to pass it an instance of your application's window through a global variable or as a parameter::

  def on_paste_activate(self, *extra):
      # Get the widget with the focus
      entry = appWindow.focus_widget
      if isinstance(entry, gtk.Editable):
          entry.paste_clipboard()
Note: These functions are available in pygtk-2.2 and above.

Edit this entry1185 / Log info1186 / Last changed on Sat Oct 16 11:49:49 2004 by Toshio Kuratomi (toshio-at-tiki-lounge-com)


14.21.1187 How do I right-align text in an Entry?

Just set the "xalign" property:

  entry.set_property('xalign', 1)
Note that this works normally in LTR locales; an entry with the number 23.22 would show up as something like (using your ascii-art imagination):

  [        23.22 ]

Edit this entry1188 / Log info1189 / Last changed on Thu Nov 18 13:10:25 2004 by Christian Robottom Reis (kiko-at-async-com-br)


14.22.1190 How do I create a mask or validator for a GtkEntry?

There is an opensource subclass of gtk.Entry, ValidatedEntry, available at: [www.astro.umass.edu]1191 otherwise...

In short, there is no feature currently implemented that makes this easy. You can hack your own mask support by catching the insert and delete_text signals and doing the appropriate manipulation, but it is far from trivial to write; FAQ 14.51192 includes a basic recipe. There is a bug filed at [bugzilla.gnome.org]1193 that discusses implementation of something like this (validation and masks) at the C level.

See the thread at [www.daa.com.au]1194 for more details.

Edit this entry1195 / Log info1196 / Last changed on Sat Jun 24 00:56:35 2006 by Daniel Popowich (dpopowich-at-astro-umass-edu)


14.23.1197 How do I send the output of an external process to a gtk.TextView without freezing the GUI?

The problem here is to avoid waiting for the external process to finish. That can easily be done with threads but it should be possible to get it working using pipes in non-blocking IO mode and monitoring output using the gobject.io_add_watch() function. The problem with this last approach is that only sockets, not pipes, can be used with the select interface in Win32... so that solution seems not too portable for that reason.

This example shows how to do it the "threaded way", as it seems quite straightforward and portable through platforms without additional tweaking.

 #!/usr/bin/env python
 """Show a shell command's output in a gtk.TextView without freezing the UI"""

 import os, threading, locale

 import pygtk
 pygtk.require('2.0')
 import gtk

 encoding = locale.getpreferredencoding()
 utf8conv = lambda x : unicode(x, encoding).encode('utf8')

 def on_button_clicked(button, buffer, command):
     thr = threading.Thread(target= read_output, args=(buffer, command))
     thr.start()

 def read_output(buffer, command):
     stdin, stdouterr = os.popen4(command)
     for line in stdouterr.readlines():
          buffer.insert(buffer.get_end_iter(), utf8conv(line))

 sw = gtk.ScrolledWindow()
 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 textview = gtk.TextView()
 textbuffer = textview.get_buffer()
 sw.add(textview)
 win = gtk.Window()
 win.resize(300,500)
 win.connect('delete-event', gtk.main_quit)
 button = gtk.Button(u"Press me!")
 command = 'dir -R %s' % os.getcwd()
 button.connect("clicked", on_button_clicked, textbuffer, command)
 vbox = gtk.VBox()
 vbox.pack_start(button, gtk.FALSE)
 vbox.pack_start(sw)
 win.add(vbox)
 win.show_all()

 gtk.main()

This recipe doesn't circumvent the behaviour of applications using <stdio.h> that don't throw their output till the process has finished. The stdio library seems to be using block buffering instead of line buffering whenever the output goes to anything other than a terminal.

The flow of data seems to be something like this:

shell process output --(stdio buffer)*--> | --(python "shell interpreter" buffer)**--> python output

That way, even when popen or other python process handling functions are told not to use buffered output the resulting output seems to be buffered anyway. The problem is that buffering is only disabled on the python side (in the buffer tagged with **), but not on the application side (buffer tagged with *), so the the overall result is buffered output.

If a terminal like result is desired we can take different approaches:

Edit this entry1199 / Log info1200 / Last changed on Thu Jul 13 14:54:06 2006 by Christian Reis (kiko-at-async-com-br)


14.24.1201 How do I add completion support for an entry?

Here is a simple example that demonstrates how to add entry completion to a GtkEntry:

 import gtk

 COL_TEXT = 0

 class CompletedEntry(gtk.Entry):
     def __init__(self):
         gtk.Entry.__init__(self)
         completion = gtk.EntryCompletion()
         completion.set_match_func(self.match_func)
         completion.connect("match-selected",
                             self.on_completion_match)
         completion.set_model(gtk.ListStore(str))
         completion.set_text_column(COL_TEXT)
         self.set_completion(completion)

     def match_func(self, completion, key, iter):
         model = completion.get_model()
         return model[iter][COL_TEXT].startswith(self.get_text())

     def on_completion_match(self, completion, model, iter):
         self.set_text(model[iter][COL_TEXT])
         self.set_position(-1)

     def add_words(self, words):
         model = self.get_completion().get_model()
         for word in words:
             model.append([word])

 if __name__ == "__main__":
     win = gtk.Window()
     win.connect('delete-event', gtk.main_quit)

     entry = CompletedEntry()
     entry.add_words(['abc', 'def', 'ghi', 'jkl', 'mno',
                      'pqr', 'stu', 'vwx', 'yz'])
     win.add(entry)
     win.show_all()

     gtk.main()

Edit this entry1202 / Log info1203 / Last changed on Mon Jul 11 15:13:40 2005 by Johan Dahlin (johan-at-gnome-org)


14.25.1204 How can I place a background image on a TextView widget?

Here's some sample code:

 tv = gtk.TextView()
 tv.show()
 tv_win = tv.get_window(gtk.TEXT_WINDOW_TEXT)
 tv_win.set_back_pixmap(yourPixmap, gtk.FALSE)
Note the placement of tv.show(). It appears that the tv.show() needs to precede getting the gtk.gdk window.

Edit this entry1205 / Log info1206 / Last changed on Wed Jun 1 14:37:44 2005 by Matt Bradshaw (matt-bradshaw-at-gmail-com)


14.26.1207 The text in the TextView is not aligned! Any ideas?

You need to use a monospace font

You will have to use TextTags which is not as easy as set_text() but not as very hard either. Then you do something like:

   tag = gtk.TextBuffer.create_tag('aligned')
   tag.set_property("font", "Courier")
   tag.set_property("foreground", "red")
   tag.set_property("size-points", 12)
   tag.set_property("weight", 400)
then you add the text by:

TextBuffer.insert_with_tags(your_text, 'aligned')

Edit this entry1208 / Log info1209 / Last changed on Mon Jun 27 11:13:36 2005 by Nikos Kouremenos (kourem-at-gmail-com)


16. GtkOptionMenu, GtkComboBox, GtkComboBoxEntry


16.1.1210 Why doesn't the GtkOptionMenu work like a real listbox?

I personally think the GtkOptionMenu was designed by the devil, and it's API is a stamina test to all good men and women out there.

GtkOptionMenu will be deprecated in GTK+ 2.4 in favor of the new GtkComboBox.

Edit this entry1211 / Log info1212 / Last changed on Thu Nov 6 14:25:26 2003 by Steve Chaplin (stevech1097-at-yahoo-com-au)


16.2.1213 Let's say I accept it as it is. How do I implement one using pygtk?

David Pinson has sent in an example to keep us all sane:

 def on_optionmenu_activate(widget, data):
     print data                      # print the data for the 
                                     # current selection
 options = ["cat", "dog", "mouse"]   # our options
 menu = gtk.Menu()                   # create a menu
 for str in options:                 # fill our menu with the options
    menu_item = gtk.MenuItem(str)
    menu_item.connect("activate",    # attach "str" to widget
                      on_optionmenu_activate, str) 
    menu_item.show()                 # don't forget this here
    menu.append(menu_item)
 option_menu = gtk.OptionMenu()      # create the optionmenu
 option_menu.set_menu(menu)          # add the menu into the optionmenu
(Note that Kiwi also includes a new API for the OptionMenu that makes it much easier to manipulate: it does signal connection automatically, fills the menu and attaches objects to the items. Check it out)

Edit this entry1214 / Log info1215 / Last changed on Tue Jan 27 12:40:10 2004 by Johan Dahlin (johan-at-gnome-org)


16.3.1216 If I set the OptionMenu's state to insensitive, and i call set_history() on it, and put it back to sensitive, the previously selected menuitem still looks insensitive!

This is a bug in GTK+ (see [bugzilla.gnome.org]1217 ). Kiwi implements a workaround for it (see [bugs.async.com.br]1218 ) which involves setting the menuitem state to STATE_PRELIGHT and then back to STATE_NORMAL:

  menu = optionmenu.get_menu()
  for item in menu.get_children():
     item.set_state(gtk.STATE_PRELIGHT)
     item.set_state(gtk.STATE_NORMAL)

Edit this entry1219 / Log info1220 / Last changed on Tue Jan 27 12:39:20 2004 by Johan Dahlin (johan-at-gnome-org)


16.4.1221 How do I find out which is the selected item in a GtkOptionMenu?

The optionmenu is an evil widget, make no mistake. By using it you will see the `magic' it uses to appear to be a simple listbox (make no mistake!) Note these important, err, `aspects' of it:

To get the text of the selected menuitem you can take advantage of this last point and use:

  selected_text = optionmenu.children()[0].get()
If you want to know the index (or, in the OptionMenu's terms, the `history'), you will need to do some further hacks using the optionmenu's menu's get_active() method:

  menu = optionmenu.get_menu()
  items = menu.children()
  selected_item = menu.get_active()
  index = children.index(item)
This index is the same as its `history'. In GTK+2.0 there is a get_history() method that can be used (avoiding the need to code this hack) to make the API a bit more consistent.

(FAQ suggested by Padraig Brady, thanks)

Edit this entry1222 / Log info1223 / Last changed on Thu Dec 19 08:31:47 2002 by Christian Reis (kiko-at-async-com-br)


16.5.1224 What signal is emitted when an optionmenu's item is selected?

In PyGTK0, the `activate' signal of the selected GtkMenuItem (yes, the item, not the menu) is triggered. This means that, if you want to be notified of a change in the optionmenu, you will need to do something like:

  def optionmenu_changed(self, item, *args):
    print "it changed: %s was selected", item

  for item in optionmenu.get_menu().children();
    item.connect("activate", optionmenu_changed)
If you want to find out which item was selected, see faq 16.41225.

In PyGTK2, the `changed' signal is emitted (along with the item's `activate' signal, I suspect), so you don't need this hack.

Edit this entry1226 / Log info1227 / Last changed on Thu Dec 19 08:39:07 2002 by Christian Reis (kiko-at-async-com-br)


16.6.1228 How do I get the label of an OptionMenu's item?

This is a tricky one. Read carefully.

 menu = optionmenu.get_menu()
 for item in menu.get_children():
   chilren = item.get_children()
   if children:
     label = item.get_children()[0]

 label = optionmenu.get_children()[0] # notice - NOT item.get_children()

Edit this entry1229 / Log info1230 / Last changed on Tue Jan 27 12:35:09 2004 by Johan Dahlin (johan-at-gnome-org)


16.7.1231 How do I get the text from the selected item in GtkComboBox/ComboBoxEntry

For the ComboBox it's a matter of getting the value relative to the active iter:

  def on_combo_box_changed(widget):
     model = widget.get_model()
     iter = widget.get_active_iter()
     print model.get_value(iter, 0)

  combo.connect("changed", on_combo_box_changed)
In the example above, when an item is selected, its text is printed out.

For a ComboBoxEntry, the text can be retrieved using:

  combo_box_entry.child.get_text()
Since the Entry text can be changed by the user the "changed" signal is not sufficient to detect whether the user is done changing the Entry. Also the "changed" callback must be changed to:

  def on_combo_box_entry_changed(widget):
     model = widget.get_model()
     iter = widget.get_active_iter()
     if iter:
         print model.get_value(iter, 0)
because the "changed" signal will be issued if a user edits the text (or pastes it from a clipboard) thereby causing no model row to be active. To detect user edits you have to connect to the child Entry.

Edit this entry1232 / Log info1233 / Last changed on Sat Jul 10 13:00:49 2004 by John Finlay (finlay-at-moeraki-com)


16.8.1234 How do I populate a ComboBox or ComboBoxEntry with strings?

For glade users, you can create a simple model for your ComboBox* using

  store = gtk.ListStore(gobject.TYPE_STRING)
  store.append (["testing1"])
  store.append (["testing2"])
  store.append (["testing3"])
  store.append (["testing4"])
For a ComboBoxEntry, it's then a matter of assigning the model to the combo and specifying the text column:

  combo = tree.get_widget("comboboxentry1")
  combo.set_model(store)
  combo.set_text_column(0)
For a ComboBox, pack a renderer into it, specifying the text cell:

  combo = tree.get_widget("combobox1")
  combo.set_model(store)
  cell = gtk.CellRendererText()
  combo.pack_start(cell, True)
  combo.add_attribute(cell, 'text',0)
Thomas Hinkle offers a convenience function that does all this for you:

  def set_model_from_list (cb, items):
    """Setup a ComboBox or ComboBoxEntry based on a list of strings."""           
    model = gtk.ListStore(str)
    for i in items:
        model.append([i])
    cb.set_model(model)
    if type(cb) == gtk.ComboBoxEntry:
        cb.set_text_column(0)
    elif type(cb) == gtk.ComboBox:
        cell = gtk.CellRendererText()
        cb.pack_start(cell, True)
        cb.add_attribute(cell, 'text', 0)
If you are not using glade, it's easier to use the gtk.combo_box_new_text() function with the append_text(), prepend_text(), insert_text() and remove_text() methods as explained here:

[www.pygtk.org]1235 [www.pygtk.org]1236

(John Finlay, Thomas Hinkle)

Edit this entry1237 / Log info1238 / Last changed on Mon Nov 29 21:46:17 2004 by Christian Robottom Reis (kiko-at-async-com-br)


17. GtkNoteBook


17.1.1239 How do I get a reference to the page my GtkNotebook just switched to (or, what is the deal with the second argument to GtkNotebook's switch_page handler)?

If you attach a handler to a GtkNotebook's page_switch handler, you may have noticed that the second argument isn't a python instance. James says:

  newpage isn't a GtkObject (if it was, it would have been wrapped in a 
  class already).  For 2.0, it is an opaque struct, so useless to C 
  programmers as well.  Use the pagenum argument and methods of the 
  GtkNotebook to get info about the page.
pagenum refers to the tab number in the notebook. The leftmost tab is 0, the tab next to the leftmost is 1, etc... To get the pagenum, use the following code:

    pagenum = widget.current_page()
So if you have a GtkNotebook and you want to know what page you just switched to, use something like:

  def handler(widget, dummy, pagenum):
    page_widget = widget.get_nth_page(pagenum)
    print "Page number switched to: %s" % pagenum
    print "Widget attached to page %s: %s" % ( pagenum, page_widget )

  notebook.connect("switch_page", handler)
And your notebook will print out the information on each page switch.

Edit this entry1240 / Log info1241 / Last changed on Thu Mar 31 00:45:46 2005 by Kathryn Patterson (kathryn-patterson-at-gmail-com)


17.2.1242 How do I make one toolbar button (e.g. an Add button) call a different function for each notebook tab?

Some applications need a main toolbar (with all of its buttons) to respond according to which tab the user has currently selected. The following code creates a function for an Add button that brings up different windows depending on what the user wants to add:

 def on_add_activate(self, widget, *args):
        #context yourApp.on_add_activate {
        # create a dictionary where the key is the name of the main
        # widget of the notebook tab and the value is the name 
        # of the function that should be called for that specific tab
        addItem = {'CustomerTab':AddCustomerWindow,
                    'InventoryTab':AddInventoryWindow,
                    'VendorTab':AddVendorWindow,
                    'ReportTab':AddReportWindow}
        # for readability purposes, create a variable that points to  
        # the notebook
        notebook = self.MainNotebook
        # tabChild points to the main widget in the current tab
        tabChild = notebook.get_nth_page(notebook.get_current_page())
        # tabName is the name of tabChild
        tabName = tabChild.get_name()
        # now you can use tabName to reference the dictionary and call
        # the appropriate function  
        additem[tabName]()  
        return gtk.TRUE
        #context yourApp.on_add_activate }

Edit this entry1243 / Log info1244 / Last changed on Fri Apr 8 19:07:40 2005 by Kathryn Patterson (kathryn-patterson-at-gmail-com)


17.3.1245 How do I create a popup menu on a notebook tab and figure out which tab a click comes from

Brian Campbell said:

For an easy way to create popup menus, and figuring out which tab a click comes from, put your tab labels into event boxes:

 tab_label_box = gtk.EventBox()
 tab_label = gtk.Label("Some label here")
 tab_label_box.add(tab_label)
 tab_label_box.connect('event', on_tab_click, your_page_widget)
 notebook.append_page(your_page_widget, tab_label_box)

 def on_tab_click(self, widget, event, child):
    if event.type == gtk.gdk.BUTTON_PRESS:
        n = notebook.page_num(child)
        # this will automagically switch to whatever page you click on
        notebook.set_current_page(n)
        if event.button == 3:
             menu = create_a_menu() # I still use the ItemFactory
             menu.popup(None, None, None, event.button, event.time)

Edit this entry1246 / Log info1247 / Last changed on Tue Jun 28 12:20:21 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


18. GtkDrawingArea


18.1.1248 How do I make a gray-scale gradient picture?

Rok Roskar was trying to make a simple gray-scale gradient picture (different shades of gray, starting with white on the left and eventually going to black on the right).

John Finlay provided this code example (hacked for brevity):

 #!/usr/bin/env python

 from gtk import *

 WIDTH=300
 HEIGHT=300

 def pix_init(d_area, width, height):
    d_area.realize()
    win = d_area.get_window()
    pixmap = create_pixmap(win, width, height, -1)
    context = win.new_gc()
    cmap = d_area.get_colormap()
    for x in range(WIDTH):
        color = cmap.alloc(x*200, x*200, x*200)
        context.foreground = color
        for y in range(HEIGHT):
            draw_point(pixmap, context, x, y)
    d_area.connect("expose-event", pix_expose, pixmap)

 def pix_expose(da, event, pixmap):
    x, y, width, height = da.get_allocation()
    da.draw_pixmap(da.get_style().fg_gc[0], pixmap, 0, 0, 0, 0, -1, -1)

 def main():
    top = GtkWindow(WINDOW_TOPLEVEL)
    da = GtkDrawingArea()
    da.size(WIDTH, HEIGHT)
    top.add(da)
    pix_init(da, WIDTH, HEIGHT)
    top.show_all()
    mainloop()

 if __name__ =="__main__":
    main()

Edit this entry1249 / Log info1250 / Last changed on Thu Jan 31 21:06:18 2002 by kiko (kiko-at-async-com-br)


18.2.1251 When I place a DrawingArea inside a ScrolledWindow the event object in callbacks has X and Y coordinates off by a few pixels!

Cameron Blackwood noticed that, when placing a GtkDrawingArea inside a GtkScrolledWindow, two peculiarities arise:

a) Connecting to GtkDrawingArea's button_press_event doesn't get called on button presses (when inside a GtkScrolledWindow).

b) If you work around this connecting the signal to the GtkScrolledWindow instead, the X and Y coordinates are off by a few pixels (3 and 4, horizontal and vertically, respectively for the default pointer).

To get this working it's matter of setting the event mask correctly on GtkDrawingArea (faq 3.31252) and not attaching to GtkScrolledWindow's button_press_event signal.

 drawingarea.add_events(GDK.BUTTON_PRESS_MASK)
Adding the GtkDrawingArea directly to a GtkWindow also allows the signal connect to work normally.

Edit this entry1253 / Log info1254 / Last changed on Mon Jan 12 21:42:50 2004 by Christian Reis (kiko-at-async-com-br)


18.3.1255 How do I set line attributes for draw_line() and draw_lines()?

James says:

All drawing operations in X take a GC (which stands for graphics context), which holds some settings used for doing the drawing. If you are going to change the settings of a GC, it is probably best to create your own (you don't really want to cause all your widgets to draw with double dashed lines).

This can be done with the drawable.new_gc() method. You can then use the gc.set_line_attributes() method to set the line width, line style, cap style and join style:

 gc.set_line_attributes(3, 
                        gdk.LINE_DOUBLE_DASH, 
                        gdk.CAP_BUTT, 
                        gdk.JOIN_MITER)
Now if you draw lines with this GC, they will use these attributes.

Edit this entry1256 / Log info1257 / Last changed on Tue Jan 27 12:30:41 2004 by Johan Dahlin (johan-at-gnome-org)


18.4.1258 How do I draw dashed or dotted lines in a GtkDrawingArea?

To draw dashes, you can manipulate the line style attribute of the DrawingArea's GC object before drawing the lines. Constant values from GDK.py are:

 LINE_SOLID
 LINE_ON_OFF_DASH
 LINE_DOUBLE_DASH
So you can do something like:

 line_style = GDK.LINE_ON_OFF_DASH
 gc.line_style(line_style)
For dots, John Finlay writes: "You can create your own dash pattern using set_dashes()." I've added information here from the tutorial at [www.moeraki.com]1259 :

"To define a dash pattern (taking notice that the line_style must be set to LINE_ON_OFF_DASH or LINE_DOUBLE_DASH), use the following GC method:

 gc.set_dashes(offset, dash_list)
where offset is the index of the starting dash value in dash_list and dash_list is a list or tuple containing numbers of pixels to be drawn or skipped to form the dashes. The dashes are drawn starting with the number of pixels at the offset position; then the next number of pixels is skipped; and then the next number is drawn; and so on rotating through all the dash_list numbers and starting over when the end is reached. For example, if the dash_list is (2, 4, 8, 16) and the offset is 1, the dashes will be drawn as: draw 4 pixels, skip 8 pixels, draw 16 pixels, skip 2 pixels, draw 4 pixels and so on."

John Hunter shows us how dots can be done in practice:

 self._spacing = 2
 gc.line_style = GDK.LINE_ON_OFF_DASH
 gc.cap_style =  GDK.CAP_BUTT
 gc.join_style = GDK.JOIN_ROUND
 gc.set_dashes(0,[1,self._spacing])
 widget.draw_lines(gc, zip(x, y) )

Edit this entry1260 / Log info1261 / Last changed on Wed Nov 6 14:48:31 2002 by Christian Reis (kiko-at-async-com-br)


18.5.1262 What's the essential approach to tracking mouse events in a GtkDrawingArea?

Assuming you want to know where the mouse is, you can either get the coordinate of a mouse click or a mouse motion. The approach is the same:

 drawing_area.connect('motion-notify-event', motion_notify_event_cb)
 drawing_area.connect('button-press-event', button_press_event_cb)  

 drawing_area.set_events(gdk.BUTTON_PRESS_MASK | gdk.POINTER_MOTION_MASK)
You need to define these functions. Eg, for button-press-event:

 def button_press_event_cb(widget, event):
    if event.button == 1:
      ... do something, when the first button is pressed ...
    elif event.button == 3:
      ... do something, when the third buttin is pressed ...
    return True
Notice how event.button carries information about which button was pressed and event.x and event.y give you the x and y coords.

For mouse motion, you simply need to define something like this:

 def motion_notify_event_cb(self, widget, event):
   print "Mouse moved to", event.x, event.y
   return True

Edit this entry1263 / Log info1264 / Last changed on Tue Jan 27 12:29:42 2004 by Johan Dahlin (johan-at-gnome-org)


18.6.1265 How do I get scrollbars to work with a DrawingArea?

Make the GtkDrawingArea as a child of a GtkViewport which is in turn the child of a GtkScrolledWindow. Whenever you determine the size of what you want to draw in the drawing area, call set_size_request on the GtkDrawingArea widget.

Small example:

 sw = gtk.ScrolledWindow()
 sw.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
 viewport = gtk.ViewPort()
 drawing_area = gtk.DrawingArea()

 sw.add(viewport)
 viewport.add(drawing_area)

Edit this entry1266 / Log info1267 / Last changed on Tue Jan 27 12:24:42 2004 by Johan Dahlin (johan-at-gnome-org)


18.7.1268 How do I make my DrawingArea have the same background used in other widgets?

What we want is draw the background of the DrawingArea with the same background color or pixmap that the one used by our current theme.

We just need to add this line to our redraw function:

  drawing_area.style.apply_default_background(drawing_area.window, True, gtk.STATE_NORMAL, None, 0, 0, w, h)

Edit this entry1269 / Log info1270 / Last changed on Tue Jan 27 10:49:32 2004 by Johan Dahlin (johan-at-gnome-org)


18.8.1271 What basic pattern should I follow when using a DrawingArea?

The DrawingArea (and drawing in GTK+ in general) is peculiar in the sense that you never draw directly to the widget. Instead, you tell the X server the widget needs to be drawn, then the X server calls you back telling you to draw an area of your widget. This important because if you don't follow this pattern, either what you draw won't be displayed, or it will fail to redraw when the window is covered and subsequently uncovered.

The key to this pattern is the 'expose-event' signal. The handler you connect to it has the following signature:

  def expose_event_cb(widget, event):
     # ...
where event is a GdkEvent structure containing the fields x, y, width, height. These fields define the area that actually needs to be painted, which might be different from the entire widget area if, for example, there is a window on top of the widget, partially obscuring it.

Note that you should call widget.queue_draw() whenever you want to repaint your widget (i.e., when you want to redraw it with something different from what's currently displayed on it).

Here's some example code to start off from:

    class MyWidget(gtk.DrawingArea):
        def __init__(self):
            gtk.DrawingArea.__init__(self)
            self.gc = None  # initialized in realize-event handler
            self.width  = 0 # updated in size-allocate handler
            self.height = 0 # idem
            self.connect('size-allocate', self.on_size_allocate)
            self.connect('expose-event',  self.on_expose_event)
            self.connect('realize',       self.on_realize)

        def on_realize(self, widget):
            self.gc = widget.window.new_gc()
            self.gc.set_line_attributes(3, gtk.gdk.LINE_ON_OFF_DASH,
                                        gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)

        def on_size_allocate(self, widget, allocation):
            self.width = allocation.width
            self.height = allocation.height

        def on_expose_event(self, widget, event):
            # This is where the drawing takes place

            widget.window.draw_rectangle(self.gc, False,
                                         1, 1, self.width - 2, self.height - 2)
            widget.window.draw_line(self.gc,
                                    0, 0, self.width - 1, self.height - 1)
            widget.window.draw_line(self.gc,
                                    self.width - 1, 0, 0, self.height - 1)

    win = gtk.Window()
    win.add(MyWidget())
    win.show_all()
    win.connect("destroy", lambda w: gtk.main_quit())
    gtk.main()
(Gustavo Carneiro, John Hunter)

Edit this entry1272 / Log info1273 / Last changed on Fri Feb 27 22:46:14 2004 by Christian Reis (kiko-at-async-com-br)


18.9.1274 How to set a tiled background pixmap on gnomecanvas.Canvas? Or, how do set custom background on gnomecanvas.Canvas?

You have to connect_after or override the signal "draw-background", and paint there what you want as canvas background, such as tiled pixmap, grid, etc. Here's an example for setting tiled pixmap:

 import gtk
 from gtk import gdk
 import gnomecanvas as canvas

 def drawbk(acv, dw, x, y, ww, hh, pb):
     gc = dw.new_gc()
     pw = pb.get_width()
     ph = pb.get_height()
     offset_x = x % pw
     offset_y = y % ph
     dw_y = -offset_y
     while dw_y < hh:
         dw_x = -offset_x
         while dw_x < ww:
             dw.draw_pixbuf(gc, pb, 0, 0, dw_x, dw_y)
             dw_x += pw
         dw_y += ph

 # window 
 win = gtk.Window()
 win.resize(100, 200)
 win.connect('destroy', gtk.main_quit)
 win.realize()

 # load a graphic
 pb = gdk.pixbuf_new_from_file('baize.png')
 w, h = pb.get_width(), pb.get_height()

 cv = canvas.Canvas()
 cv.connect_after('draw-background', drawbk, pb)

 win.add(cv)
 win.show_all()
 gtk.main()

Edit this entry1275 / Log info1276 / Last changed on Fri Jun 10 16:58:41 2005 by Gustavo J. A. M. Carneiro (gjc-at-inescporto-pt)


19. Other widgets


19.1.1277 Are there any HTML rendering widgets for PyGTK?

Placeholder XXX: fixme

Edit this entry1278 / Log info1279 / Last changed on Thu Jan 31 21:32:07 2002 by kiko (kiko-at-async-com-br)


19.2.1280 What about HTML widgets for PyGTK2?

Johan Dahlin wrapped GtkMozEmbed in a python module, which is packaged as part of gnome-python-extras.

gtkhtml2 uses pango for i18n text rendering, etc. [gtkhtml2.codefactory.se]1281 . The HTML rendering still needs work.

Note that Evolution uses libgtkhtml3, which is yet unwrapped.

Gustavo Carneiro did a XHTML-IM (XHTML-1.0 subset) renderer on top of gtk.TextView. It can be found at: [www.gnome.org]1282

Edit this entry1283 / Log info1284 / Last changed on Fri Sep 30 20:03:33 2005 by Gustavo Carneiro (gjc-at-inescporto-pt)


19.3.1285 GnomeIconList's get_icon_data() method doesn't work!

Right now, actually, it could return a SEGV if you are trying to retrieve the data from a position without any data set, as is demostrated below:

 l = gnome.GnomeIconList() 
 l.append('some-icon.png', 'some text')
 l.get_icon_data(0)
JamesH says:

If you didn't set the data associated with the icon, then the results can be unpredictable (ie. get_icon_data() will return whatever you set with set_icon_data()).

Basically, don't get() the data unless you have set() it. This could result of a basic lack of understanding of what the object data attribute is. See question 5.1

Edit this entry1286 / Log info1287 / Last changed on Tue Feb 5 14:54:21 2002 by kiko (kiko-at-async-com-br)


19.4.1288 Can I do plots or charts with PyGTK?

If you are using PyGTK2, then the answer is yes:

John Hunter's Matplotlib: [matplotlib.sourceforge.net]1289

matplotlib is a pure python 2D plotting library with a Matlab® syntax which produces publication quality figures using in a variety of hardcopy formats (PNG, JPG, TIFF, PS) and interactive GUI environments (WX, GTK) across platforms. matplotlib can be used in python scripts, interactively from the python shell (ala matlab or mathematica), in web application servers generating dynamic charts, or embedded in GTK or WX applications.

Jonathan Merritt's PyStripchart [jstripchart.sourceforge.net]1290

PyStripchart is a set of widgets for displaying sampled information in an interactive "strip chart" form. The website contains code and screenshots.

Edit this entry1291 / Log info1292 / Last changed on Wed Jan 14 12:56:28 2004 by John Hunter (jdhunter-at-ace-bsd-uchicago-edu)


19.5.1293 How do I get the current color from a gnome ColorPicker?

Gustavo Carneiro suggests using properties:

 color_picker.get_property("red")
 color_picker.get_property("green")
 color_picker.get_property("blue")
The returned values are in in range 0..65535 (16 bits).

Edit this entry1294 / Log info1295 / Last changed on Sat Jul 26 16:49:50 2003 by Christian Reis (kiko-at-async-com-br)


19.6.1296 Is there a syntax highlighting widget for PyGTK?

Yes, there is. GtkSourceView has been wrapped as PySourceView, and it's available (as a 3rd-party library) from: [www.bitbuilder.com]1297

Edit this entry1298 / Log info1299 / Last changed on Wed Aug 20 18:48:35 2003 by Christian Reis (kiko-at-async-com-br)


19.7.1300 When displaying a GnomeAbout box, it doesn't display the program name or version.

Set the 'name' and 'version' properties on the GnomeAbout widget before the widget is shown:

  aboutbox.set_property('name','Demo Program')
  aboutbox.set_property('version','0.1')
By the way, the name you want shown in the about box is not necessarily the name string you pass in to the gnome.init() method. It really wants to be the same as whatever the 'human-readable-name' property of GnomeProgram to (if you set that property), but that is getting pretty subtle (not a lot of programs do that).

(Malcolm Tredinnick, Colin Fox)

Edit this entry1301 / Log info1302 / Last changed on Mon Sep 1 13:13:24 2003 by Christian Reis (kiko-at-async-com-br)


19.8.1303 How do I pass extra arguments to a Gnome Applet's setup_menu() callback?

If setup_menu() is called with 'None' as user_data (applet.setup_menu(xml,verbs,None)), the callback prototype is callback(widget,verb). If setup_menu() is called with an extra arguement, the callback prototype is callback(widget,verb,user_data).

Edit this entry1304 / Log info1305 / Last changed on Mon Oct 6 11:38:18 2003 by Martin Gadbois (martin-gadbois-at-colubris-com)


19.9.1306 In creating a Gnome Applet, how do I use class members for callbacks?

Just create your verbs list like this in your class:
 class MyApplet:
   def __init__(self,applet):
     verbs = [ ( "Properies", self.properties), ("About",self.about) ]
     applet.setup_menu("xml here",verbs,None)
   def properties(self):
     pass # and display properties
   def about(self):
     pass # and display about box.
When called, 'self' will be set properly.

Edit this entry1307 / Log info1308 / Last changed on Mon Oct 6 14:54:50 2003 by Martin Gadbois (martin-gadbois-at-colubris-com)


19.10.1309 How do I hide the toolbar of a gnome.ui.App() instance?

If you just call hide() on the toolbar, it is hidden but its display area is still visible (empty, though); that's because it's held in a Bonobo Dock. You need hide the dock item itself, but first you have to get the dock item. One way is to use get_dock_item_by_name().

Here is a snippet from some test code that might put you on the right track. The variable my_app is a reference to the gnome.ui.App instance.

    # Hide toolbar.  We need to get the bonobo dock item to show/hide
    # instead of simply hiding the toolbar itself or we will leave
    # blank dock space when we hide.
    # The default toolbar name for a gnome.ui.App seems to be 'Toolbar'.
    bonobo_toolbar = my_app.get_dock_item_by_name('Toolbar')            
    if bonobo_toolbar:
        bonobo_toolbar.hide()
You can show it again using show() in place of hide().

(Doug Quale)

Edit this entry1310 / Log info1311 / Last changed on Wed Jan 21 09:12:32 2004 by Christian Reis (kiko-at-async-com-br)


19.11.1312 Can I use OpenGL to draw in a PyGTK application?

You can, by using a supported OpenGL extension to GTK+. There are currently two extensions in common use:

  As opposed to Jane Loff's GtkGLArea , it provides not an OpenGL
  widget, but an additional GtkWidget API which enables the standard
  (and custom) GTK+ widgets to render 3D scene using OpenGL.

Edit this entry1314 / Log info1315 / Last changed on Thu Mar 25 14:33:03 2004 by Christian Reis (kiko-at-async-com-br)


19.12.1316 Is there support for tray notification area clients?

A very basic libegg tray icon example is in gnome-python-extras: [cvs.gnome.org]1317

These wrap the libegg trayicon components (viewable at [cvs.gnome.org]1318 ).

For Microsoft Windows you can look at [aspn.activestate.com]1319

A common problem with libbegg is that Image widgets do not receive events -- to solve this, place them inside an EventBox.

Edit this entry1320 / Log info1321 / Last changed on Mon Jul 18 01:51:59 2005 by Phillip Calvin (phillipc-at-toasterlogic-com)


19.13.1322 How do I a signal a callback when a gtk.Paned widget handle is dragged?

The gtk.Paned widget provides a 'move-handle' signal that would seem to be appropriate, but Skip Montanaro points out that the 'move-handle' signal is only emitted when the handle is moved by use of the keyboard. If the paned window handle is dragged using the mouse, the signal is not emitted.

John Finlay suggests a good solution: Connect to the 'notify' signal and watch for changes in the 'position' property of the paned window. The 'notify' signal will be emitted when any property of a GObject changes.

    def on_pane_notify(pane, gparamspec):
        # A widget property has changed.  Ignore unless it is 'position'.
        if gparamspec.name == 'position':
            print 'pane position is now', pane.get_property('position')

    pane = gtk.HPaned()
    pane.connect('notify', on_pane_notify)

Edit this entry1323 / Log info1324 / Last changed on Tue Aug 24 02:42:26 2004 by Doug Quale (quale1-at-charter-net)


19.14.1325 Is there a grid or spreadsheet-like widget available?

There is Lorenzo's GtkGrid, which is independently packaged and has Python wrappers: [www.sicem.biz]1326

It is currently in alpha state. There is also a GtkSheet widget which was included in GtkExtras, but no python wrapper currently exists for it, and the project itself is no longer active.

Edit this entry1327 / Log info1328 / Last changed on Tue May 17 17:13:49 2005 by Christian Reis (kiko-at-async-com-br)


19.15.1329 How do I embed something using Plugs and Sockets?

You can embed other X objects into a gtk.Socket by using the X window's XID. Note that you can reliably embed foreign windows if and only if both sides comply to some common protocol (like Plug and Socket) -- if not, their are nasty corner-cases and things that can go wrong. In other words, you cannot just embed arbitrary XIDs and expect it to work in all cases. Best thing here is to try, and see if things don't break too badly.

We'll use as an example embedding an xterm.

 xwininfo: Window id: 0x1a0000e "xterm"

  Absolute upper-left X:  5
  Absolute upper-left Y:  649
  Relative upper-left X:  5
  Relative upper-left Y:  21
  Width: 484
  Height: 316
  Depth: 24
  Visual Class: TrueColor
  Border width: 0
  Class: InputOutput
  Colormap: 0x20 (installed)
  Bit Gravity State: NorthWestGravity
  Window Gravity State: NorthWestGravity
  Backing Store State: NotUseful
  Save Under State: no
  Map State: IsViewable
  Override Redirect State: no
  Corners:  +5+649  -791+649  -791-59  +5-59
  -geometry 80x24+0-54

  >>> long(0x1a0000e)
  27262990L

  $ python socket.py 27262990

For another example, take a look at the example in the pygtk tutorial: [www.pygtk.org]1331

(N. Volbers, Maciej Katafiasz)

Edit this entry1332 / Log info1333 / Last changed on Tue May 24 14:39:47 2005 by Christian Reis (kiko-at-async-com-br)


19.16.1334 How can I use the IconView widget?

here is an example that emulates the preferences window of Firefox (on hover effect which is not easy to do is not here)

    import pygtk
    pygtk.require('2.0')
    import gtk

    class PreferencesMgr(gtk.Dialog):
        def __init__(self):
            gtk.Dialog.__init__(self, 'Preferences', None,
                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                       (gtk.STOCK_OK, gtk.RESPONSE_OK,
                        gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
            self.current_frame = None
            self.create_gui()

        def create_gui(self):

            model = gtk.ListStore(str, gtk.gdk.Pixbuf)

            pixbuf = gtk.gdk.pixbuf_new_from_file('images/prefs_general.png')        
            model.append(['General', pixbuf])

            pixbuf = gtk.gdk.pixbuf_new_from_file('images/prefs_security.png')
            model.append(['Security', pixbuf])

            self.icon_view = gtk.IconView(model)
            self.icon_view.set_text_column(0)
            self.icon_view.set_pixbuf_column(1)
            self.icon_view.set_orientation(gtk.ORIENTATION_VERTICAL)
            self.icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
            self.icon_view.connect('selection-changed', self.on_select, model)
            self.icon_view.set_columns(1)
            self.icon_view.set_item_width(-1)
            self.icon_view.set_size_request(72, -1)

            self.content_box = gtk.HBox(False)
            self.content_box.pack_start(self.icon_view, fill=True, expand=False)
            self.icon_view.select_path((0,)) # select a category, will create frame
            self.show_all()
            self.vbox.pack_start(self.content_box)        
            self.resize(640, 480)
            self.show_all()

        def on_select(self, icon_view, model=None):
            selected = icon_view.get_selected_items()
            if len(selected) == 0: return
            i = selected[0][0]
            category = model[i][0]
            if self.current_frame is not None:
                self.content_box.remove(self.current_frame)
                self.current_frame.destroy()
                self.current_frame = None
            if category == 'General':
                self.current_frame = self.create_general_frame()
            elif category == 'Security':
                self.current_frame = self.create_security_frame()    
            self.content_box.pack_end(self.current_frame, fill=True, expand=True)
            self.show_all()

        def create_general_frame(self):
            frame = gtk.Frame('General')        
            return frame        

        def create_security_frame(self):
            frame = gtk.Frame('Security')        
            return frame        

    if __name__ == '__main__':
        p = PreferencesMgr()
        p.run()
        p.destroy()

Edit this entry1335 / Log info1336 / Last changed on Sun Jun 12 20:26:19 2005 by Nikos Kouremenos (kourem-at-gmail-com)


19.17.1337 How can I distribute gtkhtml2 (outside of gnomepythonextras)?

first get gnome-python-extras package, extract it, and copy the gtkhtml2 subdirectory somewhere, delete Makefile.in and Makefile.am from that directory as you don't need them and use this Makefile:

	PYTHONVER = `python -c 'import sys; print sys.version[:3]'`
	CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0 libgtkhtml-2.0` -fPIC -I/usr/include/python$(PYTHONVER) -I.
	LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0 libgtkhtml-2.0`

	all: gtkhtml2.so

	# Build the shared objects
	gtkhtml2.so: gtkhtml2.o gtkhtml2module.o
		$(CC) $(LDFLAGS) -shared $^ -o $@

	# The path to the GTK+ python types
	DEFS=`pkg-config --variable=defsdir pygtk-2.0`

	# Generate the C wrapper from the defs and our override file
	gtkhtml2.c: gtkhtml2.defs gtkhtml2.override
		pygtk-codegen-2.0 --prefix pygtkhtml2 \
		--register $(DEFS)/gdk-types.defs \
		--register $(DEFS)/gtk-types.defs \
		--override gtkhtml2.override \
		gtkhtml2.defs > $@

	# A rule to clean the generated files
	clean:
		rm -f gtkhtml2.so *.o gtkhtml2.c *~  

	.PHONY: clean

Edit this entry1338 / Log info1339 / Last changed on Tue Aug 30 09:23:17 2005 by Nikos Kouremenos (kourem-at-gmail-com)


19.18.1340 Why does gtkmozembed somtimes crash in load_url()?

This happens on URL:s like "[art.gnome.org]1341 ". It happens because gtkmozembed need to be initialised with a profile before it can work correctly:

  gtkmozembed.set_profile_path("/tmp", "foobar")
  gtkmozembed.MozEmbed().load_url("http://art.gnome.org")
Note that the profile file need not to exist.

Edit this entry1342 / Log info1343 / Last changed on Thu Oct 20 18:34:21 2005 by Björn Lindqvist (bjourne-at-gmail-com)


20. The GTK Mainloop and Threading


20.1.1344 What are the general tips for using threads with PyGTK?

One thread (usually the main thread) should call gtk.threads_init() and gtk.main():

 import gobject
 gobject.threads_init()

 ...

 gtk.main()
Other threads can do window modification, processing, etc. Each of those other threads needs to wrap any GTK+ method calls in a gtk.threads_enter()/gtk.threads_leave() pair.

Signal callbacks will be done in the main thread. They will also need to do threads_enter/threads_leave I believe.

A way to avoid using threads_enter/threads_leave is to call the function from the main thread, a simple way of sending a request to the server is to use gobject.idle_add:

  gobject.idle_add(...)
Eg, if you want to set the text of an entry:

  gobject.idle_add(entry.set_text, 'new text')
But be careful, because it cannot return anything which evaulates to True, if it does you have to wrap it in a lambda or a separate function

Edit this entry1345 / Log info1346 / Last changed on Thu Mar 23 16:46:53 2006 by Johan Dahlin (johan-at-gnome-org)


20.2.1347 On Win32, the input_add() function doesn't work!

No it works. It might not work with pipes but works for sockets for sure in Windows

In PyGTK 2.6 it's called gobject.io_add_watch()

Edit this entry1348 / Log info1349 / Last changed on Fri Jun 3 09:42:42 2005 by Nikos Kouremenos (kourem-at-gmail-com)


20.3.1350 How can I make Ctrl-C in the console quit my app which uses PyGTK 1.99.13 or older?

This is something of a hack, since it burns up CPU, and mainquit() won't work, but for a quick shot you can use:

 while True:
   gtk.main_iteration()
This lets the python signal handler breathe every so often. This was originally posted on [www.pycage.de]1351 and stolen :-)

See the thread [www.daa.com.au]1352 for more information, and GNOME bug 72333: [bugzilla.gnome.org]1353


If you are only interested in Ctrl-c finishing your application and you don't need special cleanup handlers, the following will perhaps work for you:

 import signal
 signal.signal(signal.SIGINT, signal.SIG_DFL)
In PyGTK 1.99.14 a timeout function was added that checks if Ctrl-C was pressed and quits.

Edit this entry1354 / Log info1355 / Last changed on Thu Mar 23 16:53:14 2006 by Johan Dahlin (johan-at-gnome-org)


20.4.1356 I get random crashing when using lots of threads in PyGTK

Edit this entry1357 / Log info1358 / Last changed on Wed Jan 22 23:45:47 2003 by Christian Reis (kiko-at-async-com-br)


20.5.1359 I want to show a splash screen and make it disappear. How?

Pablo Endres Lozada presented this question. I'd suggest using a timeout handler that calls hide() on the window. Something like:

 def setup_app(*args):
   main = gtk.Window()
   # [...] set main up

 splash = gtk.Window() 
 # [...] set splash up
 splash.show()
 # ensure it is rendered immediately
 while gtk.events_pending():
   gtk.main_iteration()

 gobject.timeout_add(5000, splash.hide) # 5*1000 miliseconds
 gobject.idle_add(setup_app)
 gtk.mainloop()
5 seconds later, the splash screen should hide. You should tie the setup portion of your application inside an idle handler (or use a similar technique) or you will end up doing all the work before the splash screen shows up, mind you.

Edit this entry1360 / Log info1361 / Last changed on Tue Nov 8 15:45:19 2005 by Johan Dahlin (johan-at-gnome-org)


20.6.1362 I am using a separate thread to run my code, but the application (or the UI) hangs.

There are a couple of hitches you can run into when trying to use threading and PyGTK together. For starters, if you are using threads, no matter if you are doing PyGTK calls from a separate thread or not, you must compile PyGTK with --enable-threads.

Now there are two approaches for threads in PyGTK:

1. Allow only the main thread to touch the GUI (gtk) part, while letting other threads do background work. For this to work, first call

  gobject.threads_init()
at applicaiton initialization. Then you launch your threads normally, but make sure the threads never do any GUI tasks directly. Instead, you use gobject.idle_add to schedule GUI task to executed in the main thread. Example:

 import threading
 import time
 import gobject
 import gtk

 gobject.threads_init()

 class MyThread(threading.Thread):
     def __init__(self, label):
         super(MyThread, self).__init__()
         self.label = label
         self.quit = False

     def update_label(self, counter):
         self.label.set_text("Counter: %i" % counter)
         return False

     def run(self):
         counter = 0
         while not self.quit:
             counter += 1
             gobject.idle_add(self.update_label, counter)
             time.sleep(0.1)

 w = gtk.Window()
 l = gtk.Label()
 w.add(l)
 w.show_all()
 w.connect("destroy", lambda _: gtk.main_quit())
 t = MyThread(l)
 t.start()

 gtk.main()
 t.quit = True
2. Allow any thread to do GUI stuff. Warning: people doing win32 pygtk programming have said that having non-main threads doing GUI stuff in win32 doesn't work. So this programming style is really not recommended.

Anyway, to make this work, start by calling:

 gtk.gdk.threads_init()
at startup. Failing to do this will make PyGTK never release the python threading lock. At least Debian's packages are compiled properly, so it's a matter of using that call.

Then you have to wrap your main loop with gtk.threads_enter()/gtk.threads_leave(), like this:

 gtk.threads_enter()
 gtk.main()
 gtk.threads_leave()
Your threads code must, before touching any gtk functions or widgets, call gtk.threads_enter(), and after gtk.threads_leave(), for example:
  ...
  gtk.threads_enter()
  try:
      myentry.set_text("foo")
  finally:
      gtk.threads_leave()
  ...
Also, keep in mind that signal handlers don't need gtk.threads_enter/leave(). There are other concerns, see [developer.gnome.org]1363 .

Cedric Gustin posted a short example of threaded code at [www.daa.com.au]1364 -- it's a good building block for a more complex threaded application.

Finally, if you are writing a C extension module, remember that you need to protect calls that potentially lock the thread with Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS.

Edit this entry1365 / Log info1366 / Last changed on Mon Aug 29 14:48:07 2005 by Gustavo Carneiro (gjc-at-inescporto-pt)


20.7.1367 I set up a timeout handler using timeout_add, but the handler only runs once.

When using a timeout handler:

 def on_timeout(self, *args):
   print "Ping", args 

 gobject.timeout_add(1000, on_timeout)
If you fail to return True in the timeout handler, it will only run once. Therefore:

 def on_timeout(self, *args):
   print "Ping", args 
   return True
will run the timeout handler every 1s.

Edit this entry1368 / Log info1369 / Last changed on Mon Apr 4 14:31:37 2005 by Nikos Kouremenos (kourem-at-gmail-com)


20.8.1370 How do I check if threading was compiled in my version of PyGTK

In PyGTK-2 all gtk.threads_init(). If you get an exception, then it isn't supported (you need to call gtk.threads_init() to enable threading support in a threaded build anyway).

In PyGTK-0, use ldd to list the dependencies of _gtkmodule.so -- if it lists pthread, it was compiled with threading.

Edit this entry1371 / Log info1372 / Last changed on Sat Jun 12 15:49:05 2004 by Christian Reis (kiko-at-async-com-br)


20.9.1373 I don't want to use threading. What other options do I have?

Stephen Kennedy reminds us that cooperative threading using generators is an alternative. Two links describe this at a bit more length:

Advantages:

Disadvantages:

For capturing the output of another process, or other file-based I/O, Danny Milosavljevic proposes using non-blocking I/O. This works like so:

He has an example module available under the LGPL at [cvs.sourceforge.net]1376

Edit this entry1377 / Log info1378 / Last changed on Sat Jul 10 11:56:26 2004 by Danny Milosavljevic (danny_milo-at-yahoo-com)


20.10.1379 When an exception is raised, it is printed out to standard error! (or how do I get exceptions to be printed to X or displayed in a window?)

One feature of running an application in the gtk mainloop is that exceptions raised don't cause an actual crash. All that happens is the callback that was executing will be interrupted -- the mainloop goes on spinning and handling events. The exception is printed out to standard error, which is great for development and developer-testing, but not as great when running without a console attached to your application, or in a production environment.

There are two approaches here, both useful in different situations.

  logfile = os.path.expanduser("~/.myapp.log")
  sys.stderr = open(logfile, 'a')
You can also combine this with a log() call that outputs to sys.stderr too:

  def log(self, s):
      now = time.strftime("%Y-%m-%d %H:%M")
      sys.stderr.write("%s: %s\n" % (now, s))
I use a function like this with a cronjob to pick up exceptions raised daily in client installations. This way I can collect problems before the user has time to report them!

Edit this entry1381 / Log info1382 / Last changed on Tue Nov 8 15:46:38 2005 by Johan Dahlin (johan-at-gnome-org)


20.11.1383 How can I monitor sockets or files inside the gtk mainloop (or how does gtk.input_add() work)?

PyGTK provides a method for monitoring a file or socket and automatically calling a users function:

 id = gtk.input_add(file_object, condition, function)
As seen above, gtk.input_add parameters are a file object, an integer constant that describes the condition you are monitoring for, and a callable.

condition is one of the following (use gtk.gdk for PyGTK-2):

Note, some versions of pyGTK require you to use:

 import GDK
 GDK.INPUT_READ
instead of gtk.INPUT_READ (or WRITE or EXCEPTION).

Example call:

 id = gtk.input_add(self.server, gtk.INPUT_READ, self.GetIO)
gtk.input_add returns an identifier, an integer than can be used with:

 gtk.input_remove(id)
to stop processing the associated file or socket. This only needs to be called when your application no longer needs the socket, not after each read or write.

The callable function should return gtk.TRUE if it wants to continue getting called in the future.

John Nelson writes to say: It may be worth noting that if your application has separate mainloop threads (i.e. you run the pygtk mainloop from more than one thread), there seems to be evidence that gtk "may" use a seperate thread to notify your program when the desired condition becomes true. Thus, if you do any gtk (gdk, really) work in the handler, you may need to call gtk.threads_enter() and gtk.threads_leave() when done.

While I can't confirm this is true, if you are seeing this symptom, give it a try and email me to update the FAQ if you do.

Another important note is that in GTK version 2, you will get back a fd in your handler if the object you pass in has a fileno() method (like a socket does). In GTK version 1, you will get a socket back if you pass a socket in. E.G.:

 ...
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

 listenhost=""
 listenport=port
 s.bind((listenhost, listenport))
 s.listen(5)
 #GDK->gtk.gdk in GTK V 2.0
 id=gtk.input_add(s, GDK.INPUT_READ, handleNewConnection)

 ...

 def handleNewConnection(self,source,condition):
     #source is a socket in GTK v 1 and a fd in version 2
     ...
     return gtk.TRUE

Edit this entry1384 / Log info1385 / Last changed on Fri Jan 30 19:07:19 2004 by Christian Reis (kiko-at-async-com-br)


20.12.1386 How do I get an action to run periodically, say, every 30 seconds?

Short answer: use gobject.timeout_add(). A longer answer with one caveat is available as FAQ 20.71387.

Edit this entry1388 / Log info1389 / Last changed on Tue Nov 8 15:49:02 2005 by Johan Dahlin (johan-at-gnome-org)


20.13.1390 The GTK thread dies, but some windows remain open. I don't want that, what can I do?

GTK doesn't close windows automatically when the thread which create them exits because it doesn't associate its windows with threads, so there's no reason to close them when a thread exits.

You can use the gtk.window_list_toplevels() function that will get all top level windows in the application. And you can destory those windows. If you want to close only some windows, then you must keep track of them or somehow choose which ones to destroy.

Note that closing all windows won't release all memory allocated by GTK. AFAIK, there is no function to clean up everything. GTK is designed to run for the lifetime of the process, so it is not a high priority to add functions to clean up internal hash tables and other data structures because they are usually needed until the process terminates. If you need a hard guarantee that everything will be freed, you may want to start a separate process.

Information provided by John Ehresman

Edit this entry1391 / Log info1392 / Last changed on Thu Mar 3 22:47:56 2005 by Nikos Kouremenos (kourem-at-gmail-com)


20.14.1393 My application uses threads and GtkDialogs seem to freeze it! What can I do?

You can sove it easily: see Q 10.17

Edit this entry1394 / Log info1395 / Last changed on Thu Mar 3 23:18:45 2005 by Nikos Kouremenos (kourem-at-gmail-com)


20.15.1396 I'm using threads and timeout or idle or input handlers and the app freezes. What's wrong?

From gtk.gdk.theads_init reference: Signal handlers are automatically invoked within a gdk_threads_enter() and gdk_threads_leave() function pair by GTK so the gtk.gdk.threads_enter() and gtk.gdk.threads_leave() functions should not be called within a Python signal handler or the application will deadlock. However, idle, timeout and input handlers are executed outside the GDK global lock (GGL) so these should use the gtk.gdk.threads_enter() and gtk.gdk.threads_leave() functions if PyGTK methods or functions are called.

An example to illustrate better the proposed solution follows:

    def run(self, called_by_timeout=False):
        if called_by_timeout:
           # if it was called outside of GDK global lock (eg. here a timeout) make sure we threas_enter
           gtk.gdk.threads_enter()

        ...code-here...

        if called_by_timeout:
           gtk.gdk.threads_leave()
more: [www.pygtk.org]1397

info provided by Víctor M. Hernández Rocamora

Edit this entry1398 / Log info1399 / Last changed on Tue Mar 15 09:49:32 2005 by Nikos Kouremenos (kourem-at-gmail-com)


20.16.1400 So how do I use gobject.io_add_watch (used to be input_add) ?

this will get and print index.html's html source without blocking or freezing your GUI

	import socket
	import gobject
	import gtk

	def handle_data(source, condition):
		data = source.recv(1024)
		if len(data) > 0:
			return True # run again
		else:
			return False # stop looping (or else gtk+ goes CPU 100%)

	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.settimeout(15)
	sock.connect(('pygtk.org', 80))
	sock.send('GET /index.html HTTP/1.1\nHost: pygtk.org\n\n')

	gobject.io_add_watch(sock, gobject.IO_IN, handle_data)
	w = gtk.Window()
	w.add(gtk.Button('abc'))
	w.show_all()
	gtk.main()
io_add_watch() can watch on objects return by urllib.urlopen() too

Please keep in mind that io_add_watch() works for sockets on all platforms, but if you want to watch files you have to use GNU/Linux or other Unices

Advanced Usage:

as you can see once you get EOF gtk+ forces you to give up on reading more possible stuff there. That is not sane for all usages but it's what it's done. I sat down and tried to workaround this. I ended up with something I hope you will find useful:

	import socket
	import gobject
	import gtk
	import signal

	def get_file():
		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		sock.settimeout(15)
		sock.connect(('pygtk.org', 80))
		sock.send('GET /index.html HTTP/1.1\nHost: pygtk.org\n\n')
		return sock

	def handle_data(source, condition):
		data = source.recv(12)
		print len(data)
		if len(data) > 0:
			return True #run forever
		else:
			print 'closed'
			print 'so get new data...'
			sock = get_file()
			gobject.io_add_watch(sock, gobject.IO_IN, handle_data)
			return False # stop looping

	sock = get_file()
	gobject.io_add_watch(sock, gobject.IO_IN, handle_data)

	w = gtk.Window()
	w.set_border_width(15)
	msg = '''\
	Play with resizing the window...

	RESULT:
	It will only block on sock.connect()
	which is normal because to use the socket you have to connect
	here we wait for maximum 15 seconds and then we timeout'''
	w.add(gtk.Label(msg))
	w.show_all()
	signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
	gtk.main()

Edit this entry1401 / Log info1402 / Last changed on Mon Jun 27 18:10:38 2005 by Nikos Kouremenos (kourem-at-gmail-com)


20.17.1403 Why isn't my thread running?

Regardless of what the thread does, gtk.threads_init() must be called before gtk.main(). Typically the main thread calls both.

Edit this entry1404 / Log info1405 / Last changed on Wed Jul 13 02:58:25 2005 by Phillip Calvin (phillipc-at-toasterlogic-com)


20.18.1406 How do I write a qt application using gobject.MainLoop?

(The latest copy of this document can be found at [www.patrickkidd.com]1407 )

GStreamer-0.10 uses asynchronous calls to control its pipelines, and these calls have async replies. You can get these replies by either polling the pipeline's bus, or by running a gobject.MainLoop. Problems arise when you are writing a qt application that has its own main loop, and your application doesn't necessarily have multi-threaded requirements (besides those already implemented by gstreamer). The following class will run the gobject.MainLoop whenever the QApplication is idle by using QTimer.start(0), and gobject.MainLoop.MainContext.pending/iteration.

The exception in the constructor protects the singleton-nature of gobject.MainLoop for this application. Now you can just make your async calls from within the main qt thread. Fire away!

 import sys
 import time
 import gobject
 from PyQt4.QtCore import QObject, QTimer, SIGNAL, QThread, QEventLoop
 from PyQt4.QtGui import QApplication

 gobject.threads_init()

 class GObjectLoop:
     """ Manages a gobject.MainLoop. """

     _instance = None

     def __init__(self):
         if not QGObjectLoop._instance is None:
             raise RuntimeError('there can only be one QGObjectLoop')
         else:
             QGObjectLoop._instance = self
         self.gmainloop = gobject.MainLoop()
         # this is horribly inefficient!
         self.gcontext = self.gmainloop.get_context()
         self.idletimer = QTimer(QApplication.instance())
         QObject.connect(self.idletimer, SIGNAL('timeout()'),
                         self.on_idle)
         self.idletimer.start(0)

     def __del__(self):
         self.gmainloop.quit()

     def on_idle(self):
         while self.gcontext.pending():
             self.gcontext.iteration()

 # this prevents a seg fault, not sure why.
 import atexit
 def _atexit():
     GObjectLoop._instance = None
 atexit.register(_atexit)
The only problem with this is that it is terribly (horribly) inefficient. In fact, your main thread is likely to hog all remaining CPU cycles! This is because qt will check the gobject main loop whenever it is idle, which is the same as saying your machine will run on_idle whenever it is idle. I ran into some threading problems with trying to run the qt and gobject loops in seperate threads, and decided that this was much easier. Good luck!

Edit this entry1408 / Log info1409 / Last changed on Sun Apr 30 21:00:34 2006 by Christian Reis (kiko-at-async-com-br)


20.19.1410 What does "Fatal Python error: GC object already tracked" mean?

This error will most likely happen in a threaded application. Make sure you have informed gobject you are writing a threaded script/application by calling gobject.threads_init() just after importing the gobject module.

Edit this entry1411 / Log info1412 / Last changed on Sun Apr 30 21:00:58 2006 by Christian Reis (kiko-at-async-com-br)


21. Win32 and PyGTK


21.1.1413 How do I get PyGTK running on MS Windows?

(Assuming you really want to do this, you should be aware that PyGTK works reasonably well on Windows, much to the credit of GTK+, Python and PyGTK developers and porters)

Cédric Gustin maintains the primary windows pygtk site containing win32 ports: [www.pcpm.ucl.ac.be]1414

The site includes installers of PyGTK-0.6.x and the 2.x line for Python 2.2. If you require Python 2.1, the older 0.6.9 version is available here: [www.pcpm.ucl.ac.be]1415

Note that, to run pygtk2, you will need a number of prerequisite DLLs. FAQ 21.21416 describes the steps to get pygtk running, including getting the dependencies installed and configured.

There are some older versions of pygtk still available:

Edit this entry1420 / Log info1421 / Last changed on Wed Jun 16 10:44:25 2004 by Christian Reis (kiko-at-async-com-br)


21.2.1422 Is there a walkthrough on getting PyGTK2 and libglade2 to work on win32

You need to install win32 versions of the following:

Here is how to do it:

1. If you don't have it, get Python for Windows from [www.python.org]1423

2. There is more than one way to install GTK runtime for win32. (2a) is the easiest (2b) gives a recipe that uses a simple installer. (2c) is more complicated but lets you choose which bits of GTK you want.

2a. The gladewin32 project [gladewin32.sourceforge.net]1424 offers a Gtk+/Win32 Development Environment (runtime, devel, docs, glade, etc.) Installer. This includes both GTK and glade libraries, plus a win32 version of the glade editor too. It installs in C:/GTK by default (we refer to this folder as %gtkdir% in a step further down).

If you use this installer, it includes libglade, and you can skip to step 4.

2b. From [www2.arnes.si]1425 get the GTK+ 2 for Windows runtime environment. Unzip it and run the setup program. It should install the libraries in C:\Program Files\Common Files\GTK\2.0\ (from now on called %gtkdir%).

Note this does not include libglade. Go to step 3.

2c. From [www.gimp.org]1426 get the recommended versions of the following packages:

Unpack the packages downloaded in a common directory, e.g. C:\Program Files\Common Files\GTK\2.0\ (from now on called %gtkdir%)

Note this does not include libglade. Go to step 3.

3. From [gladewin32.sourceforge.net]1428 download libglade-bin. Unzip and copy the contents of the bin directory to %gtkdir%/bin. While you're there, you can grab the Glade for Win32 Binary Installer [gladewin32.sourceforge.net]1429 which confusingly does not include libglade!

4. There are two possibilities for this step, which involves making the installed libraries visible to other programs. *Note that this requires modifying PATH and NOT PYTHONPATH*

4a. The simplest way to enable GTK+ for your system is to add %gtkdir%\lib and %gtkdir%\bin to your PATH.

If you are using Windows 2000/XP, you can edit the path in Start - Control Panels - System - Advanced - Environment Variables.

If you are using a DOS-based Windows version (W95,W98,ME), add the following line to your C:\AUTOEXEC.BAT file:

  set PATH="%PATH%;%gtkdir%\lib;%gtkdir%\bin" 
(You need to substitute %gtkdir% with your actual directory of course.)

4b. If you don't want to alter the system path, but can change the scripts you will run that require gtk2, add these lines to them (before the pygtk import):

 # Make Windows actually find the stuff installed
 gtkdir = 'C:/Program Files/Common Files/GTK/2.0'
 import os
 os.environ['PATH'] += ";%s/lib;%s/bin" % (gtkdir, gtkdir)
5. Reboot (editor's note: mwahahaha). (Although you probably don't need to reboot on WinXP.)

6. Download and install the PyGTK package from [www.mapr.ucl.ac.be]1430

7. You can test everything is working by starting a Python interpreter and issuing:

  # ensure we're using the right version
  import pygtk
  pygtk.require ('2.0')

  import gtk
  import gtk.glade
The "import pygtk" bits will be necessary depending on what PyGTK version you have. If you omit it, you may get exceptions such as "AttributeError: 'module' object has no attribute 'Window'" when referring to objects in the gtk module (in this case, gtk.Window).

8. Don't get an error message.

9. You're done.

* Note that on WinXP with the default Luna theme, GTK+-2.2.4.1 has a bug where radio buttons do not activate when clicked. GTK+-2.2.4 works fine.

(Lars Bensmann, John Platte, John Hunter)

Edit this entry1431 / Log info1432 / Last changed on Sat Feb 19 06:15:58 2005 by matthew arnison (maffew-at-cat-org-au)


21.3.1433 Does the Win32 port support threading?

More or less.

The current (and unlikely to change) status of threads on win32 is that you basically can't perform gui operations from a subthread, even with gdk_threads_enter/leave (and any GTK or GDK call should be considered a "gui operation"). Essentially, the X11 and win32 gui/threading models are different, and making gtk work the same on both would be very hard. There is a proposal to solve this problem more fundamentally at [bugzilla.gnome.org]1434

This isn't entirely bad news, though. Threads on win32 /do/ work in most situations.

If you need to use signals in a threaded win32 application, you need to make sure that the signal sent to your widget is done from the main thread instead of the subthread. The easiest way to do this is using gobject.idle_add via a wrapperfunction:

  def do_gui_operation(function, *args, **kw):
      def idle_func():
          gtk.threads_enter()
          try:
              function(*args, **kw)
              return False
          finally:
              gtk.threads_leave()
      gobject.idle_add(idle_func)
Now, in your subthread, instead of calling:

  gtk.threads_enter()
  do_gtk_stuff(arg1, arg2)
  gtk.threads_leave()
You should call:

  do_gui_operation(do_gtk_stuff, arg1, arg2)
You don't need to hold the thread lock to call gobject.idle_add (or do_gui_operation) but you do need to acquire it inside the idle function because they are, by default, run without holding the thread lock.

Note also some advice from Alexandre Fayolle, Win32 PyGTK extraordinaire, on older versions of PyGTK:

A trick to get threads to work properly that was sent to the list some time ago (I don't remember who I should credit for it, but it works very well) is to add a timeout function that does a very short sleep, for instance 1e-3 seconds, using timeout_add(...), for instance:

 from gtk import *
 import time
 import sys
 def sleeper():
    time.sleep(.001)
    return 1 # don't forget this otherwise the timeout will be removed

 if __name__== '__main__':
    # do other inits here
    if sys.platform == 'win32':
        timeout_add(400,sleeper)
    mainloop()
You should adjust the value of the period of the timeout so that your app still runs smoothly.

If you want pseudothreads that do not suffer from such problems see: [aspn.activestate.com]1435 [www.gnome.org]1436

Edit this entry1437 / Log info1438 / Last changed on Sun May 15 18:59:06 2005 by Nikos Kouremenos (kourem-at-gmail-com)


21.4.1439 Where is GdkImlib for MS Windows?

If you're looking for information on running GdkImlib under windows, here's the beef:

See [groups.yahoo.com]1440 . The native port of gdkimlib has been "abandoned" by the author of gtk+ on win32. I guess the only solution is to compile gtk+-1.2, gdkimlib and pygtk for X11 using cygwin and its port of XFree 4.2.

(Cedric Gustin)

If you plan to work with pygtk and gnome 2.0, you should switch to gdk-pixbuf, which actually works under windows : [developer.gnome.org]1441

(Runar Petursson)

Edit this entry1442 / Log info1443 / Last changed on Thu Aug 7 21:36:33 2003 by Christian Reis (kiko-at-async-com-br)


21.5.1444 How can I bundle a PyGTK program in windows so my users don't need to install Python or the GTK+ libs?

On win32, you should give py2exe [www.py2exe.org]1445 a try. It works with pygtk. Once your code is frozen, you can create an installer with Inno Setup for example.

Michal Pasternak recommends giving cxFreeze a try: [starship.python.net]1446 . It works in a different way than py2exe and McMillan Installer; it's faster building the package, and it doesn't automatically include all the DLLs.

The gtk+-2.x runtime environment is available here, and also as a nice installer: [gladewin32.sourceforge.net]1447

Other alternatives may include Gordon McMillan's installer which used to be available at [www.mcmillan-inc.com]1448 ([web.archive.org]1449 waybackmachine copy) - he had an overview of the other options as well in the right-hand column of that page.

[www.anti-particle.com]1450 describes one example using GTK+ 2.4, py2exe (0.5.x) and Inno Setup, and here's another one, courtesy of Jamey Cribbs:

Ok, here are some very rough notes on creating a self-executing installer of your pygtk app for Windows. I'm sure there are better ways to do this, but this works for me.

1.) Install py2exe and Inno Setup.

2.) Add os.environ['PATH'] += ";gtk/lib;gtk/bin" to top of your script.

3.) Create an executable of your app using py2exe. This is going to take a lot of trial and error, because, although the exe will probably work on your original machine, when you move it to a "clean" machine, you invariably will be missing a module that py2exe did not automatically include. Not to worry! Py2exe give you various ways to manually include missing modules. It's going to take some tweaking, but you will get there. Here is an example of the command line that I use for my app:

python setup.py py2exe --force --excludes gtk, gobject,pango --packages pyPgSQL --icon fred6.ico

(Note I think this command example is a bit stale. E.g. --force does not seem to work with versions downloaded in Oct 2004. Also the --excludes and other options can be included in the setup.py script. I suggest checking the mailing list archives.)

The reason we exclude gtk is that gtk needs some extra files, which gtk searches for relative to the path of the gtk DLLs. So it is safer to just copy the whole gtk tree intact, as is done below. This means the extra files can be found, e.g. those in gtk/etc and gtk/lib; and helps with debugging by avoiding multiple copies of the same DLL in the installation.

Here's what my setup.py script looks like:

  from distutils.core import setup
  import py2exe
  import glob

  setup(name="fredgui", scripts=["fredgui.pyw"],
   data_files=[(".",glob.glob("*.bmp")),(".",glob.glob("*.gif")),
               (".",glob.glob("*.png")),(".",glob.glob("*.jpg")),
               (".",glob.glob("*.ico")),(".",glob.glob("*.xpm")),
               (".",glob.glob("../../jgcmodules/*.py"))],)
4). Ok, now that I have a exe for my app, I need to copy some directories to the "dist/fredgui" directory that py2exe created to hold my app. I copy everything below c:\program files\common files\GTK\2.0 to a "gtk" directory under my dist/fredgui directory. (NOTE: this is not needed (py2exe does that) I also copy all of the pygtk files (and included subdirectories), from my python disribution, into my dist/fredgui directory.)

5.) Now, we turn to Inno Setup. There's a copy of my Inno script at [www.async.com.br]1451 .

6.) I compile the script and it creates a setup.exe. Copy this to a "clean" machine and run it. It should install the app, create desktop icon, start menu icons, etc. Try to run the app. If it doesn't work, chances are that you are missing a module that didn't get included in either py2exe or Inno setup. One cheezy way to debug it is to initially create the executable in py2exe as a console app (using the --console flag in py2exe). This means that, even though the app is a gui, it will still open a dos box when it runs on the target machine. This will alllow you to see the error message that gets generated when it bombs out on the clean machine.

7). Don't give up. It will probably take several tries, but eventually you will end up with a working executable on the clean machine!

Note: The above instructions are an EXTREMELY cheesy way to accomplish the task of creating a self-installing pygtk app. I'm sure that there are many more efficient ways of doing this. Also, my knowledge of py2exe and Inno setup is VERY limited, so I'm sure that there are things that could be done much better using these tools.

I hope these notes have been helpful (and that I didn't forget any steps!).

Note: If your app crashes on non-English Windows, but works OK on English Windows, it may be due to corrupted locale files (*.mo in the gtk runtime tree).

Final note: If you are using Python 2.2.3 or later, and you're getting a UnicodeError when running your script, see Michal's Pasternak's explanation at [pasternak.w.lub.pl]1452

Edit this entry1453 / Log info1454 / Last changed on Wed Mar 1 06:49:14 2006 by Filip Van Raemdonck (mechanix-at-debian-org)


21.6.1455 How do I change the Window icon of a Win32 PyGTK app?

See FAQ 10.71456.

Edit this entry1457 / Log info1458 / Last changed on Sun Jan 2 11:19:59 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)


21.7.1459 How do I make the my PyGTK app look a bit more like a `normal' Windows app?

The Gtk Wimp project produces a theme that makes GTK+ look quite similar to Windows, and on WinXP it actually uses native calls to render them. See [gtk-wimp.sourceforge.net]1460 for details and download.

It is based on the Redmond95 theme but changed significantly. Note that Raleigh is also pretty close to windows (except for subtle colors and the optionmenu).

John K Luebs offered this great explanation on what sort of differences exist, and workarounds if you don't want to use Wimp:

One important difference is the size of the fonts. The reason the default font looks so big is because Windows has a default res of 96 dpi. When GTK was first released, most people were running with monitors that were actually around 75dpi (I bet you that even today this is still the case) and therefore most people were running their X server at 75 dpi. When you run the default GTK font size (can't remember if its 10 or 12 points) at 96 it looks ridiculously big.

This does not require a change of theme. You simply need to edit your gtkrc file or parse a new one when your program starts. The "default" font on Windows 2000 systems is Tahoma 8.You can edit the gtkrc-2.0 file in your GTK runtime tree. You can also use the gtk.rc_parse function to parse a specific rc file when your application starts.

As for the resource file syntax, I think you do best to read the Resource Files chapter in section II of the GTK 2.0 API reference. What you might want is something like this in one of the rc files:

 style "win32-font"
 {
   font_name = "tahoma 8"
 }
 class "*" style "win32-font"

Edit this entry1461 / Log info1462 / Last changed on Thu Apr 17 12:11:23 2003 by Christian Reis (kiko-at-async-com-br)


21.8.1463 How do I compile PyGTK for win32

There are a set of the steps at Cedric Gustin's [www.pcpm.ucl.ac.be]1464

One potential roadbump is that for WindowsME/mingw/python2.2/pygtk2, the compiler flag -mms-bitfields needs to be set to successfully import pygtk. You can do this by editing setup.py and calling

  for module in ext_modules:
      module.extra_compile_args.append('-mms-bitfields')
Note that it has been said that cygwin-compiled pygtk may not work.

Edit this entry1465 / Log info1466 / Last changed on Mon Mar 21 12:41:07 2005 by Christian Reis (kiko-at-async-com-br)


21.9.1467 How do I find out the GTK+ installation path on windows?

Luca Gambetta (ziabice at ziabice.net) contributes the following script, which is portable between Win32 and *nix:

 import sys

 if sys.platform.startswith("win"):
     # Fetchs gtk2 path from registry
     import _winreg
     import msvcrt
     try:
         k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\GTK\\2.0")
     except EnvironmentError:
         print "You must install the Gtk+ 2.2 Runtime Environment to run this program"
         while not msvcrt.kbhit():
             pass
         sys.exit(1)
     else:    
         gtkdir = _winreg.QueryValueEx(k, "Path")
         import os
         os.environ['PATH'] += ";%s/lib;%s/bin" % (gtkdir[0], gtkdir[0])
         import pygtk
         pygtk.require ('2.0')
 import gtk

Edit this entry1468 / Log info1469 / Last changed on Fri Jun 27 16:27:28 2003 by Luca 'Ziabice' Gambetta (ziabice-at-ziabice-net)


21.10.1470 DLL Errors after upgrading to PyGTK-2.0.0.win32-py2.3

Why do I get "The procedure entry point gdk_window_get_decoration could not be located in the dll libgdk-win32-2.0-0.dll" in Windows when running a PyGTK app after upgrading to PyGTK 2.0.0.win32-py2.3?

The dll could be any of several GTK related DLLs. Such as iconv.dll, libgdk-win32-2.0-0.dll etc.. Charles Lepple was exactly right when he pointed me to the winnt/system32 directory. Glade 1.1.2 had installed a bunch of dll's in that location that were getting picked up by Python and the system, before the new GTK+ runtime 2.2.4 dlls. Python wasn't happy about it. On another system, I found a PATH with d:\tcl\bin in it, and the iconv.dll was there as well. After removing the entry from the path, and removing the dlls from the system32 dir I rebooted. Now the app loads perfectly. I haven't tried reinstalling Glade yet... However I think if I leave the GTK 2.2.4 in the PATH, and remove any rouge dlls after the install, everything should be fine.

Edit this entry1471 / Log info1472 / Last changed on Mon Sep 15 23:53:12 2003 by Steven Bell (sfbell-at-mindspring-com)


21.11.1473 Is it possible to have antialiased fonts on Win32?

Fonts on Windows are drawn by GTK+ using the native win32 calls; therefore, you need to have font smoothing enabled in Windows itself. Note that Windows will not smooth fonts within certain point sizes (6pt - 10pt for most fonts) unless you are using Windows XP.

On versions other than WinXP, you can enable font smoothing on Windows by following these steps:

And on Windows XP:

Note that GTK and Pango do not use Xft on Windows, so the GDK_USE_XFT flag doesn't have any meaning there.

(James and Tim Evans)

Edit this entry1475 / Log info1476 / Last changed on Mon May 31 20:36:31 2004 by Christian Reis (kiko-at-async-com-br)


21.12.1477 How do themes work on win32?

A patch was submitted to sourceforge to request the inclusion of the precompiled engines and associated themes in the main distro a while ago; check the patches page on [sourceforge.net]1478 .

The tricky bit is how to tell GTK on Windows which theme to use. There are at least 3 ways to do this (though I have only tested 2):

With the second choice there is less room for error since you do not have to rename folders: you simply copy one file into a different location. To get back to the original settings you just delete that gtkrc from the etc/gtk-2.0 folder.

If you don't want to tweak with rc files, there also a GUI program by Alex Shaduri to preview and select the theme and font to be used by all GTK apps. It's called "gtk2_prefs" and you will find it at [members.lycos.co.uk]1479 (version 0.2.0 was current as of this writing).

Note that all themes mostly work with some off-by-one glitch drawing seen on the right of some borders.

(Tyler Wilson, Fabien Coutant)

Edit this entry1480 / Log info1481 / Last changed on Thu Mar 18 18:14:55 2004 by Fabien COUTANT (no-email -at- world-com)


21.13.1482 Can PyGTK have the native filechooser of Windows?

This is a replacement for the earlier version of this FAQ entry that didn't work when tested in Win 2k.

The following is directly copied from C:\Python24\Lib\site-packages\win32\Demos\GetSaveFileName.py (so you need to install the 'win32all' package).

  import win32gui, win32con, os

  filter='Python Scripts\0*.py;*.pyw;*.pys\0Text files\0*.txt\0'
  customfilter='Other file types\0*.*\0'

  fname, customfilter, flags=win32gui.GetSaveFileNameW(
    InitialDir=os.environ['temp'],
    Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
    File='somefilename', DefExt='py',
    Title='GetSaveFileNameW',
    Filter=filter,
    CustomFilter=customfilter,
    FilterIndex=1)

  print 'save file names:', repr(fname)
  print 'filter used:', repr(customfilter)
  print 'Flags:', flags
  for k,v in win32con.__dict__.items():
    if k.startswith('OFN_') and flags & v:
        print '\t'+k

  fname, customfilter, flags=win32gui.GetOpenFileNameW(
    InitialDir=os.environ['temp'],
    Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
    File='somefilename', DefExt='py',
    Title='GetOpenFileNameW',
    Filter=filter,
    CustomFilter=customfilter,
    FilterIndex=0)

  print 'open file names:', repr(fname)
  print 'filter used:', repr(customfilter)
  print 'Flags:', flags
  for k,v in win32con.__dict__.items():
    if k.startswith('OFN_') and flags & v:
        print '\t'+k

Edit this entry1483 / Log info1484 / Last changed on Thu Mar 9 02:35:26 2006 by John Pye (john-pye-at-student-unsw-edu-au)


22. libglade


22.1.1485 How do I use PyGTK and glade together (using libglade)?

For a more in depth answer see the Glade articles at [www.pygtk.org]1486

Basically, the steps involved are:

1. Create your interface with glade, and save the XML file (say, foo.glade).

2. Implement the relevant code using gtk.glade:

  import gtk.glade
  # instantiate XML object
  tree = gtk.glade.XML("foo.glade")
  # get references to individual widgets
  w1 = tree.get_widget("window1")
  e1 = tree.get_widget("entry1")
Some explaining is due. First, by instantiating an gtk.glade.XML object, you are actually parsing the glade file in runtime. The XML instance abstracts the glade widget tree, which is why it's often named "tree" or "wTree" in examples.

It's important to understand that by creating an XML instance you are in fact *generating the UI*, and all widgets will be created in this step. To deal with visibility issues, see FAQ 22.61487.

The most important method in the XML instance is get_widget(), which returns widgets defined in your glade file by name. Glade assigns names by default, and the pattern is usually <widgetname><number>; in the example above we are using the default widget names for a GtkWindow and a GtkEntry. You are advised to change these names to something that makes sense for your application to avoid going insane performing code maintenance.

If you'd like to deal with signals defined in the gladefile, take a look at FAQ 22.41488.

Keep in mind that gtk.glade automatically caches XML trees. So don't try any complex tricks to reuse XML trees if you have to create the same UI multiple times. The correct thing to do is simply to instantiate the XML multiple times with the same parameters.

Edit this entry1489 / Log info1490 / Last changed on Sat Feb 4 02:06:56 2006 by Steve Chaplin (stevech1097-at-yahoo-com-au)


22.2.1491 How do I internationalize a PyGTK and libglade program?

1. Simple PyGTK application

1.1 Prepare your application

 print _('Hello World!')
 s = _('%s: %u / %u\n') % (id, x, y)
1.2 Include gettext support

 APP = 'myapp'
 DIR = 'locale'

 import locale
 import gettext
 locale.setlocale(locale.LC_ALL, '')
 gettext.bindtextdomain(APP, DIR)
 gettext.textdomain(APP)
1.3. Create the translations

Please note that the command line tools used in this example requires gettext installed. See* [www.gnu.org]1492 for more information

 xgettext -k_ -kN_ -o messages.pot *.py

 LANG=de_DE msginit

 msgmerge -U de.po messages.pot

 mkdir -p locale/de/LC_MESSAGES/
 msgfmt de.po -o locale/de/LC_MESSAGES/myapp.mo
4. Thats it - now use your application!

 # start without any translation
 LANG=de_DE python myapp.py
2 Translating glade files

2.1 Extracting strings

 intltool-extract --type=gettext/glade foo.glade
This way is prefered and will also take into account and will not include the strings that were not marked for translation

Include *.c as an argument to xgettext if you chose to have glade generate .c file instead of using intltool. In case of intltool-extract add *.glade.h instead of the .c file

2.2 Using the right domain

 widgets = gtk.glade.XML(glade_file, widget_name, APP)

Edit this entry1493 / Log info1494 / Last changed on Thu Jan 19 16:34:35 2006 by Johan Dahlin (johan-at-gnome-org)


22.3.1495 Why doesn't gettext work on my libglade UIs with Python <= 2.2?

Note: this has been fixed in Python2.3 by Martin v. Löwis; see the bug report at [sourceforge.net]1496 for details.

This was actually a problem with Python. Python2.0 to 2.2 included a pure-python gettext.py module, which provides the same basic gettext API, but has some new features. The problem with a pure python implementation is that it never calls glibc textdomain() and bindtextdomain(). Since libglade is implemented in C, the internationalization happens outside the scope of the python interpreter. Without *textdomain(), libglade never knows that C gettext support is to be activated for the UI you are instantiating.

There are a few workarounds:

 gtk.glade.bindtextdomain(APP, DIR)
 gtk.glade.textdomain(APP)

 import dl
 l = dl.open('/lib/libc.so.6')
 l.call('bindtextdomain', APP, DIR)
 # if you want unicode strings:
 l.call('bind_textdomain_codeset', APP, 'UTF-8');

Edit this entry1498 / Log info1499 / Last changed on Wed May 25 10:09:56 2005 by Christian Reis (kiko-at-async-com-br)


22.4.1500 I'm using libglade, but what do I do with the signals and handlers I set in the glade file?

Typically, you create an python object to represent a window, and then construct that object from a libglade file. PyGTK allows you to connect the signal handlers from the glade file directly to methods on your glade proxy object:

 class MyWindow:

    def __init__(self):
	# Load the glade file
        wtree = glade.XML('foo.glade')
	# Connect the glade signals handlers to the python callbacks
	wtree.signal_autoconnect(self)

    # define a callback (method)
    def a_name_of_a_signal_handler(self, *args):
        ....
The nice thing about autoconnecting to an object is that you connect to bound methods, so you always receive a reference to the object itself in the method arguments. The other arguments of the method are the standard signal arguments. Note that PyGTK _will not_ warn you about signal handlers that were registered in the glade file, but are not implemented in your object.

Often, you will also want to reference the widgets that you construct. This snippet of code, to be placed at the end of __init__, will make add each widget as an attribute of your object:

        for w in wtree.get_widget_prefix(''):
            name = w.get_name()
            # make sure we don't clobber existing attributes
            assert not hasattr(self, name)
            setattr(self, name, w)
The object-autoconnection feature was implemented in PyGTK 1.99.15; older versions don't have it. Other methods for doing the autoconnection follow.

Instead of passing signal_autoconnect an object, you can pass it a dict filled with methods, like

 dict[glade_method name] = python_method_reference
and call:

 gladetree.signal_autoconnect(dict)
for signal connection to be performed.

There are a number of base classes that wrap this process, as well. One is included with Kiwi: [www.async.com.br]1501 and another, with Mitch Chapman's GladeBase: [ftp.ssc.com]1502 (article at [www.linuxjournal.com]1503 )

Jonathan Bartlett also contributed this class to the list:

 import new, types

 class GladeWidget:
    #This method loads the XML file and autoconnects the signals
    def initialize(self, glade_file, widget_name):

        #initialize variables
        self.widgets = GladeXML(glade_file, widget_name)
        callbacks = {}

        #find and store methods as bound callbacks
        class_methods = self.__class__.__dict__
        for method_name in class_methods.keys():
            method = class_methods[method_name]
            if type(method) == types.FunctionType:
                callbacks[method_name] = new.instancemethod(
                                         method, self, self.__class__)
        self.widgets.signal_autoconnect(callbacks)
Simply use this as the base class of your GLADE window, and just define the signal handlers as regular methods. In your __init__ method, you need to call self.initialize("yourfile.glade", "YourGLADEWindowName").

Here's an example where arguments other than the widget are passed to the signal handler (note the tuple for handling clicks to the ok button):

 wTree2 = libglade.GladeXML("somefile.glade","proxy1")
 proxywidget = wTree2.get_widget("proxy1")
 id=1
 dic= {"on_cancel_clicked": proxywidget.destroy,
       "gtk_widget_destroy": proxywidget.destroy,
       "on_ok_clicked": ( handle_ok_clicked, wTree2,id)}
 wTree2.signal_autoconnect (dic)
Then the handler would be defined like so:
 def handle_ok_clicked(self,widget,name,wTree2,widgetid):
Last but not least read this tutorial: [patrick.wagstrom.net]1504

Edit this entry1505 / Log info1506 / Last changed on Mon Jun 13 12:02:39 2005 by Nikos Kouremenos (kourem-at-gmail-com)


22.5.1507 I'm using Gnome and libglade, but some widgets don't work properly.

This can happen with quite a few widgets (though a crash is more likely, as you can see from the last faq). The example posted to the mailing list recently refers to GnomeDateEdit - it was being made available (using GladeXML's get_widget() call) as a gtk.HBox. What could it be?

When using Gnome and libglade, you MUST import gnome.ui before doing any GladeXML parsing. Failing to do that means gnome will never be initialized and libglade will just Do Bad Things<tm>

Edit this entry1508 / Log info1509 / Last changed on Fri Jan 10 12:14:11 2003 by Christian Reis (kiko-at-async-com-br)


22.6.1510 When I invoke GladeXML() or glade.XML() all the widgets in my gladefile are displayed!

This is the correct behaviour with libglade, since all it does it render widgets as specified in the gladefile. What you need to do is set them as non-visible (in glade, the Properties dialog, Common tab contains a "Visible" toggle button. Push it).

Normally, you want to make all *top-level* widgets in your gladefile non-visible. The child widgets should be visible - this way, you only need to show/hide the toplevel to show the whole window, which is what you usually want.

Edit this entry1511 / Log info1512 / Last changed on Thu Jul 24 19:03:11 2003 by Christian Reis (kiko-at-async-com-br)


22.7.1513 How do I create and use a custom Glade widget?

Ross Burton wrote a patch for custom widget support, which has been integrated into PyGTK-2. A working example follows.

        import gtk
        import gtk.glade

        def create_source_cd_dropdown():
            return gtk.Label("source")

        gtk.glade.set_custom_widget_callbacks(locals())
        glade = gtk.glade.XML("cd-copier.glade")
        window = glade.get_widget("window")
        window.show_all()
        gtk.main()
Note that the glade file must define the proper callback name for the custom widget; in this case, create_source_cd_dropdown. The important call is gtk.glade.set_custom_widget_callbacks(), which takes a dictionary of function names->functions (which is why locals() works in the example).

The above method is deprecated in recent versions of pygtk.

The new API uses the method gtk.glade.set_custom_handler, which allows you to treat widget creation more dynamically if you wish.The set_custom_handler API works as follows:

    def my_handler (glade, function_name, widget_name, str1, str2, int1 , int2):
        # create your widget based on our arguments...
        return a_custom_widget

    gtk.glade.set_custom_handler(my_handler)
The following example, adapted from SimpleGladeApp.py in Sandino Flores Moreno's SimpleGladeApp.py shows how to use set_custom_handler to allow you to create custom handler constructors simply by naming class methods with the constructor names.

IMPORTANT: The call to gtk.glade.set_custom_handler() (as well gtk.glade.set_custom_widget_callbacks()) must come before the load of any Glade widget (by calling gtk.glade.XML()). The reason is that Glade needs to call the handlers when processing the XML file. The handlers are used to construct widgets, which happens at construction-time.

 class MyGladeApp:

     def __init__ (self):
         gtk.glade.set_custom_handler(self.get_custom_handler)
         self.glade = gtk.glade.XML('/path/to/gladefile.glade')
     ...

     def get_custom_handler(self, glade, function_name, widget_name,
			str1, str2, int1, int2):
	"""
	Generic handler for creating custom widgets, used to
	enable custom widgets.

	The custom widgets have a creation function specified in design time.
	Those creation functions are always called with str1,str2,int1,int2 as
	arguments, that are values specified in design time.

	This handler assumes that we have a method for every custom widget
        creation function specified in glade.

        If a custom widget has create_foo as creation function, then the
	method named create_foo is called with str1,str2,int1,int2 as arguments.
	"""
	handler = getattr(self, function_name)
	return handler(str1, str2, int1, int2)

Edit this entry1514 / Log info1515 / Last changed on Tue Dec 6 11:22:30 2005 by Fabian Sturm (f-at-rtfs-org)


22.8.1516 How do I retrieve the ID of a signal connection made by signal_autoconnect?

This is currently not possible via the libglade API. However, you can avoid using autoconnect for the specific signals you require the ID, and connect() manually, storing the ID returned.

Edit this entry1517 / Log info1518 / Last changed on Wed Sep 17 12:30:43 2003 by Christian Reis (kiko-at-async-com-br)


22.9.1519 My libglade files have widgets that don't show up in the GladeXML tree!

"I seem to be having some trouble with libglade for glade files larger than about 230K. libglade cannot seem to find widget names for widgets near the end of a file this big. If I chop the end off the file and put it in a new file (fun with vi), then things work o.k. from the new file."

Do you have repeated widget names? That is usually the cause of these problems. Try doing a grep for "<name>" in the glade file, and look for duplicates.

Edit this entry1520 / Log info1521 / Last changed on Thu Apr 25 12:47:06 2002 by Christian Reis (kiko-at-async-com-br)


22.10.1522 When I load a glade file in GladeXML I get evil warnings about GnomeApp and a crash!

If you are using libglade to import your glade file, and you get something like:

 GnomeUI-CRITICAL **: file gnome-app.c: 
    line 208 (gnome_app_new): assertion `appname != NULL' failed.
 Gtk-WARNING **: invalid cast from (NULL) pointer to `GnomeApp'
it means you have GNOME widgets in your libglade app but forgot to import gnome.ui and initialize it (using the gnome-python module). However, this could happen by mistake - you might not be intentionally requiring GNOME. If you are only using GTK+ and don't want GNOME:

 *NOTE* STOCK ICONS ARE GNOME-ONLY IN GTK+ 1.2!
 YOUR BUTTONS SHOULD NOT USE THEM IF YOU DON'T WANT TO REQUIRE GNOME!
If you are using GNOME, you need to:

 import gnome.ui    
 gnome.init("programname", "version")
before you try and instantiate a GladeXML object, or you will get crashes, even in PyGTK 0.6.11 (though i'll try and fix this soon).

Edit this entry1523 / Log info1524 / Last changed on Sun Nov 3 15:21:24 2002 by Christian Reis (kiko-at-async-com-br)


22.11.1525 How do I produce or reuse a [portion of a] widget tree in glade?

You can create as many widget trees as you like based on the same glade XML content -- and libglade even caches xml parse trees automatically. You can also grab portions of widget trees by supplying a second parameter to your XML() call specifying the name of the toplevel widget you want.

The example below creates 10 identical dialogs:

  for i in range(10):
      xml = gtk.glade.XML("foo.glade", "my-window")
      win = xml.get_widget("my-window")
      win.show()
You can also get portions of windows and place them inside other widgets in runtime.

  xml = gtk.glade.XML("foo.glade", "my-vbox")
  vbox = xml.get_widget("my-vbox")
  win = gtk.Window()
  win.add(vbox)
  win.show()
You can experiment using reparent(), add() and remove() to compose your interface dynamically, reusing both code and glade XML. The only thing to remember is to make the windows not visible by default, as per FAQ 22.61526

NB: The only thing to watch out for is keyboard accelerators, which need to be attached to the main window. This, at least in PyGTK 0.6, was a non-trivial task.

Edit this entry1527 / Log info1528 / Last changed on Sun Jun 5 13:40:15 2005 by Joel Rosdahl (joel-at-rosdahl-net)


22.12.1529 How can I get a new instance of a widget defined in a glade file?

The trick here lies in the root parameter given to the gtk.glade.XML constructor, which has this signature:

  PyGladeXMLObject = gtk.glade.XML(fname, root, domain)
where usually root and domain default to None. (Refer to the libglade reference for details).

root points to the widget from which the PyGladeXML object will start to be built. Thus, if you have a widget with an id such as "label6" and you need a new copy of it you would create a new PyGladeXML object using the glade file as fname and the widget's id as the root parameter.

This is better shown with an example:

 >>> import pygtk
 >>> pygtk.require('2.0')
 >>> import gtk
 >>> gladeXML = gtk.glade.XML("mygladefile.glade") # first 
 >>> print gladeXML
 <gtk.glade.XML object (PyGladeXML) at 0xd8d990>
 >>> label6a = gtk.glade.XML.get_widget(gladeXML, "label6")
 >>> print label6a
 <gtk.Label object (GtkLabel) at 0xf5b030>
 >>> label6b = gtk.glade.XML.get_widget(gladeXML, "label6")
 >>> print label6b
 <gtk.Label object (GtkLabel) at 0xf5b030>
 >>> gladeXML2 = gtk.glade.XML("mygladefile.glade", "label6")
 >>> print gladeXML2
 <gtk.glade.XML object (PyGladeXML) at 0xef22b0>
 >>> newlabel6 = gtk.glade.XML.get_widget(gladeXML2, "label6")
 >>> print newlabel6
 <gtk.Label object (GtkLabel) at 0xf5a7d8>
As we can see, label6a and label6b are the same object, while newlabel6 is a new instance of the "label6" widget.

Edit this entry1530 / Log info1531 / Last changed on Sun Jun 5 13:39:55 2005 by Joel Rosdahl (joel-at-rosdahl-net)


22.13.1532 Tabs in Notebook don't show up!

Either you have set the number of pages to 0 or you have empty notebook pages! Libglade has problems with empty pages. One workaround is to just put an empty hbox in the pages.

you might have got this message:

(gtk_notebook_set_tab_label): assertion `GTK_IS_WIDGET (child)' failed

Edit this entry1533 / Log info1534 / Last changed on Tue Dec 21 13:01:58 2004 by Nikos Kouremenos (kourem-at-gmailDOTcom)


23. Miscellaneous questions


23.1.1535 Why does ancient PyGTK versions segfault with Python 2.2?

Ancient versions of pygtk (0.6.x) will segfault with Python 2.2 if you turn on pymalloc support when compiling python. A build of python without PyMalloc will work fine with pygtk. This is fixed in 0.6.10.

The fix is to do a search and replace s/PyMem_DEL/PyObject_DEL/ in the pygtk sources.

Thanks go to Dave Wallace for tracking this down.

Edit this entry1536 / Log info1537 / Last changed on Sat Jun 4 10:27:42 2005 by Johan Dahlin (johan-at-gnome-org)


23.2.1538 Are there any helpful tools when developing with PyGTK?

Yes, a number.

    def dirpat(o, pat):
        """like dir, but only return strings matching re pat"""
        import re
        names = dir(o)
        pat = re.compile(pat)
        return [x for x in names if pat.search(x) is not None]

 >>> import gtk
 >>> gtk.DI <Press TAB !>
 gtk.DIALOG_DESTROY_WITH_PARENT  gtk.DIR_LEFT
 gtk.DIALOG_MODAL                gtk.DIR_RIGHT
 gtk.DIALOG_NO_SEPARATOR         gtk.DIR_TAB_BACKWARD
 [...]

Edit this entry1548 / Log info1549 / Last changed on Wed Jan 18 19:13:27 2006 by Johan Dahlin (johan-at-gnome-org)


23.3.1550 How do I find out the current X and Y position of my mouse?

Every event object generated contains the x and y attributes which indicate the current pointer position. You need to find a relevant signal to generate it. So something like:

 def on_w_motion(event):
  print "Mouse position: X:%s Y:%s" % (event.x, event.y)

 w = gtk.Window()
 e = gtk.EventBox()
 w.add(e)
 e.connect("motion_notify_event",on_w_motion)
 w.show_all()
 gtk.main()
Will generate the information when you have the mouse button clicked and dragged upon the client area.

Edit this entry1551 / Log info1552 / Last changed on Sat Jun 4 10:28:35 2005 by Johan Dahlin (johan-at-gnome-org)


23.4.1553 Are there any tips for UI designers?

There is a lot of online material on designing usable interfaces, so it's really a matter of looking into it.

[www.asktog.com]1554 is a real nice reference site by Bruce Tognazzini. His column on Fitts' law is particularly interesting: [www.asktog.com]1555

[www.useit.com]1556 is Jakon Nielsen's site. Nielsen is the usability guru, but he has been concentrating on the web and appliances lately, so you might not see much conventional computer UI advice.

You should spend some time reading the HCI guidelines for the relevant projects. Reading other UI specs is interesting because you get a feeling of what research led to what.

Books I can recommend are:

Edit this entry1564 / Log info1565 / Last changed on Tue Feb 5 14:23:44 2002 by kiko (kiko-at-async-com-br)


23.5.1566 Why does my X selection disappear when my window dies?

If you have selected some text in an entry, and your application dies, you will notice that the text is "removed" from the X clipboard. James clarifies:

X selection handling is an asynchronous operation. When a user "copies" some text to the clipboard, the text doesn't necessarily get copied anywhere. Instead, the application claims the CLIPBOARD selection. When another app wants to paste the contents of the clipboard, they request the contents of the CLIPBOARD selection in a particular format (eg. UTF8 text, html, an image, etc), which sends a message to the first app. The first app then sends the data back in the requested format. This has the benefit that no data is sent over the wire until it is requested, and content type negotiation can be performed.

As you can see, this model breaks down when the selection owner window gets destroyed. There are some tools to work around this problem such as xclipboard. The downside to xclipboard is that every time the CLIPBOARD selection is claimed, the data gets requested by xclipboard, and xclipboard will only store the data in one format.

Edit this entry1567 / Log info1568 / Last changed on Tue May 28 00:57:02 2002 by Christian Reis (kiko-at-async-com-br)


23.6.1569 When compiling PyGTK, I get a bunch of weird "Could not write method ..." messages!

While building pygtk we get a whole lot of these messages:

 Could not write method GtkTextIter.forward_find_char: No ArgType 
       for GtkTextCharPredicate
 Could not write method GtkTextIter.backward_find_char: No ArgType 
       for GtkTextCharPredicate
 Could not write method GtkAccelGroup.connect: No ArgType for 
       GClosure*
 Could not write method GtkAccelGroup.connect_by_path: No ArgType 
       for GClosure*
 [...]
These are expected and not a serious problem. They are generated by the automatic code generation stuff and are more indicative of TODO items than real problems.

Edit this entry1570 / Log info1571 / Last changed on Sat Jun 4 10:29:10 2005 by Johan Dahlin (johan-at-gnome-org)


23.7.1572 Is there a way to get version information from pygtk?

For all versions of pygtk beyond 0.6.8, there are two attributes of the gtk module that provide version information.

Use gtk.pygtk_version which is a tuple with three items, (major, minor, micro):

  if gtk.pygtk_version >= (1,99,12):
      ...
If you want to check for the Gtk+ version, use gtk.gtk_version:

  if gtk.gtk_version >= (2,0,5):
      ...

Edit this entry1573 / Log info1574 / Last changed on Sun Aug 25 10:11:08 2002 by Christian Reis (kiko-at-async-com-br)


23.8.1575 How do I beep the speaker?

Easy:

 gtk.gdk.beep()
Note that it needs to be called inside the gtk mainloop for it to run immediately; if you invoke it in interactive mode, it only beeps when you exit python.

Edit this entry1576 / Log info1577 / Last changed on Wed Dec 15 14:46:53 2004 by Xavier Spriet (xavier-at-wuug-org)


23.9.1578 Is there a way to grab the keyboard from X (like XGrabKey())?

XGrabKey grabs the input so that no other application (including the window manager) can get any keystrokes or insert them with XSendEvent. This is sometimes done for entering passwords or so to make it more difficult to sniff the keystrokes or manipulate them. In PyGTK, you can use something like:

 gdk_win = window.window
 gdk_win.keyboard_grab(1, 0) # owner_events and time, respectively
                             # XXX: is this the way?
In gtk+'s gdk.c you can see keyboard_grab() calls XGrabKeyboard. 'man XGrabKeyboard' is your friend in understanding if this does what you want.

Russ Nelson originally asked this, and Markus Schaber offered this tip.

Edit this entry1579 / Log info1580 / Last changed on Sat Jun 4 10:30:18 2005 by Johan Dahlin (johan-at-gnome-org)


23.10.1581 When wrapping a widget into a new Python extension, I get undefined symbols on importing it!

Ha shao reported the following comment to a problem reported on the mailing list when wrapping GtkSourceView:

 I import gtksourceview, kablam, here is what I get:

  /usr/lib/python2.2/site-packages/gtksourceviewmodule.so: 
     undefined symbol: gtk_source_buffer_get_tag_end
To fix this, make sure you include the header file which has gtk_source_buffer_get_tag_end defined and make sure that you link against the library in which the missing symbol is defined, in this case libgtksourceview.

Edit this entry1582 / Log info1583 / Last changed on Sat Apr 10 18:04:41 2004 by Johan Dahlin (johan-at-gnome-org)


23.11.1584 Does VTK support PyGTK?

VTK, the Visualization Toolkit [public.kitware.com]1585 is an open source 3D visualization system. If you download the VTK distribution and look in Wrapping/Python/vtk/gtk/ you'll see a class GtkVTKRenderWindow that contains a demo in the __main__ section at the bottom. A more verbose description is available at [www.daa.com.au]1586

Edit this entry1587 / Log info1588 / Last changed on Sun May 15 18:21:03 2005 by Christian Reis (kiko-at-async-com-br)


23.12.1589 How do I create a GdkRectangle?

GTK+ defines a simple graphical type called GdkRectangle, which is described in more detail at [developer.gnome.org]1590

Instead of providing the widget as a Python class, PyGTK allows one to use a tuple wherever a GdkRectangle is expected. You can simply pass in a sequence of 4 integers of the form (x, y,width, height), and it will be interpreted as a rectangle.

Edit this entry1591 / Log info1592 / Last changed on Tue May 25 12:36:18 2004 by Johan Dahlin (johan-at-gnome-org)


23.13.1593 When I create a gnome Druid, the first and last page are blank.

Rob Brown-Bayliss:

The first and last pages need to have their show() method called, I just did this:

 wtree = glade.XML("glade_file.glade")
 start_page = wtree.get_widget("start_page")
 start_page.show()
 finish_page = wtree.get_widget("finish_page")
 finish_page.show()
I am not sure why these two pages need the show() method call and the other pages in the druid dont?

Edit this entry1594 / Log info1595 / Last changed on Sat Jun 4 10:32:47 2005 by Johan Dahlin (johan-at-gnome-org)


23.14.1596 I disable text or graphics on my GtkToolbar, or the time in my GnomeDateTime, and they still show up, or, why is show_all() considered harmful?

Certain composite widgets (in other words, widgets formed by composing other widgets together in a container) which provide functionality for disabling parts of their display implement this using a simple hide() call on their subwidgets.

If you use show_all() to display them (either calling show_all() on them or on one of their parent containers) then the subwidget that was originally hidden will be shown again.

Moral of the story: avoid using show_all() when possible; it may produce unexpected results.

Edit this entry1597 / Log info1598 / Last changed on Mon Sep 29 11:33:47 2003 by Christian Reis (kiko-at-async-com-br)


23.15.1599 I'm writing a C extension that uses PyGTK. How do I acess a PyGTK object's C counterparts and vice-versa?

Tim Evans provides a simple example based on a skeleton C extension.

  #include <pygobject.h>           
  #include <pygtk.h>    
  /* global variable declared at top of file */
  static PyTypeObject *PyGObject_Type=NULL;    
  /* ... */                                
  void initfoo(void)
  {                 
      PyObject *module;
      Py_InitModule("foo", foo_functions);

      init_pygobject();
      init_pygtk();
      module = PyImport_ImportModule("gobject");
      if (module) {
          PyGObject_Type =
           (PyTypeObject*)PyObject_GetAttrString(module, "GObject");
          Py_DECREF(module);
      }
  }    

  pygobject_new((GObject*) widget);             
  /* If a python wrapper for 'widget' already exists, it will
    incref and return that, otherwise it will create a new
    python wrapper object. */
  was passed as an argument, do something like this:

  PyGObject *py_widget;                         
  GtkWidget *widget;   

  if (!PyArg_ParseTuple(args, "O!", PyGObject_Type, &py_widget))
      return NULL;
  widget = GTK_WIDGET(py_widget->obj);
You might also want to look at the 'codegen' stuff that pygtk uses to automatically generate most of the pygtk interface. Once you get used to using it, it's much easier to use than writing everything by hand.

Edit this entry1600 / Log info1601 / Last changed on Thu Feb 19 12:53:29 2004 by Christian Reis (kiko-at-async-com-br)


23.16.1602 How do I change the font and colour of some GnomePrint text?

To change font, try calling

  gnomeprint.font_find_closest_from_weight_slant(family(string),
                                                 weight(enum), 
                                                 italic(gboolean), 
                                                 size(float))
For the weight enumeration, there are FONT_* constants defined in the gnomeprint module. Try help(gnomeprint). An example is available at [cvs.gnome.org]1603

You can't change the color of a gnomeprint.Font. You should change the color of your gnomeprint.Context instead, with

  gnomeprint.Context.setrgbcolor(r,g,b).  
r/g/b are floating point values in the range 0.0 - 1.0

Edit this entry1604 / Log info1605 / Last changed on Tue Dec 16 00:27:16 2003 by Christian Reis (kiko-at-async-com-br)


23.17.1606 Is there a way to query for the current screen size?

Yes. Use gtk.gdk.screen_width() and gtk.gdk.screen_height() for the current screen width and height, respectively.

Edit this entry1607 / Log info1608 / Last changed on Mon Mar 8 18:17:10 2004 by Christian Reis (kiko-at-async-com-br)


23.18.1609 When dragging and dropping, Netscape/Firefox/etc and gedit/native gtk apps don't behave the same. Why?

Each application indicates what drag context targets it supports. It appears that Firefox and Netscape specify MIME text context targets:

 text/_moz_htmlcontext
 text/_moz_htmlinfo
 text/html
 text/unicode
 text/plain
while gedit offers text context targets:

 GTK_TEXT_BUFFER_CONTENTS
 UTF8_STRING
 COMPOUND_TEXT
 TEXT
 STRING
To handle both you need to enable them in your drag destination. For a TreeView, for instance, you might do:

 tree.enable_model_drag_dest([('text/plain',0,0),
                              ('TEXT', 0, 1),
                              ('STRING', 0, 2),
                              ('COMPOUND_TEXT', 0, 3),
                              ('UTF8_STRING', 0, 4)],
                               gtk.gdk.ACTION_DEFAULT |
                               gtk.gdk.ACTION_COPY |
                               gtk.gdk.ACTION_MOVE)
To find out what drag targets a certain selection supports, you can use this short script:

 def gettargets(wid, context, x, y, time):
   for t in context.targets:
       print t
   return True

 w = gtk.Window()
 w.set_size_request(100, 100)
 w.drag_dest_set(0, [], 0)
 w.connect('drag_motion', gettargets)
 w.show_all()

 gtk.main()
(John Finlay)

Edit this entry1610 / Log info1611 / Last changed on Mon Jun 14 16:50:47 2004 by Christian Reis (kiko-at-async-com-br)


23.19.1612 What do you see as the flaws in the Minimalist Programme?

Transformational grammar is cognitively implausible and syntactocentric. I prefer multi-stratal versions of generative unification models.

(Joe Geldart)

Edit this entry1613 / Log info1614 / Last changed on Tue Jul 13 18:28:00 2004 by Christian Robottom Reis (kiko-at-async-com-br)


23.20.1615 How do I update a progress bar and do some work at the same time

You have created a progress bar inside a window, then you start running a loop that does some work:

    while work_left:
        ...do something...
        progressbar.set_fraction(...)
You will notice that the window doesn't even show up, or if it does the progress bar stays frozen until the end of the task. The explanation is simple: gtk is event driven, and you are stealing control away from the gtk main loop, thus preventing it from processing normal GUI update events.

The simplest solution consists on temporarily giving control back to gtk every time the progress is changed:

    while work_left:
        ...do something...
        progressbar.set_fraction(...)
        while gtk.events_pending():
            gtk.main_iteration()
Notice that with this solution, the user cannot quit the application (gtk.main_quit would not work because of new loop [gtk.main_iteration()]) until your heavy_work is done.

Another solution consists on using gtk idle functions, which are called by the gtk main loop whenever it has nothing to do. Therefore, gtk is in control, and the idle function has to do a bit of work. It should return True if there's more work to be done, otherwise False.

The best solution (it has no drawbacks) was pointed out by James Henstridge. It is taking advantage of python's generators as idle functions, to make python automatically preserve the state for us. It goes like this:

    def my_task(data):
        ...some work...
        while heavy_work_needed:
            ...do heavy work here...
            progress_label.set_text(data) # here we update parts of UI
            # there's more work, return True
            yield True
        # no more work, return False
        yield False

   def on_start_my_task_button_click(data):
        task = my_task()
        gobject.idle_add(task.next, data)
The 'while' above is just an example. The only rules are that it should yield True after doing a bit of work and there's more work to do, and it must yield False when the task is done.

More on generators:

Generators are objects that are defined as functions, and when called produce iterators that return values defined by the body of the function, specifically yield statements.

The neat thing about generators are not the iterators themselves but the fact that a function's state is completely frozen and restored between one call to the iterator's next() and the following one. This is just the right thing we need to turn our functions into pseudo-threads, without actually incurring the wrath of the gods of software. More: [www.gnome.org]1616

Edit this entry1617 / Log info1618 / Last changed on Thu Jun 22 09:44:37 2006 by Johan Dahlin (johan-at-gnome-org)


23.21.1619 How can I package my gnome-python application using autotools?

I recently packaged a GNOME application written in Python with the autotools, which I chose over distutils purely as a learning exercise. If you fancy giving autotools a go you may find it to be a useful example (including glade, GConf, scrollkeeper, .desktop file and pixmap installation):

[bandsaw.sourceforge.net]1620

I found the GNOME Blog autotools files provided a good starting point.

The one thing I didn't find online was up to date information on setting up autogen.sh for use with GNOME. I was targetting GNOME 2.6 and ended up following largely out of date documentation. The correct approach is to checkout the latest version of gnome-common from the GNOME CVS server (don't use the 2.4.0 version that is packaged with many distributions; it is far too old to provide the right tools) and modify an existing autogen.sh to suit your needs. Band Saw's should be fine (for GNOME 2.6 at least).

Edit this entry1621 / Log info1622 / Last changed on Thu Sep 9 19:54:51 2004 by Graham Ashton (ashtong-at-users-sourceforge-net)


23.22.1623 How can I extend PyGTK using gtkmm/C++ ?

If you want to extend pygtk with gtkmm that means C++. Almost everything is equivalent to the C-stuff (refer to FAQ 23.151624), except:

   int argc = 0;
   char **argv = NULL;
   Gtk::Main kit(argc, argv)
This way the important internals of gtkmm are initialized. Although it may seem that just calling the static function Gtk::Main::init_gtkmm_internals() would be sufficient it is NOT.

   public PyObject* get_pyobject()
   {
     return pygobject_new((GObject*)gobj());
   }

   hbox = gtk.HBox()
   widget = MyCustomWidget()
   widget.thisown = 0
   hbox.pack_start(widget.get_pyobject())
That's it. Don't forget the 'thisown=0' if you don't want to end up with an segmentation fault because if you'd forget then Python would delete the object as soon as your function ended (thus also leaving the function's namescope).

In case you still want to have Python delete the object at the end you have the option to instantiate it using the global or object's self namescope. Normally this shouldn't be necessary because gtk takes care of the widgets memory management.

Edit this entry1625 / Log info1626 / Last changed on Mon Dec 6 06:42:01 2004 by Alexander Lehmann (lehmanna-at-in-tum-de)


23.23.1627 How do I debug a PyGTK application without an interactive session?

If you need to debug an application but are unable to obtain an interactive session to trace it from (for instance, if it crashes at startup or shutdown), you can use the following recipe, contributed by Gustavo Carneiro:

1. Install Xnest;

2. Add a test user to your system;

3. Run a nested window GDM session (in System Tools);

4. Login as the test user;

5. In your own user session:

6. In the test user nested session, trigger the error.

7. View the python backtrace in your shell, or trigger an interrupt in gdb to capture a stack trace.

Edit this entry1628 / Log info1629 / Last changed on Tue Mar 22 04:21:45 2005 by Christian Reis (kiko-at-async-com-br)


23.24.1630 Can GTK know the mouse position outside of GTK Application?

To get the position relative to a given window

  gdkwindow.get_pointer() 
If you need the absolute position, call get_pointer on the root window of the current screen:

  rootwin = widget.get_screen().get_root_window()
  x, y, mods = rootwin.get_pointer()
If you call get_pointer() on some other GdkWindow, the result will be relative to the position of that window (so you can get negative coordinates)

(James Henstridge)

Edit this entry1631 / Log info1632 / Last changed on Tue Apr 19 16:06:43 2005 by Christian Reis (kiko-at-async-com-br)


23.25.1633 Is widget.set_property('visible', False) the same as widget.hide() ?

Yes it is.

set_property('visible', True) is also the same as widget.show()

Edit this entry1634 / Log info1635 / Last changed on Tue May 3 13:12:03 2005 by Nikos Kouremenos (kourem-at-gmail-com)


23.26.1636 How do I change window properties involving atom values?

Whereas in C you would have to take the address of the integer containing the atom as property value, in PyGTK is simpler; you just have to pass the atom itself inside a sequence.

An example follows:

 desktop_type = gtk.gdk.atom_intern("_NET_WM_WINDOW_TYPE_DESKTOP", False)
 win = gtk.Window()
 win.show()
 win.realize()
 win.window.property_change(gtk.gdk.atom_intern("_NET_WM_WINDOW_TYPE", False),
                            gtk.gdk.atom_intern("ATOM", False), 32,
                            gtk.gdk.PROP_MODE_REPLACE,
                            [desktop_type])
Note: don't try to use struct.pack("I", atom)!

(Gustavo Carneiro)

Edit this entry1637 / Log info1638 / Last changed on Mon May 9 19:09:49 2005 by Christian Reis (kiko-at-async-com-br)


23.27.1639 How do I port a GObject/Glib based C application to PyGTK?

Initialization

  gtk_init(&argc, &argv);
...becomes

  import gtk
Constructors:

  GtkWidget *button;
  button = gtk_button_new();
...becomes

  button = gtk.Button()
Methods are similar:

  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(button));
...becomes

  window.add(button)
Signals:

  g_signal_connect(G_OBJECT(button), "clicked",
                   G_CALLBACK(button_clicked_cb), NULL);
...becomes

  object.connect("clicked", button_clicked_cb)
Other considerations:

Edit this entry1640 / Log info1641 / Last changed on Mon Jun 6 14:55:07 2005 by Christian Reis (kiko-at-async-com-br)


23.28.1642 How can I distribute gtkspell, trayicon (eg. modules that do not depend on gnome) so my application will take advantage of those but the user won't have to install gnome-python-extras?

You must get the source files and distribute those with your program. You can use this Makefile:

	# Set the C flags to include the GTK+ and Python libraries
	PYTHONVER = `python -c 'import sys; print sys.version[:3]'`
	CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -fPIC -I/usr/include/python$(PYTHONVER) -I.
	LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0`

	all: trayicon.so gtkspell.so

	# Build the shared objects
	trayicon.so: trayicon.o eggtrayicon.o trayiconmodule.o
		$(CC) $(LDFLAGS) -shared $^ -o $@

	gtkspell.so:
		$(CC) $(CFLAGS) $(LDFLAGS) `pkg-config --libs --cflags gtkspell-2.0` -shared gtkspellmodule.c $^ -o $@

	# The path to the GTK+ python types
	DEFS=`pkg-config --variable=defsdir pygtk-2.0`

	# Generate the C wrapper from the defs and our override file
	trayicon.c: trayicon.defs trayicon.override
		pygtk-codegen-2.0 --prefix trayicon \
		--register $(DEFS)/gdk-types.defs \
		--register $(DEFS)/gtk-types.defs \
		--override trayicon.override \
		trayicon.defs > $@

	# A rule to clean the generated files
	clean:
		rm -f trayicon.so *.o trayicon.c gtkspell.so *~  

	.PHONY: clean

Edit this entry1643 / Log info1644 / Last changed on Fri Jun 17 09:26:27 2005 by Nikos Kouremenos (kourem-at-gmail-com)


23.29.1645 How do I configure emacs to be used with pygtk?

People seem to be using python mode, abbrevs, and perhaps dynamic-completion-mode.

To turn on Abbrev mode, type:

  M-x abbrev-mode
To save the abbrevs you have currently defined to a file, type:
  M-x write-abbrev-file [RET] ~/.pygtk-abbrevs [RET]
Later, in a new session you can read the abbrevs from the file typing:
  M-x read-abbrev-file [RET] ~/.pygtk-abbrevs [RET]
Does anybody have a nice list of pygtk abbrevs, to be used in a ~/.abbrevs_defs as .pygtk-abbrevs instead of having some buffers open with pygtk code?

This abbrevs keybinding configuration seems to be quite useful too for some people:

  ;; code completion
  (global-set-key (quote [S-iso-lefttab]) (quote dabbrev-expand))
  (global-set-key (quote [S-tab]) (quote dabbrev-expand))
  (global-set-key (quote [f9]) (quote dabbrev-completion))

Edit this entry1646 / Log info1647 / Last changed on Wed Jun 22 09:38:39 2005 by pachi (pachi-at-mmn-arquitectos-com)


23.30.1648 Q_() is not available in my pygtk app. How to use Qualified translatable strings?

glib 's gstrfuncs.c

has:

 G_CONST_RETURN gchar *
 g_strip_context  (const gchar *msgid, 
		  const gchar *msgval)
 {
  if (msgval == msgid)
    {
      const char *c = strchr (msgid, '|');
      if (c != NULL)
	return c + 1;
    }

  return msgval;
 }
which is defined as #define Q_(String) g_strip_context ((String), gettext (String))

now this is done in python this way (apart from the | check which I did not implement):

 def Q_(s):
   s = _(s)
   if s[0] == '?':
       s = s[s.find(':')+1:] # remove ?abc: part
   return s
Now some theory..

in your code you do:

 menu.name = Q_('?vcard:Unknown')
 special.name = Q_('?os:Unknown') 
so pot will have:

 #: vcard.py:123 
 msgid "?vcard:Unknown" 
 msgstr "" 

 #: vcard.py:126
 msgid "?os:Unknown" 
 msgstr ""
translators get the idea how to translate Unknown and then can either do their translation either by including the ?zzz: part or without

this helps them so then now the context but moreover the know that gender (masculine, feminine, neutral)

thanks to piman, nkour

Edit this entry1649 / Log info1650 / Last changed on Fri Aug 12 15:39:43 2005 by Nikos Kouremenos (kourem-at-gmail-com)


23.31.1651 How to get the path to the file(s)/folder(s) that was dropped (by drag 'n' drop) in my application? [using selection.data]

You connect like that:
 widget.connect('drag_data_received', on_drag_data_received)
and in your callback you do:

 def on_drag_data_received(widget, context, x, y, selection, target_type, timestamp):
	uri = selection.data.strip()
	uri_splitted = uri.split() # we may have more than one file dropped
	for uri in uri_splitted:
		path = get_file_path_from_dnd_dropped_uri(uri)
		if os.path.isfile(path): # is it file?
			data = file(path).read()
			print data

 def get_file_path_from_dnd_dropped_uri(uri):
	path = urllib.url2pathname(uri) # escape special chars
	path = path.strip('\r\n\x00') # remove \r\n and NULL

	# get the path to file
	if path.startswith('file:\\\\\\'): # windows
		path = path[8:] # 8 is len('file:///')
	elif path.startswith('file://'): # nautilus, rox
		path = path[7:] # 7 is len('file://')
	elif path.startswith('file:'): # xffm
		path = path[5:] # 5 is len('file:')
	return path
Real life example:

 import gtk
 import urllib
 import os

 TARGET_TYPE_URI_LIST = 80
 dnd_list = [ ( 'text/uri-list', 0, TARGET_TYPE_URI_LIST ) ]

 def get_file_path_from_dnd_dropped_uri(uri):
	path = urllib.url2pathname(uri) # escape special chars
	path = path.strip('\r\n\x00') # remove \r\n and NULL

	# get the path to file
	if path.startswith('file:\\\\\\'): # windows
		path = path[8:] # 8 is len('file:///')
	elif path.startswith('file://'): # nautilus, rox
		path = path[7:] # 7 is len('file://')
	elif path.startswith('file:'): # xffm
		path = path[5:] # 5 is len('file:')
	return path

 def on_drag_data_received(widget, context, x, y, selection, target_type, timestamp):
	if target_type == TARGET_TYPE_URI_LIST:
		uri = selection.data.strip()
		print 'uri', uri
		uri_splitted = uri.split() # we may have more than one file dropped
		for uri in uri_splitted:
			path = get_file_path_from_dnd_dropped_uri(uri)
			print 'path to open', path
			if os.path.isfile(path): # is it file?
				data = file(path).read()
				#print data

 w = gtk.Window()
 w.connect('drag_data_received', on_drag_data_received)
 w.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
			gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP,
				dnd_list, gtk.gdk.ACTION_COPY)

 w.show_all()
 gtk.main()

Edit this entry1652 / Log info1653 / Last changed on Wed Aug 17 13:51:39 2005 by Nikos Kouremenos (kourem-at-gmail-com)


23.32.1654 How to get coordinates relative to X11 for a widget that has no window of it's own?

Try this code:

 # here I get the coordinates of the button relative to
 # window (self.window)
 button_x, button_y = self.actions_button.allocation.x, self.actions_button.allocation.y

 # now convert them to X11-relative
 window_x, window_y = self.window.window.get_origin()
 x = window_x + button_x
 y = window_y + button_y
now x, y hold the top-left corner of button and those x, y are X11 and not window-relative.

Something more advanced but hopefully useful:

 menu.popup(None, None, self.position_actions_menu, 1, 0)
 menu.show_all()

 def position_actions_menu(self, menu):
	# here I get the coordinates of the button relative to
	# window (self.window)
	button_x, button_y = self.actions_button.allocation.x, self.actions_button.allocation.y

	# now convert them to X11-relative
	window_x, window_y = self.window.window.get_origin()
	x = window_x + button_x
	y = window_y + button_y

	# now move the menu below the button
	y += self.actions_button.allocation.height

	push_in = True # push_in is True so all menu is always inside screen
	return (x, y, push_in)

Edit this entry1655 / Log info1656 / Last changed on Tue Sep 20 15:29:35 2005 by Nikos Kouremenos (kourem-at-gmail-com)


23.34.1657 How can I use gtk.binding_entry_add (and why it's better than keypress in most cases)

If in your program you have a textview and you catch keypress signal and do checks on what key is pressed then you application will break some more advanced Input Methods such as [im-ja.sourceforge.net]1658 .

It's because normal signals like 'key_press_event' are first catched by your application and then by the IM/GTK (and they are catched only if you do not return True). So you have to use bindings which are superior in most cases (NOTE: Bindings on a combination will never call your Callback if for the same combination a GTK default action exists). Those bindings need a signal-name, so you have to subclass so you can add those bindings only for that class:

	import gtk
	import gobject

	class MyTextView(gtk.TextView):
	    __gsignals__ = dict(
	        mykeypress = (gobject.SIGNAL_RUN_LAST | gobject.SIGNAL_ACTION,
	                  None, # return value
	                  (str,)) # arguments
	        )
	if gobject.pygtk_version < (2, 8):
	    gobject.type_register(MyTextView)

	gtk.binding_entry_add_signal(MyTextView, gtk.keysyms.Return, 0, 'mykeypress', str, 'return')
	gtk.binding_entry_add_signal(MyTextView, gtk.keysyms.Home, gtk.gdk.CONTROL_MASK, 'mykeypress', str, 'ctrl+home')

	def activate_cb(tv, what):
	    print 'You pressed', what

	tv = MyTextView()
	tv.connect('mykeypress', activate_cb)
	w = gtk.Window()
	w.add(tv)
	w.set_default_size(400, 300)
	w.show_all()
	w.connect('destroy', lambda w: gtk.main_quit())
	gtk.main()

Thanks to Gustavo and Muntyan

Edit this entry1659 / Log info1660 / Last changed on Thu Nov 3 16:11:24 2005 by Nikos Kouremenos (kourem-at-gmail-com)


23.35.1661 How can you set the tab / tabbing order?

Use: gtk.Container.set_focus_chain

Note: you can set the order, for direct children.

An example is here: [calmar.ws]1662

once the tab/tabbing order reaches the focus of the table2 (packed into the main table), the tab-chain of table2's children is active.

Edit this entry1663 / Log info1664 / Last changed on Tue Feb 14 12:07:04 2006 by calmar (mac-at-calmar-ws)


23.36.1665 How do I acquire a screenshot of the whole screen?

Use the GDK Pixbuf API. Although it will only output to PNG and JPEG, the latter having an optional quality option passed as a dict with a quality value string of 0-100 to the gdk.Pixbuf save() method.

 # Either "png" or "jpeg"
 format = "jpeg"

 width = gtk.gdk.screen_width()
 height = gtk.gdk.screen_height()
 screenshot = gtk.gdk.Pixbuf.get_from_drawable(
              gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height),
              gtk.gdk.get_default_root_window(),
              gtk.gdk.colormap_get_system(),
              0, 0, 0, 0, width, height)

 # Pixbuf's have a save method 
 # Note that png doesnt support the quality argument. 
 screenshot.save("screenshot." + format, format,  {"quality": "20"})
Warning: if you plan on running this code on a loop, or many times throughout the program, you might want to add the following code to avoid a big memory leak (considering the size of a bitmap of those proportions), as per a bug detailed here: [www.async.com.br]1666

 del screenshot
 gc.collect()

Edit this entry1667 / Log info1668 / Last changed on Sat Apr 22 01:08:54 2006 by Marc (m4rccd-at-yahoo-com)


23.37.1669 How do I create a throbber like the one in Firefox?

Easy, steal it from Firefox! Download the Firefox source and find the files Throbber.png and Throbber.gif (or do a Google Images search). Throbber.png is the static icon and Throbber.gif is the animated icon. Pack a gtk.Image with the static icon next to your menubar:

 hbox = gtk.HBox(expand=False)
 hbox.pack_start(menubar)
 self.throbber = gtk.Image()
 self.throbber.set_from_file('image_path/Throbber.png')
 hbox.pack_start(self.throbber, expand=False)
and create the animation:

 self.animation = gtk.gdk.PixbufAnimation('image_path/Throbber.gif')
Then all we need to do to get the throbber throbbing is load this animation into the Image:

 pixbuf = self.throbber.get_pixbuf() # save the Image contents so we can set it back later
 self.throbber.set_from_animation(self.animation)
 ...
 # then later to stop the animation just put the old contents back
 self.throbber.set_from_pixbuf(pixbuf)
Here's an example of using the throbber to show activity while we do some hard work in a thread:

 gobject.threads_init() # called somewhere at the top of your file

 def someActionCallback(self, *args):
     pixbuf = self.throbber.get_pixbuf()
     self.throbber.set_from_animation(self.animation)
     # make sure the throbbing starts now
     while gtk.events_pending():
         gtk.main_iteration()
     def call():
         try:
             # hard working code goes here
         finally: # make sure the throbbing stops whatever else happens
             gobject.idle_add(self.throbber.set_from_pixbuf, pixbuf)
     # start the hard work in a thread
     threading.Thread(target=call).start()
(See section 20 of this FAQ for more on using threads in PyGtk.)

Edit this entry1670 / Log info1671 / Last changed on Sun May 28 08:30:50 2006 by Daverz (dave-at-davidcook-org)


23.38.1672 How can I access data returned with a gpointer?

In some cases, for example in a callback function, you may get data as a gpointer instead of a python data type, making such data unreacheable from your python program. Although the gpointer data type provides no way of accesing the underlying pointer, there is a hack to do it using the gpointer's conversion to string and reach the data using the ctypes module.

Have a look at the following example, using the gtkmozembed widget. This function is the callback for the 'open_uri' widget signal. The second argument 'uri' should be a string, but all you'll get is a gpointer. The gpointer is converted to string to get the pointer value in [13:-1] characters as an hex number, which may be converted to an integer. Using ctypes this integer is typecasted to a pointer to c style string (c_char_p), which is converted to a python string by the value method.

 def mozilla_open_uri(widget, uri, *args):
     p=int(str(uri)[13:-1],16)
     url=ctypes.cast(p,ctypes.c_char_p).value
     print(url)
     return False

Edit this entry1673 / Log info1674 / Last changed on Tue May 30 18:16:02 2006 by Miguel Angel Alvarez (maacruz-at-gmail-com)


24. Deprecated List Widgets: GtkList, GtkCList, GtkCTree and others


24.1.1675 My GtkCList rows represent instances, but how can I keep track of them?

Often you have a CList where you represent instances, but since the CList itself is only an array of text cells, you might think that you need to do your own bookkeeping of them (having a mapping row -> instance, for example.) But GTK+ already does that for us:

Each row in a CList can have a data object attached to it by using the set_row_data() method. This method takes an object reference and attaches it to a row. Any object reference can be attached:

 class Foo: 
   pass
 f = Foo()
 clist = GtkCList(cols=2)
 row = clist.append(["foobar","noogie"])
 clist.set_row_data(row, f) # attaches a reference to f to row
To retrieve the reference to the instance you have attached, simply use:

 instance = clist.get_row_data(row)
To find a row that has this object attached to it, see question 13.8.

Edit this entry1676 / Log info1677 / Last changed on Sun Aug 25 08:52:19 2002 by Christian Reis (kiko-at-async-com-br)


24.2.1678 Why doesn't GtkCList's children() method return the lists rows?

If you try to

  c = gtk.GtkCList()
  c.append(["foo"])
  print c.children()
You will notice it returns an empty list. James says:

  the children() call is to return child _widgets_.  The rows of the clist 
  are not children of the CList.
See question 2.5 for a way to access CList rows.

Edit this entry1679 / Log info1680 / Last changed on Tue Jan 22 13:27:59 2002 by kiko (kiko-at-async-com-br)


24.3.1681 How do I access data that is in a GtkCList?

Once you have stuffed data into a GtkCList, using something like:

  c = gtk.GtkCList(cols=2)
  c.append(["foo","bar"])
  c.append(["snark","boojum"])
The data is rendered into the list. To retrieve the data, you can use something like:

  >>> c.get_text(0,0)
  'foo'
  >>> c.get_text(0,1)
  'bar'
To retrieve all data into a list structure, use a loop like:

  ret = []
  for row in range(0, c.rows):
    tmp = []
    for col in range(0, c.cols):
      tmp.append(c.get_text(row,col))
    ret.append(tmp)
Don't forget the data object (see 2.2) attached to rows if you want an exact snapshot of the list.

Edit this entry1682 / Log info1683 / Last changed on Tue Jan 22 13:40:21 2002 by kiko (kiko-at-async-com-br)


24.4.1684 How do I order the contents of a GtkCList according to the type of data in the columns (or, where is gtk_clist_set_compare_func)?

The gtk function gtk_clist_set_compare_func() is not currently mapped into pygtk. There are, however, solutions you can implement in python.

 # pop_all_rows removes and returns a list of rows, each of these being 
 # a list of columns. e.g. for a clist with 2 rows and 2 columns, it  ]
 # would produce: [ [ 'foo', 'bar' ] , [ 'baz', 'noogie'] ] 
 # See the Kiwi source code for an implementation.
 rows = clist.pop_all_rows()
 # use other funcs for other types
 func = int
 rows.sort( lambda x, y, column=column, func=func:    
            cmp(func(x[column]), func(y[column]) )
 clist.freeze()
 for r in rows:
   clist.append(r)
 clist.thaw()

 values = [3,4,5,1,49,456,342,345]

 # turn off column 1's visibility, so that only column 0 shows
 clist.set_column_visibility(1,0)

 # set the sort column to column 1
 clist.set_sort_column(1)

 # add the values, converting the integer to a string, and creating
 # a 8 character string that is left padded with zeros. This turns '1'
 # into '00000001' and 49345 into '00049345', allowing ascii to sort
 # by numerical value.

 for value in values:
   clist.append([str(value),"%08d" % value])

 clist.sort()

Edit this entry1686 / Log info1687 / Last changed on Sat Jul 13 13:15:42 2002 by Christian Reis (kiko-at-async-com-br)


24.5.1688 How do I get the data out of a GtkCTree?

Getting the information out of a CTree is very similar to getting the information out of a CList. Instead of CList.get_text() method with a row number, you use the CTree.node_get_text() method with the GtkCTreeNode representing the node in the tree:
  >>> ctree = gtk.GtkCTree(2, 0)
  >>> node = ctree.insert_node(None, None, ['foo', 'bar'])
  ...
  >>> ctree.node_get_text(node, 1)
  'bar'
Note that you can't get the text in the tree column this way, as it isn't a standard text cell. However, you can get information about the tree column with the ctree.get_node_info() method:
  >>> ctree.get_node_info(node)
  ('foo', 5, None, None, None, None, 1, 0)

Edit this entry1689 / Log info1690 / Last changed on Tue Jan 29 12:21:04 2002 by James Henstridge (james-at-daa-com-au)


24.6.1691 How would I recurse through all nodes in a GtkCTree?

If you wish to recurse through all nodes in a ctree, you can use code like the following:

  >>> def recurse(node):
  ...     # do something with node
  ...     for child_node in node.children:
  ...         recurse(child_node)
  ... 
  >>> for node in ctree.base_nodes():
  ...     recurse(node)
  ...
The above code should be easily be modified for your purposes.

Edit this entry1692 / Log info1693 / Last changed on Sat Jun 15 16:13:47 2002 by Christian Reis (kiko-at-async-com-br)


24.7.1694 How do I capture a right-click or double-click event on a GtkCList row?

faq 5.41695 explains the basic mechanics of capturing button presses on widgets. In our case, we attach a handler to the clist's button_press_event and verify the event button and type.

However, for right-clicks, the row you right-click on may not have been previously selected. This means the row will have to be selected first, and then right-clicked, which is bad usability (left-click then right-click). To avoid this, you can use something like this to select the row automatically on right-click:

 def button_clicked(list, event):
  # Check for right click
  if event.button == 3:
   sel=list.get_selection_info(event.x,event.y)
   list.select_row(sel[0], sel[1])
   print "Click."
   print list.selection
Let me guess, you want to pop up a menu? See faq 11.21696.

Note that if you are trying to spawn a new window when double-clicking, *if that window is modal* your application may get stuck in a pointer-focus bug. I don't know of a good workaround beyond making the window non-modal (and then changing using idle_add to make it modal again -- it sucks but it works).

Edit this entry1697 / Log info1698 / Last changed on Wed Aug 6 22:17:58 2003 by Christian Reis (kiko-at-async-com-br)


24.8.1699 How do I find a row in a GtkCList that contains "X"?

You can query the list for both it's "label" (the strings in it) or the data object attached to a row. For the first case, simply use something like:

  row = clist.find_row_from_text(text)
  print "Row that contains %s: %s" % (text, row)
To find the row with a certain data object attached to it use:

  row = clist.find_row_from_data(obj)

Edit this entry1700 / Log info1701 / Last changed on Mon Feb 4 10:25:46 2002 by kiko (kiko-at-async-com-br)


24.9.1702 When entering data dynamically into my GtkCList or tree, it flickers like mad!

If you are filling many rows into a GtkCList as part of a loop, each row insertion will force GTK+ to redraw the widget, causing flickering. To avoid this, you should wrap the insertion loop/call with call to the list's freeze() and thaw() methods:

 c = gtk.GtkCList
 # ...
 c.freeze() # avoid flickering
 for f in ...:
  c.insert_row(row_data)
 c.thaw()
If you really want flicker free operation, use pygtk 2; the new tree/list widget is much more powerful, and flickers a lot less.

Edit this entry1703 / Log info1704 / Last changed on Thu Jun 6 15:20:14 2002 by Christian Reis (kiko-at-async-com-br)


24.10.1705 How do I align a GtkCList's columns?

By default, a CList's columns will be left-aligned. Use the clist function set_column_justification for each column, passing in the appropriate GTK constants. Example:

 c = gtk.GtkCList(cols=2)
 c.set_column_justification(0, GTK.JUSTIFY_RIGHT)
 c.set_column_justification(1, GTK.JUSTIFY_CENTER)
Possible values for justification include:

 GTK.JUSTIFY_LEFT
 GTK.JUSTIFY_RIGHT
 GTK.JUSTIFY_CENTER

Edit this entry1706 / Log info1707 / Last changed on Thu Aug 22 16:24:59 2002 by Christian Reis (kiko-at-async-com-br)


24.11.1708 How do I remove a row from a CList?

Use the clist's remove function, which takes a row as argument:

 clist.remove(2) # remove row 2

Edit this entry1709 / Log info1710 / Last changed on Thu Aug 22 16:43:34 2002 by Christian Reis (kiko-at-async-com-br)


24.12.1711 How do I find out which row(s) are selected in the GtkCList?

The GtkCList has an (often-ignored) attribute called selection. It contains a list of selected rows. When the list mode is SINGLE or BROWSE, it will contain only one element:

 row = clist.selection[0]
 print "Row %d is selected" % row
If the mode is MULTIPLE or EXTENDED, the list will contain as many items as there are rows selected:

 for row in clist.selection:
   print "Row %d is selected" % row

Edit this entry1712 / Log info1713 / Last changed on Sun Aug 25 09:06:56 2002 by Christian Reis (kiko-at-async-com-br)


24.13.1714 How do I colour the background of a GtkCList row?

The GtkCList function set_background() can be used to colour a row. The trick here is getting the colour to set. pygtk-0 has a bug in which GdkColor SEGVs when being instantiated; however, the correct way to do it relies on the GtkWidget's get_colormap() method, which returns a GdkColormap. This instance provides a method to allocate a new color:

 map = clist.get_colormap()
 color = map.alloc("red")
 clist.set_background(row,color)
Note that you can pass both names ("red") and hex triplets (0xffff, 0x0000, 0x0000) to alloc():

 map = clist.get_colormap()
 color = map.alloc(0xffff, 0x0000, 0x0000)
 clist.set_background(row,color)

Edit this entry1715 / Log info1716 / Last changed on Sun Aug 25 10:06:56 2002 by Christian Reis (kiko-at-async-com-br)


24.14.1717 How do I find out what the current selection mode in the GtkCList is?

Easy (but undiscoverable):

 print clist['selection_mode']
will return the selection mode integer (which will correspond to one of SELECTION_SINGLE, SELECTION_BROWSE, SELECTION_MULTIPLE and SELECTION_EXTENDED).

Edit this entry1718 / Log info1719 / Last changed on Tue Oct 8 22:26:35 2002 by Christian Reis (kiko-at-async-com-br)


24.15.1720 How do I change the style of the white space between CList rows?

That'ss the `base' attribute of the CList's style object. See FAQ 4.51721 for information on how to change it.

Edit this entry1722 / Log info1723 / Last changed on Wed Aug 13 21:18:06 2003 by Christian Reis (kiko-at-async-com-br)

Search FAQ1724 What's new1725 FAQ index1726 Whole FAQ1727 Roulette1728 Add entry1729

PyGTK FAQ Wizard1730 | PyGTK Homepage1731 | Feedback to faq at pygtk.org