Last week I set out to learn PyGTK by doing. Quickly. As can be imagined, the resulting code was less than stellar, but I did learn a lot.
By far the most glaring design error I made was in not completely decoupling my UI objects from "business" logic, ala MVC. This failure was the result of not totally comprehending the role signals should play in GTK applications. I made the first step correctly, with distinct objects for the UI panel and logic, but sadly that was the last smart choice I made. My next was deciding how to update the UI when the state of the system changed. "Hmm", I thought. "If I just pass the appropriate UI control through to the logic layer, I can update the view as necessary! Brilliant!". BZzzzzzzzzzzzt! Wrong.
The right approach in GTK is to use signals to notify the UI of changes to your objects. To do this, inherit from gobject.Gobject and add a __gsignals__ attribute. Here's a mocked up example of a simulation that emits a "simulation-step" signal every time the simulation is updated. To update a hypothetical counter widget we simply connect the signal to a callback that updates the widget.
class Controller(gobject.GObject):
__gsignals__ = {
'simulation-step': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, (int,)),
}
def step_simulation(self, step):
self.emit('simulation-step', step)
class View(object):
def __init__(self, builder, controller):
# "builder" is a Glade gtk.Builder object.
builder.connect_signals(self)
self.step_counter = builder.get_object('step_counter')
controller.connect('simulation-step', self.on_simulation_step)
def on_simulation_step(self, simulation, step):
self.step_counter.set_value(step)
controller = Controller()
view = View(controller)
The fundamental mistake I made was assuming that GTK signals were purely for notifying my application of UI changes. In reality, signals are equally important in notifying the UI of application state changes.
Comments [0]