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

再描画する必要のあるウィジェットがわかっている場合はqueue_draw()queue_draw_region()またはqueue_draw_area()そのウィジェットを呼び出すことができます。これにより、そのウィンドウ領域が無効になり、再描画されます。よりきめ細かい制御が必要な場合は、Gtk.DrawingAreaを使用することをお勧めします。

GTK+描画モデルのドキュメントを確認することをお勧めします。

于 2012-09-23T03:04:12.833 に答える