我在更新自定义GTK +小部件时遇到问题:VUWidget。 Generator类正在更新类Section的level属性,其子类具有VUWidget属性。 Generator类正确更新级别属性的值。
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()
#_____________________________________________________________________
#=========================================================================
信号在类Section中实现并正确发出
__gsignals__ = {
'changed-value' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_FLOAT,))
}
此致 CK
答案 0 :(得分:3)
这是一种方法,我将其子类化并提供自定义 draw 方法。如果状态有任何更改,我会调用 invalidate ,强制小部件重新绘制 expose-event 。如果您需要不同的上下文,可以在 on_expose_event 中提供 方法。
所以基本上,只在一个的地方进行所有绘图。如果窗口小部件应显示不同的内容,请设置新状态并重新呈现。使维护变得容易。
#cairovehicle.py
import gtk
class CairoVehicle(gtk.DrawingArea):
def __init__(self):
gtk.DrawingArea.__init__(self)
self.connect("expose-event", self.on_expose_event)
def get_background(self):
"""Serves as a caching solution."""
return self.__bg
def set_background(self, pattern):
"""Serves as a caching solution."""
self.__bg = pattern
def get_brush(self):
"""Serves as a caching solution."""
return self.__brush
def set_brush(self, pattern):
"""Serves as a caching solution."""
self.__brush = pattern
def on_expose_event(self, widget, event):
context = self.window.cairo_create()
# Restrict cairo to the exposed area
context.rectangle(*event.area)
context.clip()
self.width, self.height = self.window.get_size()
self.draw(context)
def on_configure_event(self, widget, event):
"""Override this in case you want to do something when
the widget's size changes."""
return super(CairoVehicle, self).on_configure_event(widget, event)
def invalidate(self):
"""Force a re-rendering of the window."""
rect = self.get_allocation()
# Compensate for parent offset, if any.
parent = self.get_parent()
if parent:
offset = parent.get_allocation()
rect.x -= offset.x
rect.y -= offset.y
self.window.invalidate_rect(rect, False)
def draw(self, context):
"""Override this."""
# do custom drawing here
raise NotImplementedError()
def make_grid(self, context, fgcolor, bgcolor, gapwidth, linewidth,
width, height):
context.set_source_rgba(*bgcolor)
context.rectangle(0, 0, width, height)
context.fill()
context.set_source_rgba(*fgcolor)
context.set_line_width(linewidth)
# uneven linewidths lead to blurry displaying when set on integer
# coordinates, so in that case move coordinates away by half a
# pixel.
adjust = 0.5 if linewidth % 2 else 0
i = 1
j = 1
while gapwidth*i-adjust < width:
context.move_to(gapwidth*i-adjust, 0)
context.line_to(gapwidth*i-adjust, height)
context.stroke()
i += 1
while gapwidth*j-adjust < height:
context.move_to(0, gapwidth*j-adjust)
context.line_to(width, gapwidth*j-adjust)
context.stroke()
j += 1
class Grid(CairoVehicle):
def draw(self, context):
context.push_group()
self.make_grid(context, fgcolor=(0, 0, 0, 1), bgcolor=(1, 1, 1, 1),
gapwidth=20, linewidth=1, width=self.width,
height=self.height)
self.set_background(context.pop_group())
context.set_source(self.get_background())
context.paint()
if __name__ == "__main__":
w = gtk.Window()
w.connect("destroy", gtk.main_quit)
w.show()
cv = Grid()
cv.show()
w.add(cv)
gtk.main()
对评论的补充回复:
Gtk.Window和Gdk.Window在概念上是不同的。第一个是一个容器,可以只有一个其他小部件(其他容器或任何其他小部件)。第二个用于在显示器上绘制东西并捕获事件。 gdk.Window是在一个小部件的“实现”事件中构建的。在此之前,它在PyGtk中只是无。恕我直言,它是不可取的(甚至不知道它是否可行)在gtk.Window.window上绘制。自定义绘图应在gtk.DrawingArea.window中完成。这就是DrawingArea的用途。
<强>参考文献:强>
https://mail.gnome.org/archives/gtk-app-devel-list/1999-January/msg00138.html
GtkDrawingArea - how to make it drawable?