lgs is currently certified at Master level.

Name: Lorenzo Gil Sanchez
Member since: 2003-06-18 10:49:10
Last Login: 2010-08-25 19:21:46

FOAF RDF Share This

Homepage: http://www.lorenzogil.com


Recent blog entries by lgs

Syndication: RSS 2.0
Grid widget (again)

After a long time without talking about this, one of my favourite subjects, it's time to revisit this topic. The problem is GTK+ does not provide a widget for grids like the ones in GNUCash or (ehem) Microsoft Access. This kind of widgets are pretty useful when all the rows has the same format (e.g., every column has a type and other attributes) and the user needs to edit the data *fast*. Note that a Sheet, like the widget used in Gnumeric or other spreadsheet programs, does not have that property: one column can have different data types in different rows.

Are you sure GTK+ does not have that widget? What about the powerfull GtkTreeView? Yeah, you are right. The GtkTreeView is a damn cool widget with the features we are looking for:

  • Every row has the same format
  • You can edit the cells

Not to talk about the tons of other nice features the GtkTreeView also have (MVC architecture, sortable, filterable, column orderable, flexible renderers, ...). My only problem about the GtkTreeView was that the editing of the cell was not fast enough. With a standard configuration of a GtkTreeView the user needs to go to a cell, press enter to put it on editable mode, edit the cell and press enter again. Too much keystrokes == no fast editable.

Well, that was in the old pre 2.6 days. Now there is a way to make the TreeView fast when talking about editing. It is called 'start-editing' signal on the renderers. In 2.4 the problem was that once you start editing a cell you didn't have access to the widget used as the cell editor (usually a GtkEntry) so you couldn't connect a key-press-event handler to see what key the user pressed to go to the next cell. This is exactly the problem 'start-editing' solves in 2.6. Actually it is useful for many other cases.

I even started my own GtkGrid project to work around this problem in 2.4 which I don't regret at all even when now it is not necessary anymore. I learned a lot of things doing this:

  • How to write a widget from scracth in C
  • How to write Python bindings for such a widget
  • How to read more than 30.000 lines of code (GtkTreeView and friend classes) and not to die

Now for the lessons learned:

  • When you need a feature in GTK+ first ask *very politely* to the maintainers if it can be done. Note the difference between 'it can be done' and 'will you do it?'. I don't think I was unpolited in the above story, the problem was I just assumed that they will do it if it was a good idea. Now I know, there are too many good ideas in bugzilla.gnome.org that don't get done just as a matter of (lack of) resources.
  • If they say yes go to the code and try to write a patch for that. No matter how hard it seems to be. Writing something from scratch is almost always harder. Having a patch will give your request much more chances to be implemented. Be prepared to modify your patch as many times as the maintainers told you until they seem happy with it.
  • If they say no, don't give up, go to the code and see if there are some ideas the maintainers didn't considered and talk with them about those in a GTK+ meeting
  • Even then, maybe the feature you are requesting does not have its way in GTK+. Maybe this is the time to write something from scratch, but please, try the other steps first.

As Johan said, it seemed I had a problem with communication with this grid issue. I could have written a patch to add this 'start-editing' signal to GtkCellRenderer and showing its utility it may have been accepted. The problem was I didn't know enough about GTK+ internals to do this. Then when writing my widget I got this knowledge and that was when I should have written the patch. But it's too hard to throw away your code and do the right thing in this situation. Btw, I hate the fact that Johan is almost always right :-)

I have a demo of this concept that work pretty good but also has a couple of hacks. Let me know if you want to take a look at it.

5 Mar 2005 (updated 5 Mar 2005 at 17:58 UTC) »

Yesterday I finished the version of a Gazpacho small plugin and I was about to create a svn project in the central repository for that. I just have an XML file, a PNG image and a Python file. Well, I also have the compiled Python file (*.pyc)

As you may know, we don't want pyc or any other form of auto generated files in the repository. So, before importing my code I removed the pyc file.

Oops, Murphy used the fact that it was 8 o'clock in the night and I was pretty tired, to made me erase the actual .py file instead of the .pyc file. Magically, 238 lines of code dissapeared in front of me as I didn't have any other copy of that file. Now is where the laughs come up.

Fortunately I had heard of python decompilers so I started looking on the net and then asked Johan. The program I was looking was decompyle. apt-get install decompyle and see what happens.

It didn't work because the decompyle program of this Debian (Ubuntu) installation was too old and didn't know how to handle python 2.3 bytecode format.

So, back to the net and look for the last version. Wooho, I found it and it says it can handle 2.3 format. So, where is the freaking download button? Nowhere, this has gone commercial and you have to pay to get your files back :-(

Well, this is the free software world. Somebody writes a good software, people like it, people use it and he/she try to get some money from his work. Totally legal and right stuff.

Back to Johan, he told me there is a fork on this software to keep it free (as in beer). God blesses forks (and free software to allow them). But this time it was no easy to find it, since all the google links points towards the commercial page. Finally I found it here: http://mirrors.wamug.org.au/ubuntu/pool/universe/d/decompyle/

This time it works properly and I got my file back :-)

The day of the living exception

