Pregunta

Estoy actualizando algún código de usar libglade a GtkBuilder, que se supone que es el camino del futuro.

Con gtk.glade, se podría llamar glade_xml.signal_autoconnect(...) en repetidas ocasiones a las señales de conexión en objetos de diferentes clases correspondientes a diferentes ventanas en el programa. Sin embargo Builder.connect_signals parece funcionar sólo una vez, y (por tanto) para dar advertencias sobre cualquier controlador que no están definidos en la primera clase que se pasa en.

Me doy cuenta de que puedo conectar de forma manual, pero esto parece un poco laboriosa. (O para el caso que podría utilizar algunos hackery getattr dejar que se conectan a través de un proxy para todos los objetos ...)

Es un error no hay ninguna función para conectar los controladores a través de múltiples objetos? O me estoy perdiendo algo?

Otra persona tiene un problema similar http://www.gtkforums.com/about1514.html que supongo significa que esto no se puede hacer.

¿Fue útil?

Solución

Esto es lo que tengo actualmente. Siéntase libre de usarlo, o para sugerir algo mejor:

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

Otros consejos

He estado buscando una solución a esto desde hace algún tiempo y encontrado que puede hacerse pasando un diccionario de todos los manipuladores de connect_signals.

El inspeccione módulo puede extraer métodos usando inspect.getmembers(instance, predicate=inspect.ismethod Estos pueden ser concatenados en un diccionario utilizando d.update(d3), mirando hacia fuera para funciones duplicadas como on_delete.

Ejemplo código:

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)

Esto no va a recoger nombres de los métodos de alias declaran usando @alias. Para un ejemplo de cómo hacerlo, consulte el código para Builder.py, en def dict_from_callback_obj.

Sólo soy un novato, pero esto es lo que hago, tal vez pueda inspirar ;-)

I instanciar los componentes principales de un 'control' y pasar el objeto constructor de modo que el objeto instanciado puede hacer uso de cualquiera de los objetos de ventana principal Builder (en el ejemplo) o añadir al constructor (ejemplo aboutDialog). También me pase un diccionario (DIC), donde cada componente agrega "señales" a la misma.
A continuación, se ejecuta el 'connect_signals (DIC).
Por supuesto que tengo que hacer alguna señal manual de la conexión cuando necesito para pasar argumentos de usuario con el método de devolución de llamada, pero esos son pocos.

#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")
        ...

Editar: alternativa al automóvil adjuntar señales a las devoluciones de llamada:
código no probado

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 
})
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top