Graphical Python Programming With PyGTK
Making a Window

Akkana Peck
Thursday, May 14, 2009 12:05:16 PM
Whitespaces and formatting are meaningful in Python, so the code is posted both inline in this article, and on a separate page which is linked at the bottom.
To draw on a GTK drawing area, you need something called its
drawable. Use widget.window to get that.
Drawables let you get lots of useful properties, like the width and
height of the area you're drawing in, widget.window.get_size.
Other Stories on LinuxPlanet
|
Drawing in nearly all Linux toolkits requires something called a
graphics context. That's an object which stores details about
how you want to draw, like foreground and background colors, line
width, line style and so forth. widget.window.new_gc()
creates one. I've named mine xgc so it won't be confused with
Python's garbage collector, which also uses the abbreviation gc.
Colors in PyGTK are a little tricky. You have to create a
gtk.gdk.Color object and pass it to the graphics context's
set_rgb_fg_color() function. You can use named colors with
gtk.gdk.color_parse(), or you can define them by their red, green and
blue values, like this for red: gtk.gdk.Color(65535, 0, 0).
Then you're ready to draw. PyGTK has lots of drawing functions to
draw points, lines, rectangles, arcs, polygons and so on, but
in the example above, I just draw a red line from the upper left corner
(0, 0) to the lower right (w, h), to get Figure 3.

That's progress ... but it's boring. How about adding some circles and
ovals? PyGTK uses a rather complicated function for that, so let's
break it down:
drawable.draw_arc(gc, filled, x, y, width, height, angle1, angle2)
where gc is the graphics context, filled is whether you
want an outline (False) or a filled-in shape (True).
x and y are the coordinates of an imaginary box
containing your oval, while width and height are the
size of that box. Finally angle1 and angle2 are how
much of the circle you want to draw, starting at the 3-o-clock
position and proceeding counter-clockwise around the circle.
Here's the tricky part: the units for angle1 and angle2
are 1/64ths of a degree. So if you want a full circle, use 0 for
angle1 and 360*64 for angle2. If you want an arc that goes from the
45° point to 180°, you'd use angle1 = 45*64 and
angle2 = 180*64 (Figure 4).

I know it sounds a bit complicated, so here's a sample of
how it works in practice:
xgc.set_rgb_fg_color(gtk.gdk.color_parse("yellow"))
widget.window.draw_arc(xgc, True, 200, 100, 200, 200, 0, 360*64)
xgc.set_rgb_fg_color(gtk.gdk.Color(0, 0, 0)) # black
widget.window.draw_arc(xgc, True, 240, 145, 30, 40, 0, 360*64)
widget.window.draw_arc(xgc, True, 330, 145, 30, 40, 0, 360*64)
xgc.line_width = 6
widget.window.draw_arc(xgc, False, 240, 150, 120, 110, 200*64, 140*64)
Try it and see what it does! (Figure 5.)

In the next article I'll show how to put this all together to make
applications that look pretty, or useful, or both. But for now,
you can find out more about PyGTK at the
PyGTK website,
where they have a very good reference manual as well as
tutorials and other information.
In particular, the reference page on
drawables
will tell you about all the different drawing methods you can use.
Here's the final program:
#!/usr/bin/env python
import gtk, random
# This function will be called whenever you click on the button:
def click_handler(widget) :
# quit the application:
gtk.main_quit()
# This function will be called whenever the drawing area is exposed:
def expose_handler(widget, event) :
w, h = widget.window.get_size()
xgc = widget.window.new_gc()
xgc.set_rgb_fg_color(gtk.gdk.color_parse("yellow"))
widget.window.draw_arc(xgc, True, 200, 100, 200, 200, 0, 360*64)
xgc.set_rgb_fg_color(gtk.gdk.Color(0, 0, 0)) # black
widget.window.draw_arc(xgc, True, 240, 145, 30, 40, 0, 360*64)
widget.window.draw_arc(xgc, True, 330, 145, 30, 40, 0, 360*64)
xgc.line_width = 6
widget.window.draw_arc(xgc, False, 240, 150, 120, 110, 200*64, 140*64)
# Create the main window:
win = gtk.Window()
# Organize widgets in a vertical box:
vbox = gtk.VBox()
win.add(vbox)
# Create an area to draw in:
drawing_area = gtk.DrawingArea()
drawing_area.set_size_request(600, 400)
vbox.pack_start(drawing_area)
drawing_area.connect("expose-event", expose_handler)
drawing_area.show()
# Make a pushbutton:
button = gtk.Button("Quit")
# When it's clicked, call our handler:
button.connect("clicked", click_handler)
# Add it to the window:
vbox.pack_start(button)
button.show()
# Obey the window manager quit signal:
win.connect("destroy", gtk.main_quit)
vbox.show()
win.show()
gtk.main()
Click here to see the whole program Next: The Code »