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 が呼び出されると、それを含むウィジェットに再レンダリングするよう通知するシグナルが送信されます。
どのシグナルが誰に向けて発信され、その動作をどのようにエミュレートするかを知る必要があります。