【问题标题】:How to use custom signals in GObject?如何在 GObject 中使用自定义信号?
【发布时间】:2015-11-28 12:59:02
【问题描述】:

我想制作一个带有 TreeView 小部件和其中一些项目的程序,它可以通过发出和捕获我称之为 incr 的信号来交换数据。

我创建了 10 个树项目,将 incr 信号连接到每个项目。现在,如果我从其中一个发出 incr 信号,为什么其他 9 个不接收它?

为什么只有发射器对象才能捕捉到自己发射的信号?

这是一个演示此问题的示例程序:

#!/usr/bin/env python3

from gi.repository import Gtk, GObject


class TreeItem(GObject.GObject):
    __gsignals__ = {
        'incr': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, ())
    }

    def __init__(self, title):
        GObject.GObject.__init__(self)
        self.title = title

    def do_incr(self):
        print('It works!')

GObject.type_register(TreeItem)


class Application(Gtk.Window):
    def __init__(self):
        super().__init__(Gtk.WindowType.TOPLEVEL)
        self.connect('destroy', self.__on_destroy)
        vbox = Gtk.VBox()
        button = Gtk.Button('emit signal')
        button.connect('clicked', self.__on_button_clicked)
        vbox.pack_start(button, False, False, 0)

        list_store = Gtk.ListStore(GObject.GObject)
        text_renderer = Gtk.CellRendererText()
        tree_column = Gtk.TreeViewColumn(None, text_renderer)
        self.__tree_view = Gtk.TreeView(list_store)
        self.__tree_view.append_column(tree_column)
        tree_column.set_cell_data_func(text_renderer, self.__populate_tree)
        vbox.pack_start(self.__tree_view, True, True, 0)
        self.add(vbox)

        self.show_all()

        for i in range(10):
            item = TreeItem(str(i))
            item.connect('incr', self.__on_incr)
            list_store.append((item,))

    def __on_incr(self, item):
        item.title = str(int(item.title) + 1)
        self.__tree_view.queue_draw()

    def __on_button_clicked(self, e):
        selected_item = self.get_selected_item()
        if selected_item:
            selected_item.emit('incr')

    def get_selected_item(self):
        selection = self.__tree_view.get_selection()
        if selection:
            model, iter_ = selection.get_selected()
            return model.get_value(iter_, 0)

    def __populate_tree(self, column, cell, model, iter_, user_data):
        item = model.get_value(iter_, 0)
        cell.set_property('text', item.title)

    def __on_destroy(self, e):
        Gtk.main_quit()


if __name__ == '__main__':
    Application()
    Gtk.main()

【问题讨论】:

  • 您没有在上述代码的任何地方发出信号。并且当你发出一个信号时,其他同类型的对象不会得到通知;他们必须连接到每个其他对象的信号才能工作。对于它的价值,如果您希望 GtkTreeView 在每次调用 do_incr 信号时更新,您可能最好使用自定义 GtkTreeModel 子类;它有一个changed 信号,您发出该信号以通知 GtkTreeView 对象已更改。
  • @andlabs 我在 __on_button_clicked() 中发出信号。所有项目都通过connect()连接到回调函数。

标签: python gtk pygobject gobject


【解决方案1】:

我创建了 10 个树项目,将“incr”信号连接到每个项目,现在如果我从其中一个项目发出“incr”信号,为什么其余 9 个项目无法接收?

当 TreeItem 发出您的应用程序接收到的信号时,您正在将 TreeItems 连接到您的应用程序。您的 TreeItem 没有连接到任何东西,因此它们什么也没有收到。我不完全确定你想要在哪里实现这种行为。

【讨论】:

    【解决方案2】:

    相关部分在这里:

        [...]
        for i in range(10):
            item = TreeItem(str(i))
            item.connect('incr', self.__on_incr)
            list_store.append((item,))
    

    您将每个项目连接到一个信号,然后:

    def __on_button_clicked(self, e):
        selected_item = self.get_selected_item()
        if selected_item:
            selected_item.emit('incr')
    

    它仅向 selected_item 发出信号,因为这是唯一发出的信号。

    每个项目都连接到同一个方法这一事实并不意味着当信号发出时,所有项目都会被调用。每个对象都会发出信号,就像您在selected_item.emit('incr') 中所做的那样(您说的是:对于这个selected_item,请发出信号incr)。其他项目的信号从未发出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-29
      • 1970-01-01
      相关资源
      最近更新 更多