Tag/tag.png

Content Cleanup Required
This article should be cleaned-up to follow the content standards in the Wiki Guide. More info...

Tag/tag.png

Style Cleanup Required
This article does not follow the style standards in the Wiki Guide. More info...

Tag/tag.png

Needs Expansion
This article is incomplete, and needs to be expanded. More info...

Purpose

This wiki page explains how to import an application's user interface that was made with Glade into Python in order to make a UME/Hildon application. In particular, it covers:

  • How to import a Glade user interface definition file into Python
  • How to access objects defined in Glade and give them local Python names
  • How to reparent Glade widgets to the required Python Hildon Window
  • How to get a GTK Menu defined in Glade and set it as the Hildon Program menu in Python

Terminology: What's "reparenting"? The top level window in a UME application is - by definition - a Hildon Window. However, Glade can only create a GTK Window, not the Hildon Window you need. (When using Glade, you need a GTK Window as a top-level widget so that you can add other child widgets to it). To deal with this mismatch, you create a real Hildon Window in your Python and then "reparent" the GTK Window's direct children to it.

Prerequisites

  • Glade
  • A UME development/build/run environment
  • Understanding of the files and directories required by a UME Desktop Python application -- see

Files and Directories for Adding a Python Application to UME

  • Basic Python knowledge

Packages

You will need the following packages installed in the UME target:

  • python-gtk2
  • python-hildon-1.2
  • python-glade2

You can install each by entering the target UME root directory (the target chroot when working from Image-Creator) and executing the usual apt-get install (package name) command.

Using Glade

This how-to assumes basic knowledge of how to use Glade. However, even if you've never used it before, rest assured that it's quite easy.

Glade is a graphical tool for creating a GTK user interface by dragging widgets onto a canvas or into other widgets (in which case they become children) and then optionally selecting widgets and modifying their properties. The result is an XML file with the .glade extension that contains a description of the user interface that can be imported into various languages, including Python. After importing the .glade file, you can access the widgets using the names you gave them in Glade and then use them programmatically.

As noted, one important point is how to deal with the fact that Glade cannot create a Hildon Window. It can only create a GTK Window, and indeed it requires one as a parent for most other widgets (but not menus). So, in Glade, you create the GTK Window and add widgets to it, then, in your Python you "reparent" the GTK Window's child widgets to your real Hildon Window. To minimize reparenting, this example program's root window has only one child, a GTK VBox widget, which in turn contains child widgets. So, this VBox must be reparented from the GTK Window to a Hildon Window.

Let's take a look at these steps in a little more detail, but first let's review the Python program's basic structure.

This Python program's structure

Note: Please see main.py source at the end of this page.

This is a simple Python program.

Among the usual imports at the top is: import gtk.glade, which is required to import the .glade file.

The program has one class, GladeTestApp, whose constructor creates the Hildon Program and Hildon Window, imports the .glade file, assigns Glade objects local names, reparents a widget, sets the Hildon program menu from a Glade-defined menu, sets up signal handlers for user events, and other things.

The class is instantiated as an object named app, and it's run() method is executed.

Let's start by examining how the constructor creates the Hildon Program and Hildon Window.

Creating the Hildon Program and Hildon Window

Here's the top of the GladeTestApp class, showing the beginning of its constructor.

