GTK is the Gnome desktop graphics library first developed for Gimp, the GNU Image Manipulation Program. The GTK libraries were packaged into a Python GUI library known as PyGTK. These libraries closely resemble the capabilities of the GTK "C" libraries.
Alternative GUI development libraries exist for Python including those based on VW_windows, Qt and the Tk tool kit.
Python and PyGTK are typically native packages on Linux and are easily installed on MS/Windows as MSI installations.
Linux: (example RHEL6/CentOS 6)- python (native package: 2.6.5)
- pygtk2 (native package: 2.16.0)
- python2.7 (native package: 2.7.1)
- python-gtk2 (native package: 2.22.0)
- python2.5 (native package: 2.5.2)
- python-gtk2 (native package: 2.13.0)
- python: http://www.python.org/download/
msi install: http://python.org/ftp/python/2.7.3/python-2.7.3.msi
(Be sure to add C:\Python27\ folder to the PATH to pick up python.exe) - PyGTK: http://www.pygtk.org/downloads.html 32 bit all in one installer
http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.22/pygtk-all-in-one-2.22.6.win32-py2.7.msi
All pyGTK layouts are organized in a tree structure with the root of the tree being the main display window.
GUI Window:
gtk.Window(type=gtk.WINDOW_TOPLEVEL)Options:
- set_title(title)
- set_position(position)
- set_focus(focus)
- set_default(default_widget)
- set_resizable(resizable)
- ...
#!/usr/bin/env python import pygtk pygtk.require('2.0') import gtk class MyProgram: def __init__(self): # create a new window app_window = gtk.Window(gtk.WINDOW_TOPLEVEL) app_window.set_size_request(500, 350) app_window.set_border_width(10) app_window.set_title("MyProgram title") app_window.connect("delete_event", lambda w,e: gtk.main_quit()) # Program goes here ... app_window.show() return def main(): gtk.main() return 0 if __name__ == "__main__": MyProgram() main()
GUI Layout:
In order to layout graphics, display test, display text entry boxes and other GUI widgets one can use a network of horizontal or vertical layout widgets. If laying out widgets in two dimensions one can use a table of horizontal and vertical rows and collumns.- Horizontal boxes
gtk.HBox(homogeneous=False, spacing=0)- homogeneous: True = equal space allocations for al child objects.
- spacing: The additional horizontal space between child objects in pixels
- Vertical Boxes
gtk.VBox(homogeneous=False, spacing=0)- homogeneous: True = equal space allocations for al child objects.
- spacing: The additional vertical space between child objects in pixels
- Table
gtk.Table(rows=4, columns=3, homogeneous=False)- homogeneous: True = equal space allocations for al child objects.
- rows: number of rows
- columns: number of columns
- resize(rows, columns)
- set_row_spacing(row, spacing)
- set_column_spacing(column, spacing)
- attach(child, left_attach, right_attach, top_attach, bottom_attach, xoptions=gtk.EXPAND|gtk.FILL, yoptions=gtk.EXPAND|gtk.FILL, xpadding=0, ypadding=0)
- ...
The following uses HBox(), VBox() and Table() to layout text and button widgets in the display window:
#!/usr/bin/env python import pygtk pygtk.require('2.0') import gtk class MyProgram: def __init__(self): # create a new window app_window = gtk.Window(gtk.WINDOW_TOPLEVEL) app_window.set_size_request(500, 350) app_window.set_border_width(10) app_window.set_title("MyProgram title") app_window.connect("delete_event", lambda w,e: gtk.main_quit()) vbox_app = gtk.VBox(False, 0) app_window.add(vbox_app) vbox_app.show() label_app = gtk.Label("Application name: ") label_app.show() vbox_app.pack_start(label_app, False, False, 6) # Draw Table() to layout text: table_layout = gtk.Table(rows=2, columns=2, homogeneous=True) label_a = gtk.Label("AAA") label_a.show() table_layout.attach(label_a, 0, 1, 0, 1, 0,0,0,0) label_b = gtk.Label("BBB") label_b.show() table_layout.attach(label_b, 0, 1, 1, 2, 0,0,0,0) label_c = gtk.Label("CCC") label_c.show() table_layout.attach(label_c, 1, 2, 0, 1, 0,0,0,0) label_d = gtk.Label("DDD") label_d.show() table_layout.attach(label_d, 1, 2, 1, 2, 0,0,0,0) table_layout.show() vbox_app.add(table_layout) # Use HBox() to layout text and button next to each other: hbox_close = gtk.HBox(False, 0) label_close = gtk.Label("Close aplication: ") hbox_close.pack_start(label_close, True, True, 0) label_close.show() button_close = gtk.Button(stock=gtk.STOCK_CLOSE) button_close.connect("clicked", lambda w: gtk.main_quit()) button_close.set_flags(gtk.CAN_DEFAULT) hbox_close.pack_start(button_close, True, True, 0) button_close.show() hbox_close.show() vbox_app.add(hbox_close) # Place after association to hbox/vbox to avoid the following error: # GtkWarning: gtkwidget.c:5460: widget not within a GtkWindow button_close.grab_default() app_window.show() return def main(): gtk.main() return 0 if __name__ == "__main__": MyProgram() main()
Button widgets provide a mechanism to provide functionality for the user action of selecting the button. Thus the programmer must provide a Python callback function to be executed when the button is pressed.
gtk.Button(label=None, stock=None, use_underline=True)
Options:
- set_label(label)
- set_relief(newstyle)
- set_alignment(xalign, yalign)
- set_image(image)
- set_image_position(position)
- ...
... ... hbox_buttons = gtk.HBox(False, 0) button_a = gtk.Button("Execute process A") button_a_data = (arg_1, arg_2, arg_3, arg_4) button_a.connect("clicked", self.button_a_callback, button_a_data) button_a.set_flags(gtk.CAN_DEFAULT) hbox_buttons.pack_start(button_a, True, True, 0) button_a.show() ... ...
Callback function to execute if button is pressed:
def button_a_callback(self, widget, data_a): # function arguments first_fn_arg = data_a[0] second_fn_arg = data_a[1] third_fn_arg = data_a[2] fourth_fn_arg = data_a[3] # process data ... ... return
Text entry widgets require a callback function to manage and receive the text.
In this example we have a callback (callback enter_callback_b()) defined by the programmer when the widget is defined and the callback assigned to the widget by the call to the "connect" function call: entry_b.connect("changed", self.enter_callback_b, entry_b).
Note that the callback is called initially when the default text is assigned and every time the text entry is changed.
In this example we also added a label to display the intent of the text entry box to the user. A default entry is also assigned.
The variable entry_text_b can be passed to the location in the code where it is to be used but also can be assigned to a global variable.
gtk.Entry(gtk.Widget, gtk.Editable, gtk.CellEditable)gtk.Entry(max=0)
Options:
- set_has_frame(setting)
- set_max_length(max) : max string length alowed to be enetered. Set to "0" for upper limit (65536).
- set_width_chars(n_chars) : width of the text entry box
- set_text(text) : Set the default text entry
- set_alignment(xalign)
- set_overwrite_mode(overwrite)
- ...
#!/usr/bin/env python import pygtk pygtk.require('2.0') import gtk class TextEntry: def enter_callback_b(self, widget, entry_b): entry_text_b = entry_b.get_text() print "Text entry: %s\n" % entry_text_b return # Main program to draw GUI def __init__(self): # create a new window app_window = gtk.Window(gtk.WINDOW_TOPLEVEL) app_window.set_size_request(500, 100) app_window.set_border_width(10) app_window.set_title("My program title") app_window.connect("delete_event", lambda w,e: gtk.main_quit()) # Set default text in text entry box entry_checker_default_b = "abc def default text" # Text label hbox_b = gtk.HBox(False, 0) app_window.add(hbox_b) # attach HBox to window label_b = gtk.Label("Enter text: ") label_b.show() hbox_b.pack_start(label_b, False, False, 0) # Generate text entry box entry_b = gtk.Entry() entry_b.set_max_length(80) entry_b.set_width_chars(50) entry_b.connect("changed", self.enter_callback_b, entry_b) entry_b.set_text(entry_checker_default_b) entry_b.select_region(0, len(entry_b.get_text())) entry_b.show() hbox_b.pack_start(entry_b, False, False, 0) hbox_b.show() app_window.show() return def main(): gtk.main() return 0 if __name__ == "__main__": TextEntry() main()
The check box/button is a typical GTK widget which requires a callback function which is assigned to the widget. In this example we use a frame widget to generate a visual frame to encapsulate the displayed widget. In addition we used a global variable to pass the variable around to potential functions which could use the variable.
gtk.CheckButton(label=None, use_underline=True)- label : String to be used as a text label
- use_underline : True=underscore in the text label indicates "alt" accelerator key
#!/usr/bin/env python import pygtk pygtk.require('2.0') import gtk # Global variables b_entry_checkbox = True class Checkbox: def entry_checkbox(self, widget, checkbox): global b_entry_checkbox b_entry_checkbox = checkbox.get_active() if b_entry_checkbox: print "Box checked" else: print "Not checked" return # Main program to draw GUI def __init__(self): global b_entry_checkbox # create a new window app_window = gtk.Window(gtk.WINDOW_TOPLEVEL) app_window.set_size_request(500, 100) app_window.set_border_width(10) app_window.set_title("My program title") app_window.connect("delete_event", lambda w,e: gtk.main_quit()) frame_checkbox = gtk.Frame("Check for true:") frame_checkbox.set_shadow_type(gtk.SHADOW_IN) app_window.add(frame_checkbox) check_box = gtk.CheckButton("Checkbox text string") check_box.connect("toggled", self.entry_checkbox, check_box) check_box.set_active(True) # Set the defaut check_box.show() frame_checkbox.add(check_box) frame_checkbox.show() app_window.show() return def main(): gtk.main() return 0 if __name__ == "__main__": Checkbox() main()
Combo boxes allow for a selection of assigned options. Like all other widgets, it must be assigned to a layout widget to be displayed.
gtk.ComboBox(model=None)gtk.combo_box_new_text()
Options:
- set_entry_text_column(text_column)
- set_wrap_width(width)
- set_active(index)
- append_text(text)
- ...
... ... global g_combo_selected ... ... combo_box = gtk.combo_box_new_text() combo_box.append_text("Choose option:") combo_box.append_text("option-a") combo_box.append_text("option-b") combo_box.append_text("option-c") combo_box.append_text("option-d") combo_box.connect('changed', self.combo_select_callback) combo_box.set_active(0) # set the default option to be shown combo_box.show() ... ...
Combo box callback:
def combo_select_callback(self, widget): global g_combo_selected model = widget.get_model() index = widget.get_active() if index: print 'Option selected: ', model[index][0] g_combo_selected = model[index][0] if g_checker_selected == "Choose option:": print "Error! Choose an option" return
Other combo box types include:
- gtk.Combo
- gtk.ComboBoxEntry
- gtk.ComboBoxText
The dialog box presents a pop-up message box to inform the application user.
gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_NONE, message_format=None)- flags : gtk.DIALOG_MODAL, gtk.DIALOG_DESTROY_WITH_PARENT or 0 for no flags. Can be combined.
- type: The pyGTK libraries provides default message box symbology for the following purposes:
- Error message: gtk.MESSAGE_ERROR
- Warning message: gtk.MESSAGE_WARNING
- Information message: gtk.MESSAGE_INFO
- Question message: gtk.MESSAGE_QUESTION
- buttons:
- gtk.BUTTONS_NONE
- gtk.BUTTONS_OK
- gtk.BUTTONS_CLOSE
- gtk.BUTTONS_CANCEL
- gtk.BUTTONS_YES_NO
- gtk.BUTTONS_OK_CANCEL
- message format: string containing the message text or None
- set_markup(str)
- set_image(image)
- ...
Information message dialog:
# Print dialog box to inform user message_for_user = "Check sign of value entered" md = gtk.MessageDialog(app_window, gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, message_for_user) md.run() md.destroy()
Note that the variable "md" is not attached to a layout widget or any other entity in the application. It is not required to "show()" the widget either. It stands alone and can be placed anywhere in the code as a mechanism to present a message to the user.
gtk.MESSAGE_ERROR | gtk.MESSAGE_WARNING | gtk.MESSAGE_INFO |
The following code snippet shows how to embed and display an X Pixmap image (XPM) within a Python pyGTK script. Any bitmap image (gif, jpeg, etc) can be converted to an "xpm" file using image manipulation software such as XV or Gimp and performing a "Save as ...".
XPM is a "C" text string representation of a color bit mapped image. Graphic software conversion typically prepares the XPM in this mode to be embedded into "C" programs. Only minor changes are required to use the XPM image in a Python/pyGTK script. It must be changed from a "C" char to a Python string.
The original native XPM image file:static char * YoLinux_logo_xpm[] = { "186 176 4613 2", " c None", ". c #000000", "+ c #161616", "@ c #121212", "# c #010101", "$ c #0C0C0C", "% c #060606", "& c #070707", .. ... " . L@M@S@T@U@V@W@X@Y@Z@`@ #.#+#@###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#^#/#(#_#:#:#<#[#}#. ", " |#1#2#8#9#0#a#b#c#d#: e#f#g#h#i#. . j#k#l#m#n#o#p#q#r#. s#t#u#v#w#x#y#z#,.A#B#C#D#E#% ", " F#G#H#I#N#a 1+, O#>+P#Q#R#S#T#U#V#W#X#Y#Z#`# $.$+$@$#$$$%$&$*$=$-$;$>$,$'$)$!$~${$]$^$/$ ", " P#O ,*'*)*!*H&~*{*9 ]*,%^*/*(*_*:*<*[*}*|*1*2*3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*i* ", " . . . $ p*,*q*'*r*W@D$s*t*u*v*w*x*y*z*A*B*C*D*E*F*|*G*H*I*1*J*K*L*M*N*O*P*Q*R*Q*S*T*U* ", ... ... " "};
Convert native XPM "C" string to a Python string:
YoLinux_logo_xpm [ "186 176 4613 2", " c None", ". c #000000", "+ c #161616", "@ c #121212", "# c #010101", "$ c #0C0C0C", "% c #060606", "& c #070707", .. ... " . L@M@S@T@U@V@W@X@Y@Z@`@ #.#+#@###$#%#*#=#-#;#>#,#'#)#!#~#{#]#^#/#(#_#:#:#<#[#}#. ", " |#1#2#8#9#0#a#b#c#d#: e#f#g#h#i#. . j#k#l#m#n#o#p#q#r#. s#t#u#v#w#x#y#z#,.A#B#C#D#E#% ", " F#G#H#I#N#a 1+, O#>+P#Q#R#S#T#U#V#W#X#Y#Z#`# $.$+$@$#$$$%$&$*$=$-$;$>$,$'$)$!$~${$]$^$/$ ", " P#O ,*'*)*!*H&~*{*9 ]*,%^*/*(*_*:*<*[*}*|*1*2*3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*i* ", " . . . $ p*,*q*'*r*W@D$s*t*u*v*w*x*y*z*A*B*C*D*E*F*|*G*H*I*1*J*K*L*M*N*O*P*Q*R*Q*S*T*U* ", ... ... " "]
Code to display XPM:
... ... # Convert XPM image (list of strings) to GTK pixbuf logo_pixbuf = gtk.gdk.pixbuf_new_from_xpm_data(YoLinux_logo_xpm) logo = gtk.Image() # convert pixbuf to GTK image logo.set_from_pixbuf(logo_pixbuf) logo.show() ... ...
- Lots of other pyGTK widgets are avaialable including:
- progress bar: gtk.ProgressBar()
(Progress defined as 0 to 1. Widget also displays text messages.) - About pop-up: gtk.AboutDialog()
- Arrow: gtk.Arrow()
- Date selection: gtk.Calendar()
- Cells: gtk.CellEditable(), gtk.CellLayout(), gtk.CellRenderer(), ...
- Clipboard: gtk.Clipboard()
- Menus: gtk.Menu(), gtk.MenuBar(), gtk.MenuItem(), gtk.MenuShell(), ...
- ...
- progress bar: gtk.ProgressBar()
- Programatically one can change the display of widgets:
- Turn off: widget_name.hide()
- Turn on: widget_name.show()
- Log files are helpful:
import os import sys import time import datetime def f_abc(): # Open log file logFile = open("AppLog.txt","w") now = datetime.datetime.now() current_time= now.strftime("%Y-%m-%d %H:%M") logFile.write("Application run: " + current_time+"\n") ... ... logFile.write(str_a + "\n") ... ... logFile.write("Run complete!\n") logFile.close() return
- PyGTK is cross platform. Keep your Python program cross platform as well:
import os ... ... if os.name == "posix": command_purge = "rm -Rf /tmp" + os.sep + intermediate_dir elif os.name == "nt": command_purge = "DEL /Q C:" + os.sep + intermediate_dir ... ...
Links: