gpt4 book ai didi

python - PyGTK 自定义小部件不会重绘

转载 作者:行者123 更新时间:2023-11-30 23:38:47 26 4
gpt4 key购买 nike

我在更新自定义 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()
#_____________________________________________________________________

#=========================================================================

信号在类部分中实现并正确发出

__gsignals__ = {
'changed-value' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_FLOAT,))
}

问候对照

最佳答案

这是一种方法,我将其子类化并提供自定义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 是在小部件的“realize”事件中构造的。在此之前,PyGtk 中只是 None。恕我直言,在 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?

关于python - PyGTK 自定义小部件不会重绘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14172427/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com