pygtk gtk.Builder.connect_signals на несколько объектов? - PullRequest
3 голосов
/ 09 января 2011

Я обновляю некоторый код от использования libglade до GtkBuilder, который должен быть будущим.

С gtk.glade вы могли бы повторно вызывать glade_xml.signal_autoconnect(...) для подключения сигналов к объектам разныхклассы, соответствующие различным окнам в программе.Однако Builder.connect_signals, кажется, работает только один раз и (следовательно), чтобы предупреждать о любых обработчиках, которые не определены в первом классе, который передается.

Я понимаю, что могу подключить их вручную, но это кажетсянемного трудоемко(Или, если на то пошло, я мог бы использовать некоторую хакерскую функцию getattr, чтобы позволить ей соединять их через прокси со всеми объектами ...)

Это ошибка, что нет функции для подключения обработчиков к нескольким объектам?Или я что-то упустил?

У кого-то есть похожая проблема http://www.gtkforums.com/about1514.html, которая, как я полагаю, означает, что это невозможно сделать.

Ответы [ 4 ]

4 голосов
/ 13 января 2011

Вот что у меня сейчас есть. Не стесняйтесь использовать его или предложить что-то лучшее:

class HandlerFinder(object):
    """Searches for handler implementations across multiple objects.
    """
    # See <http://stackoverflow.com/questions/4637792> for why this is
    # necessary.

    def __init__(self, backing_objects):
        self.backing_objects = backing_objects

    def __getattr__(self, name):
        for o in self.backing_objects:
            if hasattr(o, name):
                return getattr(o, name)
        else:
            raise AttributeError("%r not found on any of %r"
                % (name, self.backing_objects))
3 голосов
/ 24 декабря 2013

Я какое-то время искал решение для этого и обнаружил, что это можно сделать, передав значение всех обработчиков в connect_signals.

Модуль проверки может извлекать методы, используя inspect.getmembers(instance, predicate=inspect.ismethod Затем их можно объединить в словарь, используя d.update(d3), следя за дублирующимися функциями, такими как on_delete.

Пример кода:

import inspect
...    
handlers = {}
for c in [win2, win3, win4, self]:  # self is the main window
    methods = inspect.getmembers(c, predicate=inspect.ismethod)
    handlers.update(methods)
builder.connect_signals(handlers)

Это не приведет к получению имен методов псевдонимов, объявленных с использованием @alias.Пример того, как это сделать, приведен в коде для Builder.py по адресу def dict_from_callback_obj.

2 голосов
/ 10 января 2011

Я только новичок, но это то, чем я занимаюсь, может быть, это может вдохновить ;-)

Я создаю экземпляры основных компонентов из «элемента управления» и передаю объект построителя, чтобы созданный объект мог использовать любой из объектов построителя (например, mainwindow) или добавить в построитель (пример aboutDialog). Я также передаю словарь (dic), где каждый компонент добавляет к нему «сигналы».
Затем выполняется 'connect_signals (dic)'.
Конечно, мне нужно выполнить какое-то ручное соединение сигналов, когда мне нужно передать пользовательские аргументы в метод обратного вызова, но их мало.

#modules.control.py
class Control:

    def __init__(self):

        # Load the builder obj
        guibuilder = gtk.Builder()
        guibuilder.add_from_file("gui/mainwindow.ui")
        # Create a dictionnary to store signal from loaded components
        dic = {}

        # Instanciate the components...
        aboutdialog = modules.aboutdialog.AboutDialog(guibuilder, dic)           
        mainwin = modules.mainwindow.MainWindow(guibuilder, dic, self)
        ...

        guibuilder.connect_signals(dic)
        del dic


#modules/aboutdialog.py
class AboutDialog:

    def __init__(self, builder, dic):
        dic["on_OpenAboutWindow_activate"] = self.on_OpenAboutWindow_activate
        self.builder = builder

    def on_OpenAboutWindow_activate(self, menu_item):
        self.builder.add_from_file("gui/aboutdialog.ui")
        self.aboutdialog = self.builder.get_object("aboutdialog")
        self.aboutdialog.run()

        self.aboutdialog.destroy()

#modules/mainwindow.py
class MainWindow:

    def __init__(self, builder, dic, controller):

        self.control = controller

        # get gui xml and/or signals
        dic["on_file_new_activate"] = self.control.newFile
        dic["on_file_open_activate"] = self.control.openFile
        dic["on_file_save_activate"] = self.control.saveFile
        dic["on_file_close_activate"] = self.control.closeFile
        ...

        # get needed gui objects
        self.mainWindow = builder.get_object("mainWindow")
        ...

Редактировать: альтернатива автоматическому присоединению сигналов к обратным вызовам:
Непроверенный код

def start_element(name, attrs):
    if name == "signal":
        if attrs["handler"]:
            handler = attrs["handler"]
            #Insert code to verify if handler is part of the collection
            #we want.
            self.handlerList.append(handler)

def extractSignals(uiFile)
    import xml.parsers.expat
    p = xml.parsers.expat.ParserCreate()
    p.StartElementHandler = self.start_element
    p.ParseFile(uiFile)

self.handlerList = []
extractSignals(uiFile)

for handler in handlerList:
    dic[handler] = eval(''. join(["self.", handler, "_cb"]))
1 голос
/ 05 июня 2014
builder.connect_signals
({ 
   "on_window_destroy" : gtk.main_quit, 
   "on_buttonQuit_clicked" : gtk.main_quit 
})
...