Thanks to Gustavo I just discovered this really nice Python recipe: Automatically start the debugger on an exception

2 Mar 2005 (updated 2 Mar 2005 at 19:57 UTC) »
Problems with gtype

Until recently the way Gazpacho instantiates widgets was using their python class. For example, for a GtkWindow I had the <type 'gtk.Window'> class, that is what you usually get when typing:

import gtk; print gtk.Window

The problem was when loading a .glade file. Then when you have to instantiate a widget you don't usually know the module where this widget has the class in. For example, let's see this (fake) glade file:

<?xml version="1.0" ?>
    <widget class="GtkWindow" id="window1">

Now, how do I get the gtk.Window class from the 'GtkWindow' name. Well, if we just work with gtk+ widgets it's easy. All I have to do is to strip the 'Gtk' prefix from the name, and look for 'Window' in the gtk module.

Ok, that's cheating, and certainly doesn't work as soon as you start working with other modules, like kiwi.

So I tried another approach: getting the gtype from the class name and building the widgets with gobject.new:

>>> gobject.type_from_name('GtkWindow')
<GType GtkWindow (136052312)>
>>> gobject.new(_)
<gtk.Window object (GtkWindow) at 0xb72e22ac>

Looks like this works perfectly but actually, it doesn't. The problem now is that when you create your widgets in pure python (as kiwi does) you __init__ method is not called anymore when using gobject.new(). Seems like a bug but it is not, since this is the expected behaviour. Even when it's the behaviour I don't want at all.

Sooo, back to the classes. Let's sumarize: I don't have an easy way to get the class object from the class name and I can't use gobject.new to construct the object. So let's get the class object from the gtype. That's the best solution and it would also be great if pygtk would support this :-(

Here is my workaround function that I hope I can remove as soon as this bug is fixed:

def class_from_gtype(gtype, module_list):
  for module in module_list:
    for name, klass in inspect.getmembers(module, inspect.isclass):
      if gtype == getattr(klass, '__gtype__', None):
        return klass

Note how easy is to get the gtype from a python class: it's on the '__gtype__' attribute.

Update: new version of class_from_gtype function thansk to Johan:

def class_from_gtype(gtype, module_list):
    def is_gobject_subclass(k):
        return isinstance(k, type) and issubclass(k, gobject.GObject)
    for module in module_list:
        for klass in filter(is_gobject_subclass,
                            [getattr(module, n) for n in dir(module)]):
            if gtype == klass.__gtype__:
                return klass
23 Feb 2005 (updated 23 Feb 2005 at 22:15 UTC) »
libglade lessons

Today Mikael explained me why using libglade for loading .glade files in Gazpacho is a bad idea.

Basically we don't want to add stuff to libglade that it is specific for a GUI builder like i18n information or other things like that.

We shouldn't depend on libglade adding this kind of stuff because it is not designed for that. It just ignores this kind of information because applications don't care about it.

Having said that it doesn't mean libglade should not accept some other changes to accept new GTK+ features. IMHO libglade is starting to show its age (7 years) and it's been a while since it has not added a GTK+ feature.

31 Jan 2005 (updated 31 Jan 2005 at 12:09 UTC) »
Improving my Python skils

After reading PythonIs Not Java, a great article by the way, I realized that when I write Python code I do some things just because I have a big inertia from other languages and from what some teachers teached me and don't really think in a Python way. Here are two things I should change:

  • Don't write setters or getters until you really need to do so because they involve more logic that just setting or getting an attribute. When the time comes to do so, you have the great property() builtin to allow you to do the changes without modifying any client code

  • Write functions than return functions so a lot of code can be reused. The inner function is a template for your common problem and the outer function is just used to give some parameters to the inner one

I specially like this sentence of the article:

Essentially, if you've been using Java for a while and are new to Python, do not trust your instincts. Your instincts are tuned to Java, not Python. Take a step back, and above all, stop writing so much code.

Thanks to Phillip J. Eby for this clear explanation

27 older entries...


lgs certified others as follows:

  • lgs certified rms as Master
  • lgs certified lgs as Apprentice
  • lgs certified alvaro as Master
  • lgs certified arauzo as Apprentice
  • lgs certified arturogf as Journeyer
  • lgs certified jdahlin as Master

Others have certified lgs as follows:

  • lgs certified lgs as Apprentice
  • malcolm certified lgs as Apprentice
  • arauzo certified lgs as Master
  • Uraeus certified lgs as Apprentice
  • alejandro certified lgs as Journeyer
  • coffelius certified lgs as Master
  • arturogf certified lgs as Journeyer
  • salmoni certified lgs as Journeyer
  • carlosgc certified lgs as Journeyer
  • lerdsuwa certified lgs as Apprentice
  • alvaro certified lgs as Journeyer
  • jdahlin certified lgs as Master
  • fxn certified lgs as Journeyer
  • olea certified lgs as Journeyer
  • kov certified lgs as Master
  • pvanhoof certified lgs as Journeyer
  • gpoo certified lgs as Master
  • pcburns certified lgs as Journeyer
  • henrique certified lgs as Master

[ Certification disabled because you're not logged in. ]

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!

Share this page