12.2. Drawing Methods

There are a general set of methods that can be used to draw onto the drawing area 'canvas'. These drawing methods can be used for any gtk.gdk.Drawable subclass (either a gtk.gdk.Window or a gtk.gdk.Pixmap). The drawing methods are:

  drawable.draw_point(gc, x, y)

gc is the Graphics Context to be used to do the drawing.

x and y are the coordinates of the point.

  drawable.draw_line(gc, x1, y1, x2, y2)

gc is the Graphics Context.

x1 and y1 specify the starting point of the line. x2 and y2 specify the ending point of the line.

  drawable.draw_rectangle(gc, filled, x, y, width, height)

where gc is the Graphics Context.

filled is a boolean indicating the rectangle should be filled with the foreground color if TRUE or not filled, if FALSE.

x and y are the top left corner of the rectangle.

width and height are the width and height of the rectangle.

  drawable.draw_arc(gc, filled, x, y, width, height, angle1, angle2)

gc is the Graphics Context.

filled is a boolean indicating the arc should be filled with the foreground color if TRUE or not filled, if FALSE.

x and y are the top left corner of the bounding rectangle. width and height are the width and height of the bounding rectangle.

angle1 is the start angle of the arc, relative to the 3 o'clock position, counter-clockwise, in 1/64ths of a degree.

angle2 is the end angle of the arc, relative to angle1, in 1/64ths of a degree counter clockwise.

  drawable.draw_polygon(gc, filled, points)

gc is the Graphics Context.

filled is a boolean indicating the polygon should be filled with the foreground color if TRUE or not filled, if FALSE.

points is a list of coordinate pairs in tuples e.g. [ (0,0), (2,5), (3,7), (4,11) ] of the points to be drawn as a connected polygon.

  drawable.draw_string(font, gc, x, y, string)

  drawable.draw_text(font, gc, x, y, string)

font is the gtk.gdk.Font to use to render the string.

gc is the Graphics Context.

x and y are the coordinates of the point to start rendering the string i.e the left baseline.

string is the string of characters to render.

Note

Both the draw_string() and draw_text() methods are deprecated - use a pango.Layout instead with the draw_layout() method.

  drawable.draw_layout(gc, x, y, layout)

gc is the Graphics Context.

x and y are the coordinates of the point to start rendering the layout.

layout is the pango.Layout that is to be rendered.

  drawable.draw_drawable(gc, src, xsrc, ysrc, xdest, ydest, width, height)

gc is the Graphics Context.

src is the source drawable.

xsrc and ysrc are the coordinates of the top left rectangle in the source drawable.

xdest and ydest are the coordinates of the top left corner in the drawing area.

width and height are the width and height of the source drawable area to be copied to the drawable. If width or height is -1 then the full width or height of the drawable is used.

  drawable.draw_image(gc, image, xsrc, ysrc, xdest, ydest, width, height)

gc is the Graphics Context.

image is the source image.

xsrc and ysrc are the coordinates of the top left rectangle in the source drawable.

xdest and ydest are the coordinates of the top left corner in the drawing area.

width and height are the width and height of the source drawable area to be copied to the drawable. If width or height is -1 then the full width or height of the image is used.

  drawable.draw_points(gc, points)

gc is the Graphics Context.

points is a list or tuple of coordinate pairs in tuples e.g. [ (0,0), (2,5), (3,7), (4,11) ] of the points to be drawn.

  drawable.draw_segments(gc, segs)

gc is the Graphics Context.

segs is a list or tuple of start and end coordinate pairs in tuples e.g. [ (0,0, 1,5), (2,5, 1,7), (3,7, 1,11), (4,11, 1,13) ] of the line segments to be drawn.

  drawable.draw_lines(gc, points)

gc is the Graphics Context.

points is a list or tuple of coordinate pairs in tuples e.g. [ (0,0), (2,5), (3,7), (4,11) ] of the points to be connected with lines.

  drawable.draw_rgb_image(gc, x, y, width, height, dith, rgb_buf, rowstride)

  drawable.draw_rgb_32_image(gc, x, y, width, height, dith, buf, rowstride)

  drawable.draw_gray_image(gc, x, y, width, height, dith, buf, rowstride)

gc is the Graphics Context.

x and y are the top left corner of the image bounding rectangle.

width and height are the width and height of the image bounding rectangle.

dith is the dither mode as described below