class GladeTestApp():
    """pygtk-glade-hildon demo project"""

    def __init__(self):

        #make the hildon program
        self.program = hildon.Program()
        self.program.__init__()
        
        #make the hildon window and add to program
        self.window = hildon.Window()
        self.window.set_title("PyGlade")
        self.program.add_window(self.window

As you can see, the Hildon Program is created and assigned to self.program. And, the Hildon Window is created and assigned to self.window. Pretty straightforward.

Next, we'll import the .glade file.

Importing the .glade file

The .glade file is imported inside GladeTestApp's constructor. The code looks like this:

        self.glade_file = "pygladeui.glade"
        self.wTree=gtk.glade.XML(self.glade_file)

The first line defines a variable (self.glade_file) and assigns it the file name of the .glade file, in this case pygladeui.glade.

The second line actually imports all user interface objects from the specified .glade file into a new variable named self.wTree.

Now, all the objects defined in the .glade file can be retrieved from self.wTree and can be assigned local names for programmatic use. They are retrieved using the names they were given (or assigned by default) when using Glade, as shown next.

Reparenting to Hildon Window

As noted, the GTK window made with Glade contains a GTK VBox widget that contains all other application widgets (except for the menu, discussed below). When making this VBox widget with Glade, I gave it the following name: vbox1. (The widget's name is viewed/set in Glade by selecting it and looking at its "properties" in the Properties window.)

Here's the Python code that fetches the VBox from the imported glade file:

        #reparent the vbox1 from glade to self.window
        self.vbox1 = self.wTree.get_widget("vbox1")
        self.reparent_loc(self.vbox1, self.window)

The first non-comment code line gets the specified GTK VBox and assigns it to the self.vbox1 variable.

The second reparents the VBox from the GTK window made in Glade to the Hildon Window made in Python that's named self.window with the reparent_loc() function.

That's it for reparenting! Let's take a look at importing the GTK menu made in Glade and setting it as the application's Hildon menu.

Getting the menu and making it a Hildon Menu

In Hildon, you create a GTK menu and add it to the Hildon Program with the set_common_menu(GTK.menu) function, as mentioned previously.

The following Python code shows how to get the imported the GTK menu that's named menu1, assign it to self.menuGlade, and then set the Hildon Program to use this as its common menu.

        #get menu from glade and reparent as common menu in hildon program
        self.menuGlade = self.wTree.get_widget("menu1")
        self.program.set_common_menu(self.menuGlade)  

Source

main.py

import pygtk
import gtk
import hildon
import gtk.glade

class GladeTestApp():
    """pygtk-glade-hildon demo project"""

    def __init__(self):

        #make the hildon program
        self.program = hildon.Program()
        self.program.__init__()
        
        #make the hildon window and add to program
        self.window = hildon.Window()
        self.window.set_title("PyGlade")
        self.program.add_window(self.window)
        
        #receive signal to close window from framework close button  
        if (self.window):
            self.window.connect("destroy", gtk.main_quit)
        
        #import the glade file and assign to self.wTree
        self.glade_file = "pygladeui.glade"
        self.wTree = gtk.glade.XML(self.glade_file)
        
        #reparent the vbox1 from glade to self.window
        self.vbox1 = self.wTree.get_widget("vbox1")
        self.reparent_loc(self.vbox1, self.window)
        
        #get menu from glade and reparent as common menu in hildon program
        self.menuGlade = self.wTree.get_widget("menu1")
        self.program.set_common_menu(self.menuGlade)        
        
        #get quit menu item and connect signal
        self.menuItem_quit = self.wTree.get_widget("quit1")
        self.menuItem_quit.connect("activate", gtk.main_quit)
  
        #get hbox1 in order to modify contents based on user actions
        self.hbox1 = self.wTree.get_widget("hbox1")

        #get label1 for use    
        self.label1 = self.wTree.get_widget("label1")        

        self.controlBar = hildon.Controlbar()
        self.controlBar.set_min(0) 
        self.controlBar.set_max(50) 
        self.controlBar.set_value(15) 
        self.controlBar.connect("value-changed", self.control_changed, self.label1)
        
        self.menuItem_controlBar = self.wTree.get_widget("controlBar")
        self.menuItem_controlBar.connect("activate", self.controlBar_pressed, self.hbox1, self.controlBar, self.label1)

        self.dateEditor = hildon.DateEditor() 
        self.dateEditor.set_year(2006) 
        self.dateEditor.set_month(4) 
        self.dateEditor.set_day(20)  
      
        self.menuItem_dateEditor = self.wTree.get_widget("dateEditor")
        self.menuItem_dateEditor.connect("activate", self.dateEditor_pressed, self.hbox1, self.dateEditor, self.label1)        
        
        #get button1 and connect a signal handler
        self.button1 = self.wTree.get_widget("button1")
        if (self.button1):
            self.button1.connect("pressed", self.button1_pressed, self.label1)
        
        #destroy the gtk window imported from glade
        self.gtkWindow = self.wTree.get_widget("window1")
        self.gtkWindow.destroy()
        
        #display everything
        self.window.show_all()

    def run(self):
        gtk.main()

# signal handlers
    
    def menuItem_quit1_pressed(self, widget):
        gtk.main_quit 

    def button1_pressed(self, widget, label):
        label.set_label("new label")     
    
# controlBar

    def controlBar_pressed(self, widget, hbox, controlBar, label):
        self.dechild_hbox(hbox)
        hbox.add(controlBar)
        controlBar.show()
        label.set_text("ControlBar")

    def control_changed(self, widget, label): 
        label.set_text(" %s of %s" % (widget.get_value(), widget.get_max()))

# dateEditor

    def dateEditor_pressed(self, widget, hbox, dateEditor, label):
        self.dechild_hbox(hbox)
        hbox.add(dateEditor)
        label.set_text("DateEditor")
        dateEditor.show()

#utility

    def dechild_hbox(self, hbox_widgets):
        children = hbox_widgets.get_children()
        for child in children:
            hbox_widgets.remove(child)

    def reparent_loc(self, widget, newParent):
        widget.reparent(newParent)

if __name__ == "__main__":
    app = GladeTestApp()
    app.run()

Makefile

BINDIR = ${DESTDIR}/usr/bin/
APPDIR = ${DESTDIR}/usr/share/pyglade
all: 
install:
        @mkdir -p ${BINDIR}
        @mkdir -p ${APPDIR}
        @install -m 755 -D main.py ${APPDIR}/main.py
        @install -m 755 -D pygladeui.glade ${APPDIR}/pygladeui.glade
        @install -m 755 -D executable.txt ${BINDIR}/pyglade
        @install -m 755 -D desktop.txt ${DESTDIR}/usr/share/applications/pyglade.desktop
        @install -m 755 -D pyglade_26.png ${DESTDIR}/usr/share/icons/hicolor/22x22/apps/pyglade_26.png

clean:
        @rm -f ${APPDIR}/main.py
        @rm -f ${APPDIR}/pygladeui.glade
        @rm -f ${BINDIR}/pyglade
        @rm -f ${DESTDIR}/usr/share/applications/pyglade.desktop
        @rm -f ${DESTDIR}/usr/share/icons/${THEME}/22x22/apps/pyglade_26.png

re.


CategoryProgramming

UMEGuide/ApplicationDevelopment/GladeWithPythonForUMEHildon (last edited 2009-08-14 22:29:00 by rocket2dmn)