Marco Islas Blog




Drawing with Cairo without flicker

(py)Gtk provides a quick way to get a cairo context using the gtk.DrawingArea widget, this widget let you draw everythin you want into your application using the widget.window drawable area.

It help you to create custom widgets (you can also use this with buttons or any other widget), the problem with the usage of this context is that everything you ask it to draw it will draw it as soon as it can.

If you draw several lines or you draw the same thing very often (an animation for example) your draw may flick, making your application looks ugly.

There is an easy way to avoid this, using a surface to draw and when you are done put your draw into the context using the set_source_surface method.

In the next example you have a windows, with a custom "progressbar" using gtk.DrawingArea and a slide that is supposed to change the value of the progressbar but I'm so lazy to move a slide that let the computer do the work :-).

The trick is this part of the code:

        def do_expose(self, widget, event):
                x,y,w,h = self.allocation
                surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w,h)
                context = cairo.Context(surface)
                #cleaning
                rectangle = context.rectangle(x,y,w,h)
                context.set_source_rgb(1,1,1)
                context.fill()
                value = (self.value / 100)*w
                rectangle = context.rectangle(x,y,value,h)
                context.set_source_rgb(0.2,0.5,0.8)
                context.fill()
                cr = self.window.cairo_create()
                cr.set_source_surface(surface)
                cr.paint()
                return True
 

We create a surface using cairo.ImageSurface and then create a cairo context from it, draw on that context and at the end use the widget.window.cairo_create to create a context for the drawing_area and use set_source_surface to get all the stuff
we drew into the DrawingArea context. At the en just paint it.





#!/usr/bin/env python
import gtk
import cairo
import random
import gobject
class progressbar(gtk.DrawingArea):
        def __init__(self):
                gtk.DrawingArea.__init__(self)
                self.connect('expose-event', self.do_expose)
                self.value = 0
                self.set_property('events', gtk.gdk.EXPOSURE_MASK)
       
        def do_expose(self, widget, event):
                x,y,w,h = self.allocation
                surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w,h)
                context = cairo.Context(surface)
                #cleaning
                rectangle = context.rectangle(x,y,w,h)
                context.set_source_rgb(1,1,1)
                context.fill()
                value = (self.value / 100)*w
                rectangle = context.rectangle(x,y,value,h)
                context.set_source_rgb(0.2,0.5,0.8)
                context.fill()
                cr = self.window.cairo_create()
                cr.set_source_surface(surface)
                cr.paint()
                return True
       
        def set_value(self, value):
                self.value = value
                self.emit('expose-event', gtk.gdk.Event(gtk.gdk.EXPOSE))

def change_value(scale, progres):
        progress.set_value(scale.get_value())
def random_change(scale):
        r = random.randint(50,100)
        scale.set_value(r)
        return True
window = gtk.Window()
window.set_size_request(640,480)
window.set_position(gtk.WIN_POS_CENTER)
window.connect('destroy', gtk.main_quit)
vbox = gtk.VBox()
window.add(vbox)
progress = progressbar()
progress.set_size_request(100,100)
vbox.pack_start(progress, False, False, 2)
adjustment = gtk.Adjustment(value=0, lower=0, upper=100)
scale = gtk.HScale(adjustment)
scale.connect('value-changed', change_value, progress)
vbox.pack_start(scale, False, False, 2)
gobject.idle_add(random_change, scale)
window.show_all()
gtk.main()
 

Leave a Comment

Write the captcha code you are seeing.

Comment XML feeds: RSS | Atom




twitter logo




Recent Comments On Blog

avatar
Marco Antonio Islas Cruz on
 
avatar
Marco Antonio Islas Cruz on
 
avatar
Marco Antonio Islas Cruz on
 Getting ready
avatar
Marco Antonio Islas Cruz on
 Python: Create win32 services using Python and py2exe
avatar
jopython@gmail.com on
 Python: Create win32 services using Python and py2exe
avatar
yodenuevo on
 Holy Shit!
avatar
markuz on
 Holy Shit!
avatar
yo on
 Holy Shit!
avatar
Gustavo on
 Things that happen last week
avatar
Marco Antonio Islas Cruz on
 Christine: rola_christine.py