Question

Je suis mise à jour du code de l'utilisation libglade à GtkBuilder, qui est censé être la voie de l'avenir.

Avec gtk.glade, vous pouvez appeler glade_xml.signal_autoconnect(...) à plusieurs reprises pour des signaux de connexion sur des objets de différentes classes correspondant aux différentes fenêtres du programme. Cependant semble Builder.connect_signals au travail qu'une seule fois, et (donc) pour donner des avertissements au sujet des gestionnaires qui ne sont pas définis dans la première classe qui est passé dans.

Je sais que je peux les connecter manuellement, mais cela semble un laborieux bits. (Ou pour cette matière que je pourrais utiliser une getattr pour carriole laisser les relier par un proxy pour tous les objets ...)

Est-ce un bug il n'y a pas de fonction de brancher des gestionnaires sur plusieurs objets? Ou suis-je manque quelque chose?

Quelqu'un d'autre a un problème similaire http://www.gtkforums.com/about1514.html que je suppose que ce moyen ne peut se faire.

Était-ce utile?

La solution

Voici ce que j'ai actuellement. Ne hésitez pas à utiliser, ou de suggérer quelque chose de mieux:

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

Autres conseils

Je suis à la recherche d'une solution à ce pendant un certain temps et a constaté que cela peut être fait en passant un dict de tous les gestionnaires à connect_signals.

Le module peut inspecter extraire en utilisant des méthodes inspect.getmembers(instance, predicate=inspect.ismethod Ceux-ci peuvent alors être concaténés dans un dictionnaire en utilisant d.update(d3), en faisant attention pour les fonctions en double telles que on_delete.

Exemple de code:

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)

Ce ne captera pas les noms des méthodes d'alias déclarés en utilisant @alias. Pour un exemple de la façon de le faire, voir le code pour Builder.py, à def dict_from_callback_obj.

Je ne suis qu'un novice mais c'est ce que je fais, peut-être qu'il peut inspirer ;-)

J'instancier les composants principaux d'un « contrôle » et passer l'objet constructeur afin que l'objet instancié peut utiliser l'un des objets de constructeur (de mainWindow dans l'exemple) ou ajouter au constructeur (exemple aboutDialog). Je passe aussi un dictionnaire (CIVD) où chaque composant ajoute des « signaux » à elle.
Ensuite, les « connect_signals (CIVD) » est exécutée.
Bien sûr, je dois faire quelque signal manuel de connexion lorsque je dois passer des arguments de l'utilisateur à la méthode de rappel, mais ce sont quelques-uns.

#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: alternative à l'auto attacher des signaux à callbacks:
code non testé

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 
})
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top