3

我正在将一些代码从使用 libglade 更新到 GtkBuilder,这应该是未来的方式。

使用 gtk.glade,您可以glade_xml.signal_autoconnect(...)重复调用将信号连接到程序中不同窗口对应的不同类的对象上。但是Builder.connect_signals似乎只工作一次,并且(因此)对传入的第一个类中未定义的任何处理程序发出警告。

我意识到我可以手动连接它们,但这似乎有点费力。(或者就此而言,我可以使用一些 getattr hackery 让它通过代理将它们连接到所有对象......)

没有功能可以跨多个对象连接处理程序,这是一个错误吗?还是我错过了什么?

其他人也有类似的问题http://www.gtkforums.com/about1514.html我认为这意味着无法完成。

4

4 回答 4

4

这是我目前拥有的。随意使用它,或提出更好的建议:

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))
于 2011-01-13T00:04:53.473 回答
3

一段时间以来,我一直在寻找解决方案,发现可以通过将所有处理程序的 dict 传递给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.

于 2013-12-24T14:50:42.137 回答
2

我只是一个新手,但这就是我所做的,也许它可以激发灵感;-)

我从“控件”实例化主要组件并传递构建器对象,以便实例化的对象可以使用任何构建器对象(例如 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"]))
于 2011-01-10T13:12:25.380 回答
1
builder.connect_signals
({ 
   "on_window_destroy" : gtk.main_quit, 
   "on_buttonQuit_clicked" : gtk.main_quit 
})
于 2014-06-05T14:28:00.087 回答