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.)
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)
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)
:pserver:anonymous@anoncvs.gnome.org:/cvs/gnomeThe 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/pygtkPlease 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)
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)
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)
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)
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)
cd /usr/src/pygtk-0.9.9 # we wish :-) ./configure make make installFor 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)
(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)
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)
Let's call the library "foo" (how original)
1) foo.defs.
h2defs.py /usr/include/foo-1.0/*.h > foo.defs2) 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 started5) 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)
Edit this entry448 / Log info449 / Last changed on Fri Jul 16 11:01:06 2004 by Christian Robottom Reis (kiko-at-async-com-br)
Edit this entry452 / Log info453 / Last changed on Sat Dec 28 17:05:38 2002 by Christian Reis (kiko-at-async-com-br)
You should run
./autogen.sh make make installin 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/prefixAnd then, don't forget to set PYTHONPATH before running the program, eg:
export PYTHONPATH=/home/user/prefix/lib/python2.3/site-packagesThen 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)
>>> 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)
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)
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)
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/pkgconfigOr, 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)
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)
Edit this entry484 / Log info485 / Last changed on Fri Feb 25 11:30:55 2005 by Christian Reis (kiko-at-async-com-br)
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)
(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 gtkto
import gtk2 as gtkThis 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)
- 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)
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)
pygtk.require("1.2") # for pygtk-0and
pygtk.require("2.0") # for pygtk2Note 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.uior:
# To require 1.2 import pygtk pygtk.require("1.2") import gtk, libglade, gnome, gnome.uiIf 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)
- pygtk-0.6.10 - gnome-python-1.4.3 - pygtk2-1.99.13So 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)
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 etcWhich 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)
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)
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)
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)
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)
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)
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 pressesHowever, 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)
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)
<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)
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)
# # 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)
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.
Edit this entry557 / Log info558 / Last changed on Sat May 6 11:16:01 2006 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
Edit this entry591 / Log info592 / Last changed on Sat Feb 9 14:47:25 2002 by kiko (kiko-at-async-com-br)
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)
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 redThis 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 redSee 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)
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)
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)
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)
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)
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)
export GDK_USE_XFT=1It'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)
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)
Edit this entry627 / Log info628 / Last changed on Sat Oct 25 15:34:18 2003 by Christian Reis (kiko-at-async-com-br)
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)
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)
>>> 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') TrueOnce 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)
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-outIn 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)
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)
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)
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)
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_PRELIGHTbut 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)
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)
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)
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_PIXMAPAlso 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)
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)
Edit this entry675 / Log info676 / Last changed on Thu Sep 19 22:04:09 2002 by Christian Reis (kiko-at-async-com-br)
>>> win = gtk.Window() >>> win.realize() # or win.show() >>> rect = win.allocationWould return a gdk.Rectangle, which can be accessed by using:
>>> rect.width, rect.height, rect.x and rect.yor 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)
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 casewill 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)
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)
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)
(: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)
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:
Edit this entry695 / Log info696 / Last changed on Tue Nov 16 15:33:31 2004 by Johan Dahlin (johan-at-gnome-org)
>>> 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)
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)
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)
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)
gtk.gdk.SCROLL_UP, gtk.gdk.SCROLL_DOWN, gtk.gdk.SCROLL_LEFT, gtk.gdk.SCROLL_RIGHTExample:
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)
Edit this entry716 / Log info717 / Last changed on Tue Jun 29 09:54:29 2004 by Christian Reis (kiko-at-async-com-br)
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)
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)
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 retvalDon'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)
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 basesIn 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__ = GMetaFooSo, 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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 belowSpecial 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)
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)
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)
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)
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)
Edit this entry789 / Log info790 / Last changed on Mon Jun 14 16:19:01 2004 by Christian Reis (kiko-at-async-com-br)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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' failedYou 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)
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)
Edit this entry824 / Log info825 / Last changed on Thu Aug 10 11:52:51 2006 by Thomas Guettler (guettli+pygtkfaq-at-thomas-guettler-de)
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)
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)
Edit this entry833 / Log info834 / Last changed on Tue May 25 12:33:12 2004 by Johan Dahlin (johan-at-gnome-org)
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)
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)
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)
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)
>>> 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)
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)
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)
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.TRUEwhere 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)
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)
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)
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)
>>> w = gtk.GtkWindow() >>> w.set_title("foo") >>> print w['title'] fooIn 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)
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)
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)
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)
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)
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.TRUEIn 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)
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)
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)
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)
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)
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)
>>> win = gtk.Window() >>> print win.window NoneBut 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 58720259LAnd 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)
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)
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)
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)
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)
[UI_GnomeApp] Menubar_detachable=false Menus_have_tearoff=falseNone 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)
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_timeBut 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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 tooor by using the TreeView's insert_column_with_attributes() API:
gtk.TreeView.insert_column_with_attributes(position, title, renderer, property1=column1, ....)The parameters are:
For CellRendererText, the most common cell renderer, the most important properties are 'text' (indicating from which treemodel column the data should come), 'markup' (the same as text, but indicating that pango markup should be parsed from the data), and 'visible' (indicating if the column should be displayed by default or not).
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)
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)
(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)
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)
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)
# 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)
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)
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)
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)
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 iterAlternatively, 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)
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)
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)
Edit this entry1013 / Log info1014 / Last changed on Mon Sep 29 11:36:27 2003 by Christian Reis (kiko-at-async-com-br)
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 1Note 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)
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)
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)
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 nodeHere 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)
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)
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)
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)
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)
# 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)
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)
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)
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)
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)
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)
renderer = gtk.CellRendererText() renderer.set_property("foreground", "red") # ... and use renderer in TreeViewColumnTo 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)
# 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)
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)
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 TrueAnd 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)
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)
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)
(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)
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)
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)
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)
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_heightDon'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)
Edit this entry1106 / Log info1107 / Last changed on Wed May 4 07:33:15 2005 by Nikos Kouremenos (kourem-at-gmail-com)
Once a sort column ID has been set on a TreeModel implementing the TreeSortable interface it cannot be returned to the original unsorted state. You can change the sort function or use a default sort function but you cannot set the TreeModel to have no sort function.
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)
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)
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)
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().fontthen 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)
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)
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)
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)
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)
def on_insert_text(widget, text, len, *args): passThe 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)
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)
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)
# 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 seenset_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)
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)
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)
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)
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)
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)
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)
Edit this entry1172 / Log info1173 / Last changed on Sun Feb 8 17:34:22 2004 by Christian Reis (kiko-at-async-com-br)
Edit this entry1176 / Log info1177 / Last changed on Mon Jun 14 16:37:35 2004 by Christian Reis (kiko-at-async-com-br)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
LINE_SOLID LINE_ON_OFF_DASH LINE_DOUBLE_DASHSo 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)
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 TrueNotice 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)
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)
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)
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)
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)
Edit this entry1278 / Log info1279 / Last changed on Thu Jan 31 21:32:07 2002 by kiko (kiko-at-async-com-br)
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)
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)
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)
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)
Edit this entry1298 / Log info1299 / Last changed on Wed Aug 20 18:48:35 2003 by Christian Reis (kiko-at-async-com-br)
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)
Edit this entry1304 / Log info1305 / Last changed on Mon Oct 6 11:38:18 2003 by Martin Gadbois (martin-gadbois-at-colubris-com)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
I am writing a pygtk-1.2 app. I have lots of interaction with GnomeCanvas and lots of threading. For example, it is common to have a thread running which moves, creates or destroys a widget on the canvas.
In the process of doing this I encountered a number of non-deterministic, intermittent, severe crashes related to threading problems. Even after extensive locking they would not go away.
1) While moving an object from a thread GnomeUI-ERROR **: file gnome-canvas.c: line 3812 (gnome_canvas_request_redraw_uta): assertion failed: (canvas->redraw_area != NULL) aborting...
2) While creating an object from a thread Xlib: unexpected async reply (sequence 0x10b9)! (plus various other sequence numbers)
Were you making use of the gtk.threads_enter() and gtk.threads_leave() calls to protect GTK calls outside of the main thread/signal handlers?
If not, that would explain the problems you ran into. GTK is not completely thread safe, so in some cases you need to acquire the GDK thread lock. Note that you can assume the GDK thread lock is acquired within signal handlers, but it isn't within idle, timeout and IO handlers.
Try upgrading the libpthread packages on your machine.
I have had a problem with random threads crashing on pygtk 2, my app was interacting with another and all sorts of weird crap was going on, but, only some times, it might run for one minute, or 5 days, but eventually it would crash while starting a new thread. This crash would even lock gdb.
Finally used a small C prog to simulate what I was doing and still got the crashes. Turns out to be a semi known problem with the pthread library (some refs on google to same problem with oracle and pthread)
I upgraded and have gone from my app guaranteed crash once a day to crash free for 30 days, every time the crash was either init'ing a new thread or a thread communicating with the main app.
I note that the new Redhat beta for 8.1 lists as a feature a new posix threading lib.
Stay away from Redhat betas :-)
Edit this entry1357 / Log info1358 / Last changed on Wed Jan 22 23:45:47 2003 by Christian Reis (kiko-at-async-com-br)
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)
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 = True2. 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)
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 Truewill 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)
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)
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)
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!
Grab Gustavo's code from [www.daa.com.au]1380 .
Edit this entry1381 / Log info1382 / Last changed on Tue Nov 8 15:46:38 2005 by Johan Dahlin (johan-at-gnome-org)
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_READinstead 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)
Edit this entry1388 / Log info1389 / Last changed on Tue Nov 8 15:49:02 2005 by Johan Dahlin (johan-at-gnome-org)
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)
Edit this entry1394 / Log info1395 / Last changed on Thu Mar 3 23:18:45 2005 by Nikos Kouremenos (kourem-at-gmail-com)
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)
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)
Edit this entry1404 / Log info1405 / Last changed on Wed Jul 13 02:58:25 2005 by Phillip Calvin (phillipc-at-toasterlogic-com)
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)
Edit this entry1411 / Log info1412 / Last changed on Sun Apr 30 21:00:58 2006 by Christian Reis (kiko-at-async-com-br)
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)
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.gladeThe "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)
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)
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)
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)
Edit this entry1457 / Log info1458 / Last changed on Sun Jan 2 11:19:59 2005 by Gian Mario Tagliaretti (g-tagliaretti-at-parafernalia-org)
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)
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)
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)
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)
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)
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)
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)
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)
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.mo4. Thats it - now use your application!
# start without any translation LANG=de_DE python myapp.py2 Translating glade files
2.1 Extracting strings
intltool-extract --type=gettext/glade foo.gladeThis 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)
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)
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_referenceand 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)
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)
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)
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)
Edit this entry1517 / Log info1518 / Last changed on Wed Sep 17 12:30:43 2003 by Christian Reis (kiko-at-async-com-br)
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)
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)
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)
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)
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)
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)
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)
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)
[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)
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)
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)
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)
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)
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)
I import gtksourceview, kablam, here is what I get: /usr/lib/python2.2/site-packages/gtksourceviewmodule.so: undefined symbol: gtk_source_buffer_get_tag_endTo 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)
Edit this entry1587 / Log info1588 / Last changed on Sun May 15 18:21:03 2005 by Christian Reis (kiko-at-async-com-br)
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)
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)
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)
#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)
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)
Edit this entry1607 / Log info1608 / Last changed on Mon Mar 8 18:17:10 2004 by Christian Reis (kiko-at-async-com-br)
text/_moz_htmlcontext text/_moz_htmlinfo text/html text/unicode text/plainwhile gedit offers text context targets:
GTK_TEXT_BUFFER_CONTENTS UTF8_STRING COMPOUND_TEXT TEXT STRINGTo 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)
(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)
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)
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)
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)
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)
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)
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)
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)
gtk_init(&argc, &argv);...becomes
import gtkConstructors:
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)
# 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)
To turn on Abbrev mode, type:
M-x abbrev-modeTo 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)
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 sNow 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)
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 pathReal 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)
# 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_ynow 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)
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)
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)
# 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)
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)
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)
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 rowTo 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)
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)
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)
The Kiwi source code includes a complete CList mod, which adds arrows and does direct/reverse sorting. Browse the code to see what it's like. The following is a simplification of the algorithm I use in Kiwi to do this:
# 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()
This prevents the need to remove and re-add all the data. To sort again,just call the .sort() method of the clist, or turn on autosorting with clist.set_auto_sort(1)
This approach is used in GRAMPS (a genealogy program: [gramps.sourceforge.net]1685 ), and the sorts are quite fast, even for clists with 1000s of entries.
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)
>>> 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)
>>> 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)
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.selectionLet 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)
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)
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)
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)
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)
row = clist.selection[0] print "Row %d is selected" % rowIf 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)
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)
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)
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