我正在使用libglade更新一些代码到GtkBuilder,这应该是未来的方式。
使用gtk.glade,您可以反复调用glade_xml.signal_autoconnect(...)
将信号连接到与程序中不同窗口对应的不同类的对象上。但是Builder.connect_signals
似乎只工作一次,并且(因此)对任何未在传入的第一个类中定义的处理程序发出警告。
我意识到我可以手动连接它们,但这看起来有点费力。 (或者就此而言,我可以使用一些getattr hackery让它通过代理将它们连接到所有对象......)
这是一个错误,没有功能可以跨多个对象连接处理程序吗?或者我错过了什么?
其他人有类似的问题http://www.gtkforums.com/about1514.html,我认为这意味着无法做到这一点。
答案 0 :(得分: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))
答案 1 :(得分: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声明的别名方法名称。有关如何执行此操作的示例,请参阅def dict_from_callback_obj
处的Builder.py代码。
答案 2 :(得分:2)
我只是一个新手,但这就是我所做的,也许它可以启发;-)
我从'control'实例化主要组件并传递构建器对象,以便实例化对象可以使用任何构建器对象(示例中为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"]))
答案 3 :(得分:1)
builder.connect_signals
({
"on_window_destroy" : gtk.main_quit,
"on_buttonQuit_clicked" : gtk.main_quit
})