【问题标题】:Is there a generic update notification/pub sub system for GTK?GTK 是否有通用的更新通知/发布子系统?
【发布时间】:2011-12-11 21:37:17
【问题描述】:

我正在构建一个带有多个小部件的 PyGTK 应用程序,当这些小部件发生更改时,需要通知其他小部件有关更改。我想避免这样的代码:

def on_entry_color_updated(self, widget):
    self.paint_tools_panel.current_color_pane.update_color()
    self.main_window.status_bar.update_color()
    self.current_tool.get_brush().update_color()

改为这样做:

def on_entry_color_updated(self, widget):
    self.update_notify('color-changed')

状态栏、当前颜色窗格和当前工具将订阅该通知事件并采取相应行动。据我所知,GObject 信号机制只允许我在特定小部件上注册回调,因此每个想要接收通知的对象都必须知道该小部件。

GTK 提供这样的系统还是我应该自己构建它? 如果我正确理解他们的design doc,GNOME 的照片组织应用程序 Shotwell 的开发人员必须构建自己的信号机制.在这里搜索 SO 并没有找到任何明确的答案。

编辑:

澄清为什么我认为 GObject 信号不是我需要的(或只是我需要的一部分)。使用 GObject,我需要将一个对象显式连接到另一个对象,如下所示:

emitter.connect('custom-event', receiver.event_handler)

所以在我的应用程序中,我必须这样做:

class ColorPane(gtk.Something):
    def __init__(self, application):
        # init stuff goes here...

        application.color_pallette.connect('color-changed', self.update_color)

    def update_color(self, widget):
        """Show the new color."""
        pass

class StatusBar(gtk.Something):
    def __init__(self, application):
        # init stuff goes here...

        application.color_pallette.connect('color-changed', self.update_color)

    def update_color(self, widget):
        """Show the new color name."""
        pass

class Brush(gtk.Something):
    def __init__(self, application):
        # init stuff goes here...

        application.color_pallette.connect('color-changed', self.update_color)

    def update_color(self, widget):
        """Draw with new color."""
        pass

换句话说,我必须将应用程序对象或知道 color_palette 的其他对象传递给我的应用程序中的其他对象,以便它们连接到 color_pallette 信号。这是我想要避免的那种耦合。

【问题讨论】:

    标签: python user-interface architecture gtk pygtk


    【解决方案1】:

    首先,您可以创建GObject 的自定义子类,它提供一些custom signals。以下示例是链接文章中给出的示例的略微修改版本:

    import pygtk
    pygtk.require('2.0')
    import gobject
    
    class Car(gobject.GObject):
    
        __gsignals__ = {
            'engine-started': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
            'engine-stopped': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
        }
    
        def __init__(self):
            gobject.GObject.__init__(self)
            self._state = 0
    
        def start(self):
            if not self._state:
                self._state = 1
                self.emit('engine-started')
    
        def stop(self):
            if self._state:
                self._state = 0
                self.emit('engine-stopped')
    
    
    gobject.type_register(Car)
    
    def kill_switch(c):
        def callback(*unused, **ignored):
            c.stop()
        return callback
    
    def on_start(*unused, **ignored):
        print "Started..."
    
    def on_stop(*unused, **ignored):
        print "Stopped..."
    
    some_car = Car()
    some_car.connect('engine-started', on_start)
    some_car.connect('engine-started', kill_switch(some_car))
    some_car.connect('engine-stopped', on_stop)
    some_car.start()
    

    另一种方法是利用 PyPI 上已有的众多事件/信号包之一,例如:

    【讨论】:

      【解决方案2】:

      GObjects 不必是小部件。例如,您的应用程序类可以是一个 GObject,它定义了其他小部件连接到的信号。

      另外,我认为您没有正确理解 Shotwell 设计文档。在我看来,他们的信号系统是 100% GObject 信号系统,只是特别保证了信号处理的顺序。正如他们在设计文档中所说,这些事情在普通的 GObject 中是可能的,但 Vala 更容易按照他们的方式编写代码。

      【讨论】:

      • 我认为 GObject 信号不适合我的目的,因为它需要我明确地连接两个对象。我已经更新了我的问题以澄清。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      • 2018-01-17
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多