2011-01-09 2 views
3

Я обновляю некоторый код с помощью libglade до GtkBuilder, который должен быть способом будущего.pygtk gtk.Builder.connect_signals на несколько объектов?

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

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

Это ошибка, которая не позволяет подключить обработчики нескольких объектов? Или я чего-то не хватает?

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

ответ

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)) 
+0

Большое спасибо, просто и эффективно! :) – mac

2

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

Я инстанцирует основные компоненты от «контроля» и передать объект строитель так, что созданный объект может сделать использование любого из объектов-строителей (пример в главном окне) или добавление к строителю (пример 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") 
     ... 

Edit: альтернатива для автоматических присоединять сигналы обратных вызовов:
Непроверенного код

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

Благодарим за ответ. Я вижу, что это сработает, но оно повторяет имена обработчиков, которых я хотел избежать :) – poolie

+1

Я учусь, пытаясь ответить. Что-то я попробую ... назовите мои обработчики с соглашением, которое идентифицирует, какой класс ему понадобится. Затем проанализируйте файл ui, чтобы найти требуемые обработчики, или это могут быть все обработчики, если файл ui специфичен для класса. Код добавлен в мой ответ. Не уверен, что это поможет вам или нет, но я уверен, что я учусь этому.:-) – Dave

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.

-1
builder.connect_signals 
({ 
    "on_window_destroy" : gtk.main_quit, 
    "on_buttonQuit_clicked" : gtk.main_quit 
}) 
Смежные вопросы