Search code examples
pythonpygtkdrawing2d

Pygtk graphics contexts and allocating colors


I've searched on this, but nothing has what I'm looking for.

http://www.mail-archive.com/[email protected]/msg10529.html -- Nobody answered him. This is exactly what I'm experiencing. When I set the foreground on a graphics context, it doesn't seem to actually change.

I've been through the tutorial and FAQ, but neither say much. They either just use the black and white contexts or they give you broken links. I'm left thinking maybe it's a bug. But the kid in me says I'm just missing something and I keep ignoring the fact I have a working alternative. This would be better though. And the further I get into this, the more I'm going to need these contexts and colors.

Here's my code snippet.

def CreatePixmapFromLCDdata(lcdP, ch, widget):
    width = lcdP.get_char_width()
    height = lcdP.get_char_height()

    # Create pixmap
    pixmap = gtk.gdk.Pixmap(widget.window, width, height)

    # Working graphics contexts, wrong color
    black_gc = widget.get_style().black_gc
    white_gc = widget.get_style().white_gc

    char_gc = widget.window.new_gc()
    colormap = char_gc.get_colormap()

    bg_color = NewColor(text="#78a878", colormap=colormap)

    print "Before", char_gc.foreground.red, char_gc.foreground.green, char_gc.foreground.blue
    char_gc.set_foreground(bg_color)
    print "AFter", char_gc.foreground.red, char_gc.foreground.green, char_gc.foreground.blue

    fg_color = NewColor(text="#113311", colormap=colormap)

    pixmap.draw_rectangle(char_gc, True, 0, 0, width, height)
    char_gc.foreground = fg_color
    for j in range(lcdP.dots['y']):
        k = lcdP.pixels['y']*j
        for i in range(lcdP.dots['x']):
            if 1<<(lcdP.dots['x']-1-i) & ch[j] == 0: continue

            m = i*lcdP.pixels['y']

            for jj in range(k, k+lcdP.pixels['y']-1):
                for ii in range(m+1, m+lcdP.pixels['x']):
                    pixmap.draw_point(char_gc, ii, jj)
    return pixmap

I thought maybe it was the way I was allocating the colors. As you see in the snippet, I've used the graphic context's own colormap. I've tried different colormaps, this being the latest. I've even tried an unallocated color. Notice the white_gc and black_gc graphics contexts. When I use those I'm able to draw black on a white background fine. Otherwise (with a created context) everything's black, fg and bg. When I change white's foreground color, it always comes out black.

Here's the output. Notice the color doesn't change very much. I'd say it didn't change, or at least not enough to matter visually.

Before 6 174 60340
After 5 174 60340

Here's how I allocate the colors.

def NewColor(red=0, green=0, blue=0, text=None, colormap=None):
    if text == None:
        c = gtk.gdk.Color(red, green, blue)
    else:
        c = gtk.gdk.color_parse(text)
    if colormap == None:
        colormap = gtk.gdk.colormap_get_system()
    colormap.alloc_color(c)
    return c

Solution

  • I've had some trouble with Drawable and GC in the past. This answer got me started on the way to a solution. Here's a quick example that uses a custom colour gc to draw some squares:

    import gtk
    
    square_sz = 20
    pixmap = None
    colour = "#FF0000"
    gc = None
    
    def configure_event( widget, event):
        global pixmap
        x, y, width, height = widget.get_allocation()
        pixmap = gtk.gdk.Pixmap(widget.window, width, height)
        white_gc = widget.get_style().white_gc
        pixmap.draw_rectangle(white_gc, True, 0, 0, width, height)
        return True
    
    def expose_event(widget, event):
        global pixmap
        if pixmap:
            x , y, w, h = event.area
            drawable_gc = widget.get_style().fg_gc[gtk.STATE_NORMAL]
            widget.window.draw_drawable(drawable_gc, pixmap, x, y, x, y, w, h)
        return False
    
    def button_press_event(widget, event):
        global pixmap, square_sz, gc, colour
        if event.button == 1 and pixmap:
            x = int(event.x / square_sz) * square_sz
            y = int(event.y / square_sz) * square_sz
            if not gc:
                gc = widget.window.new_gc()
                gc.set_rgb_fg_color(gtk.gdk.color_parse(colour))
            pixmap.draw_rectangle(gc, True, x, y, square_sz, square_sz)
            widget.queue_draw_area(x, y, square_sz, square_sz)
    
        return True
    
    if __name__ == "__main__":
        da = gtk.DrawingArea()
        da.set_size_request(square_sz*20, square_sz*20)
    
        da.connect("expose_event", expose_event)
        da.connect("configure_event", configure_event)
        da.connect("button_press_event", button_press_event)
    
        da.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.BUTTON_PRESS_MASK)
    
        w = gtk.Window()
        w.add(da)
        w.show_all()
        w.connect("destroy", lambda w: gtk.main_quit())
    
        gtk.main()
    

    Hope it helps.