0

我有一个现有项目,我正在尝试围绕它构建一个 GUI(使用 PyGI + Gtk3)。我需要稍微扩展一些原生对象以使其可渲染。我把问题归结为简化的代码:

# Simplified Equivalent Code

from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import GdkPixbuf

# Pre-existing, complex object
class Move(object):
    def __init__(self, color):
        self.color = color

# Pre-existing, complex object
class Block(object):
    def __init__(self,move=None,**kwds):
        self.move = move

# New object created to help render a Block
class BlockGui(Block):
    pixbufs = {
            'empty' : GdkPixbuf.Pixbuf.new_from_file('block_empty.png'),
            'red' : GdkPixbuf.Pixbuf.new_from_file('block_red.png'),
            'blue' : GdkPixbuf.Pixbuf.new_from_file('block_blue.png'),
          }

    def __setattr__(self, name, value):
        super(BlockGui, self).__setattr__(name, value)

        if name == 'move':
            print "Need to emit a signal here"

    def get_pixbuf(self):
        try:
            return BlockGui.pixbufs[self.move.color]
        except AttributeError:
            return BlockGui.pixbufs['empty']

class BlockRenderer(Gtk.CellRendererPixbuf):
    __gproperties__ = {
            'block' : (GObject.TYPE_PYOBJECT,
                'block to render',
                'the block object to be rendered',
                GObject.PARAM_READWRITE)
            }

    def __init__(self):
        GObject.GObject.__init__(self)
        self.block = None

    def do_set_property(self, prop, value):
        # What is a GParamBoxed? Should I be checking if prop == 'block' from it somehow?
        if isinstance(value, BlockGui):
            self.block = value
            self.set_property('pixbuf', self.block.get_pixbuf())

GObject.type_register(BlockRenderer)

def destroy(widget, data=None):
    Gtk.main_quit()

# Normally do not have access to this assignment
def on_clicked(widget, liststore, treeview):
    treeiter = liststore.get_iter(2)
    block = liststore.get_value(treeiter, 1)
    block.move = Move('red')

def main():
    # 3x5 so this demo window has some size
    fmt = [GObject.TYPE_PYOBJECT] * 3
    liststore = Gtk.ListStore(*fmt)
    for r in xrange(5):
        liststore.append([BlockGui() for x in xrange(3)])

    treeview = Gtk.TreeView(liststore)

    for c in xrange(3):
        col = Gtk.TreeViewColumn(str(c))
        treeview.append_column(col)
        cell = BlockRenderer()
        col.pack_start(cell, True)
        col.add_attribute(cell, 'block', c)

    button = Gtk.Button("Change Color!")
    button.connect('clicked', on_clicked, liststore, treeview)

    vbox = Gtk.VBox()
    vbox.add(treeview)
    vbox.add(button)

    window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
    window.connect('destroy', destroy)
    window.add(vbox)
    window.show_all()

    Gtk.main()

if __name__ == '__main__':
    main()

当前代码运行时,单击按钮不会立即产生结果,但是将鼠标悬停在更改的行上会导致中心方块变为红色(因为悬停在行上会触发刷新)。通常,当一个“正确”的 GObject 调用了 set_attribute 时,它​​会发出一些信号来通知包含它的小部件重新渲染。

我需要知道发出哪个信号,向谁发出信号,以及如何模拟这种行为。

4

1 回答 1

0

If you know the widget that must be redrawn, then you can just call queue_draw(), queue_draw_region() or queue_draw_area() for that widget. That will invalidate that window area and it will be redrawn. If you want more fine grained control, you might want to use Gtk.DrawingArea.

You might want to check the documentation for The GTK+ Drawing Model.

于 2012-09-23T03:04:12.833 回答