PyGTK自定义小部件不为红色

2024-10-04 03:25:50 发布

您现在位置:Python中文网/ 问答频道 /正文

更新自定义GTK+widget:VUWidget时出现问题。 生成器类正在更新类节的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()  
    #_____________________________________________________________________  

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

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

^{pr2}$

问候 Ck公司


Tags: rectselfeventsourcegtkdefsectionwidget
1条回答
网友
1楼 · 发布于 2024-10-04 03:25:50

这里有一种方法,我将其子类化并提供一个自定义的draw方法。如果状态有任何变化,我调用invalidate,强制小部件重新绘制暴露事件。如果需要不同的上下文,可以在on_expose_事件中提供 方法。在

所以基本上,你所有的画都只在一个地方。如果小部件应该显示不同的内容,请设置新状态并重新呈现。易于维护。在

#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.窗口以及Gdk窗口在概念上是不同的。第一个是一个容器,它可以正好有一个其他小部件(其他容器或任何其他小部件)。第二个用于在显示上绘制内容并捕捉事件。这个gdk窗口在widget的“realize”事件中构造。在此之前,在PyGtk是没有的。以何为例,这是不可取的(甚至不知道是否可行)gtk.Window.Window. 自定义绘图应在gtk.图纸区域窗口. 这就是DrawingArea的目的。在

参考文献:

https://mail.gnome.org/archives/gtk-app-devel-list/1999-January/msg00138.html
GtkDrawingArea - how to make it drawable?

相关问题 更多 >