pygtk gtk.builder.connect_signalsは複数のオブジェクトに?
-
08-10-2019 - |
質問
Libgladeを使用してGtkbuilderに至るまでのコードを更新しています。
GTK.Gladeを使用すると、電話をかけることができます glade_xml.signal_autoconnect(...)
プログラム内の異なるウィンドウに対応するさまざまなクラスのオブジェクトに信号を接続するために繰り返し。でも Builder.connect_signals
一度だけ動作しているようで、(したがって)渡されたファーストクラスで定義されていないハンドラーについて警告を出すようにします。
私はそれらを手動で接続できることに気づきましたが、これは少し面倒なようです。 (または、そのことについては、Getattrハッカーを使用して、すべてのオブジェクトにプロキシを介してそれらを接続できるようにすることができます...)
複数のオブジェクトにハンドラーを接続する機能がないバグですか?それとも私は何かが足りませんか?
他の誰かが同様の問題を抱えています http://www.gtkforums.com/about1514.html これは、これができないことを意味します。
解決
これが私が現在持っているものです。お気軽に使用するか、より良いものを提案してください:
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))
他のヒント
私はしばらくの間、これの解決策を探していましたが、すべてのハンドラーの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
.
私は初心者だけですが、これは私がしていることです、多分それはインスピレーションを与えることができます;-)
「コントロール」から主要なコンポーネントをインスタンス化し、ビルダーオブジェクトを渡して、インスタンス化されたオブジェクトがビルダーオブジェクト(例のmainWindow)を使用したり、ビルダーに追加したりすることができるようにします。また、各コンポーネントが「信号」を追加する辞書(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"]))
builder.connect_signals
({
"on_window_destroy" : gtk.main_quit,
"on_buttonQuit_clicked" : gtk.main_quit
})