0

I have an existing project that I'm trying to build a GUI around (using PyGI + Gtk3). There are some native objects that I need to extend slightly to make them renderable. I've boiled the problem down to the simplified code here:

# 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()

When the current code is run, clicking the button yields no immediate result, but running the mouse over the changed row will cause the center square to turn red (as the hover over the row triggers a refresh). Normally, when a 'proper' GObject has a set_attribute called, it will emit some signals to notify the widgets containing it to re-render.

I need to know which signal that emits, to whom it's emitted, and how to emulate that behavior.

ptomato
  • 56,175
  • 13
  • 112
  • 165
Pat
  • 1,882
  • 2
  • 15
  • 22
  • Also, someone with more rep than me needs to create a PyGI tag. PyGTK is dead AFAIK... – Pat Sep 17 '12 at 04:11
  • 1
    I've tagged it `pygobject`. PyGI is the old name for what is now called PyGObject. Confusingly, PyGObject was also the name for the GObject bindings in PyGTK which, as you say, is on its way out. – ptomato Sep 17 '12 at 10:10

1 Answers1

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.

gpoo
  • 8,408
  • 3
  • 38
  • 53