For the draw_rgb_image() method, rgb_buf is the RGB Image data packed in a string as a sequence of 8-bit RGB pixel triplets. For the draw_rgb_32_image() method, buf is the RGB Image data packed in a string as a sequence of 8-bit RGB pixel triplets with 8-bit padding (4 characters per RGB pixel). For the draw_gray_image() method, buf is the gray image data packed in a string as 8-bit pixel data.

rowstride is the number of characters from the start of one row to the start of the next row of the image. rowstride usually defaults to: 3 * width for the draw_rgb_image() method; 4 * width for the draw_rgb_32_image(); and, width for the draw_gray_image() method. If rowstride is 0 the line will be replicated height times.

The dither modes are:

  RGB_DITHER_NONE    # Never use dithering.

  RGB_DITHER_NORMAL  # Use dithering in 8 bits per pixel (and below) only.

  RGB_DITHER_MAX     # Use dithering in 16 bits per pixel and below.

The drawingarea.py example program demonstrates the use of most of the DrawingArea methods. It also puts the DrawingArea inside a ScrolledWindow and adds horizontal and vertical Ruler widgets. Figure 12.1, “Drawing Area Example” shows the program in operation:

Figure 12.1. Drawing Area Example

Drawing Area Example

The drawingarea.py source code is below and uses the gtk.xpm pixmap:

    1   #!/usr/bin/env python
    2
    3   # example drawingarea.py
    4
    5   import pygtk
    6   pygtk.require('2.0')
    7   import gtk
    8   import operator
    9   import time
   10   import string
   11
   12   class DrawingAreaExample:
   13       def __init__(self):
   14           window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   15           window.set_title("Drawing Area Example")
   16           window.connect("destroy", lambda w: gtk.main_quit())
   17           self.area = gtk.DrawingArea()
   18           self.area.set_size_request(400, 300)
   19           self.pangolayout = self.area.create_pango_layout("")
   20           self.sw = gtk.ScrolledWindow()
   21           self.sw.add_with_viewport(self.area)
   22           self.table = gtk.Table(2,2)
   23           self.hruler = gtk.HRuler()
   24           self.vruler = gtk.VRuler()
   25           self.hruler.set_range(0, 400, 0, 400)
   26           self.vruler.set_range(0, 300, 0, 300)
   27           self.table.attach(self.hruler, 1, 2, 0, 1, yoptions=0)
   28           self.table.attach(self.vruler, 0, 1, 1, 2, xoptions=0)
   29           self.table.attach(self.sw, 1, 2, 1, 2)
   30           window.add(self.table)
   31           self.area.set_events(gtk.gdk.POINTER_MOTION_MASK |
   32                                gtk.gdk.POINTER_MOTION_HINT_MASK )
   33           self.area.connect("expose-event", self.area_expose_cb)
   34           def motion_notify(ruler, event):
   35               return ruler.emit("motion_notify_event", event)
   36           self.area.connect_object("motion_notify_event", motion_notify,
   37                                    self.hruler)
   38           self.area.connect_object("motion_notify_event", motion_notify,
   39                                    self.vruler)
   40           self.hadj = self.sw.get_hadjustment()
   41           self.vadj = self.sw.get_vadjustment()
   42           def val_cb(adj, ruler, horiz):
   43               if horiz:
   44                   span = self.sw.get_allocation()[3]
   45               else:
   46                   span = self.sw.get_allocation()[2]
   47               l,u,p,m = ruler.get_range()
   48               v = adj.value
   49               ruler.set_range(v, v+span, p, m)
   50               while gtk.events_pending():
   51                   gtk.main_iteration()
   52           self.hadj.connect('value-changed', val_cb, self.hruler, True)
   53           self.vadj.connect('value-changed', val_cb, self.vruler, False)
   54           def size_allocate_cb(wid, allocation):
   55               x, y, w, h = allocation
   56               l,u,p,m = self.hruler.get_range()
   57               m = max(m, w)
   58               self.hruler.set_range(l, l+w, p, m)
   59               l,u,p,m = self.vruler.get_range()
   60               m = max(m, h)
   61               self.vruler.set_range(l, l+h, p, m)
   62           self.sw.connect('size-allocate', size_allocate_cb)
   63           self.area.show()
   64           self.hruler.show()
   65           self.vruler.show()
   66           self.sw.show()
   67           self.table.show()
   68           window.show()
   69
   70       def area_expose_cb(self, area, event):
   71           self.style = self.area.get_style()
   72           self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
   73           self.draw_point(10,10)
   74           self.draw_points(110, 10)
   75           self.draw_line(210, 10)
   76           self.draw_lines(310, 10)
   77           self.draw_segments(10, 100)
   78           self.draw_rectangles(110, 100)
   79           self.draw_arcs(210, 100)
   80           self.draw_pixmap(310, 100)
   81           self.draw_polygon(10, 200)
   82           self.draw_rgb_image(110, 200)
   83           return True
   84
   85       def draw_point(self, x, y):
   86           self.area.window.draw_point(self.gc, x+30, y+30)
   87           self.pangolayout.set_text("Point")
   88           self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
   89           return
   90
   91       def draw_points(self, x, y):
   92           points = [(x+10,y+10), (x+10,y), (x+40,y+30),
   93                     (x+30,y+10), (x+50,y+10)]
   94           self.area.window.draw_points(self.gc, points)
   95           self.pangolayout.set_text("Points")
   96           self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
   97           return
   98
   99       def draw_line(self, x, y):
  100           self.area.window.draw_line(self.gc, x+10, y+10, x+20, y+30)
  101           self.pangolayout.set_text("Line")
  102           self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
  103           return
  104
  105       def draw_lines(self, x, y):
  106           points = [(x+10,y+10), (x+10,y), (x+40,y+30),
  107                     (x+30,y+10), (x+50,y+10)]
  108           self.area.window.draw_lines(self.gc, points)
  109           self.pangolayout.set_text("Lines")
  110           self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
  111           return
  112
  113       def draw_segments(self, x, y):
  114           segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70),
  115               (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50))
  116           self.area.window.draw_segments(self.gc, segments)
  117           self.pangolayout.set_text("Segments")
  118           self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
  119           return
  120
  121       def draw_rectangles(self, x, y):
  122           self.area.window.draw_rectangle(self.gc, False, x, y, 80, 70)
  123           self.area.window.draw_rectangle(self.gc, True, x+10, y+10, 20, 20)
  124           self.area.window.draw_rectangle(self.gc, True, x+50, y+10, 20, 20)
  125           self.area.window.draw_rectangle(self.gc, True, x+20, y+50, 40, 10)
  126           self.pangolayout.set_text("Rectangles")
  127           self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
  128           return
  129
  130       def draw_arcs(self, x, y):
  131           self.area.window.draw_arc(self.gc, False, x+10, y, 70, 70,
  132                                     0, 360*64)
  133           self.area.window.draw_arc(self.gc, True, x+30, y+20, 10, 10,
  134                                     0, 360*64)
  135           self.area.window.draw_arc(self.gc, True, x+50, y+20, 10, 10,
  136                                     0, 360*64)
  137           self.area.window.draw_arc(self.gc, True, x+30, y+10, 30, 50,
  138                                     210*64, 120*64)
  139           self.pangolayout.set_text("Arcs")
  140           self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
  141           return
  142
  143       def draw_pixmap(self, x, y):
  144           pixmap, mask = gtk.gdk.pixmap_create_from_xpm(
  145               self.area.window, self.style.bg[gtk.STATE_NORMAL], "gtk.xpm")
  146
  147           self.area.window.draw_drawable(self.gc, pixmap, 0, 0, x+15, y+25,
  148                                          -1, -1)
  149           self.pangolayout.set_text("Pixmap")
  150           self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
  151           return
  152
  153       def draw_polygon(self, x, y):
  154           points = [(x+10,y+60), (x+10,y+20), (x+40,y+70),
  155                     (x+30,y+30), (x+50,y+40)]
  156           self.area.window.draw_polygon(self.gc, True, points)
  157           self.pangolayout.set_text("Polygon")
  158           self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
  159           return
  160
  161       def draw_rgb_image(self, x, y):
  162           b = 80*3*80*['\0']
  163           for i in range(80):
  164               for j in range(80):
  165                   b[3*80*i+3*j] = chr(255-3*i)
  166                   b[3*80*i+3*j+1] = chr(255-3*abs(i-j))
  167                   b[3*80*i+3*j+2] = chr(255-3*j)
  168           buff = string.join(b, '')
  169           self.area.window.draw_rgb_image(self.gc, x, y, 80, 80,
  170                                    gtk.gdk.RGB_DITHER_NONE, buff, 80*3)
  171           self.pangolayout.set_text("RGB Image")
  172           self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
  173           return
  174
  175   def main():
  176       gtk.main()
  177       return 0
  178
  179   if __name__ == "__main__":
  180       DrawingAreaExample()
  181       main()