I have a problem updating a custom GTK+ widget: VUWidget.
A Generator class is updating the level property of the class Section, whose subclass has a VUWidget property. The Generator class updates the values of the level properties correctly.
import pygtk
pygtk.require("2.0")
import gtk, gtk.gdk
import cairo
#=========================================================================
class VUWidget(gtk.DrawingArea):
__gtype_name__ = 'VUWidget'
_BACKGROUND_RGB = (0., 0., 0.)
_LEVEL_GRADIENT_BOTTOM_ORGBA = (1, 0, 1, 0, 1)
_LEVEL_GRADIENT_TOP_ORGBA = (0, 1, 0, 0, 1)
#_____________________________________________________________________
def __init__(self, section):
gtk.DrawingArea.__init__(self)
self.section = section
self.connect("configure_event", self.on_configure_event)
self.connect("expose-event", self.OnDraw)
self.section.connect("changed-value", self.ValueChanged)
self.set_size_request(30,100)
self.realize()
self.show()
#_____________________________________________________________________
def ValueChanged(self, widget, level):
#print ("Callback %f" % self.section.GetLevel())
rect = self.get_allocation()
self.window.invalidate_rect(rect, False)
return False
#_____________________________________________________________________
def GenerateBackground(self):
rect = self.get_allocation()
ctx = cairo.Context(self.source)
ctx.set_line_width(2)
ctx.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
pat = cairo.LinearGradient(0.0, 0.0, 0, rect.height)
pat.add_color_stop_rgba(*self._LEVEL_GRADIENT_BOTTOM_ORGBA)
pat.add_color_stop_rgba(*self._LEVEL_GRADIENT_TOP_ORGBA)
ctx.rectangle(0, 0, rect.width, rect.height)
ctx.set_source(pat)
ctx.fill()
#_____________________________________________________________________
def on_configure_event(self, widget, event):
self.source = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.allocation.width, self.allocation.height)
self.GenerateBackground()
return self.OnDraw(widget, event)
#_____________________________________________________________________
def OnDraw(self, widget, event):
ctx = self.window.cairo_create()
ctx.save()
rect = self.get_allocation()
ctx.rectangle(0, 0, rect.width, rect.height)
ctx.set_source_rgb(*self._BACKGROUND_RGB)
ctx.fill()
ctx.rectangle(0, rect.height * (1. - self.section.GetLevel()), rect.width, rect.height)
ctx.clip()
ctx.set_source_surface(self.source, 0, 0)
ctx.paint()
ctx.restore()
return False
#_____________________________________________________________________
def Destroy(self):
del self.source
self.destroy()
#_____________________________________________________________________
#=========================================================================
the signal is implemented in the class Section and is emitted correctly
__gsignals__ = {
'changed-value' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_FLOAT,))
}
Regards
Ck
Here’s one way to do it, I subclass this and provide a custom draw method. If there are any changes to the state, I call invalidate, forcing the widget to re-draw through the expose-event. If you need a different context, you can provide it in the on_expose_event
method.
So basically, do all your drawing in one place only. If the widget should display something different, set the new state and re-render. Makes it easy to maintain.
Supplemental response to comment:
Gtk.Window and Gdk.Window are conceptually different. The first is a container that can have exactly one other widget (other container or any other widget). The second is used for drawing stuff on the display and capture events. The gdk.Window is constructed in a widget’s “realize” event. Before that, it is just None in PyGtk. IMHO, it is inadvisable (don’t even know if it’s doable) to draw on a gtk.Window.window. Custom drawing should be done in the gtk.DrawingArea.window. That is what DrawingArea is there for.
References:
https://mail.gnome.org/archives/gtk-app-devel-list/1999-January/msg00138.html
GtkDrawingArea – how to make it drawable?