On Fri, May 28, 2010 at 10:25:51AM +0200, Alessandro Dentella wrote:
> Ciao a tutti,
[...]
> Quando la finestra risulta incancellabile tramite il bottone kill, anche la
> cancellazione tramite window-manager fallisce (AttributeError: G objectc has
> no attribute 'title'). È come se la istanza 'g' sia stata resa monca 
> nonostante
> esista ancora una finestra con una callback attiva che referenzia (in senso
> forte) l'istanza stessa ed il suo metodo 'delete_event_cb'. Chiamo 'monca'
> questa istanza nel senso che:
> 
>   * la weakref non la vede più
>   * la callback capisce che è una istanza di 'G' ma non ne vede l'attributo
>     di istanza 'title'::
> 
>       Traceback (most recent call last):
>       File "testd2_win.py", line 39, in clicked_cb
>         if self.title:
>       AttributeError: 'G' object has no attribute 'title'
>   
> Conto su un vostro input per non andare in corto...

Vediamo un po' tutti i possibili problemi che possono sorgere:

1. il metodo `delete_event_cb` elimina il riferimento alla finestra ma
il metodo può essere ancora chiamato dal padre e non essendoci più
riferimenti a `self.w`...

2. gli unici riferimenti che hai agli oggetti `G` sono dei riferimenti
deboli. a questo punto credo che tu debba andare a vedere come i
riferimenti deboli siano implementati in pygtk. non sono molto preparato
qui ma sicuramente il problema è questo. Accanto a `self.windows`
affianca un'altra lista: `self.objects` con riferimenti forti, vedrai
che a questo punti non hai più di questi problemi.

per quanto ne so' la gestione dei riferimenti in pygtk è pensata per, ad
eccezione di casi particolari, potersene dimenticare. nel momento in cui
non ci sono più riferimenti python ad un oggetto gobject, questo viene
deallocato.

ps. ti allego la versione modificata.

pps. la gerarchia che crei è con soli due livelli, perché allora non usi
due classi distinte? ti allego la versione modificata

ciao
m.

import sys
import weakref
import gtk


class Father(object):

    def __init__(self):
        self.children = []
        self.objects = []
        self.w = gtk.Window()
        self.h = gtk.HBox()
        self.kill_button = gtk.Button("kill")
        self.crea_button = gtk.Button("crea %s finestre" % n)
        self.w.add(self.h)
        self.h.add(self.crea_button)
        self.h.add(self.kill_button)
        self.w.show_all()
        self.w.connect('destroy', gtk.main_quit)
        self.kill_button.connect('clicked', self.clicked_cb)
        self.crea_button.connect('clicked', self.crea_molte_finestre)

    def crea_molte_finestre(self, win, ev=None):
        for i in range(n):
            obj = Child(title=str(i))
            r = weakref.ref(obj)
            self.children.append(r)
            self.objects.append(obj)

    def clicked_cb(self, win):
        for g in self.children:
            obj = g()
            print obj
            if obj is not None:
                obj.destroy()
        del self.children[:]
        del self.objects[:]


class Child(object):

    def __init__(self, title):
        self.title = title
        self.w = gtk.Window()
        self.w.set_title(title)
        self.h = gtk.HBox()
        self.kill_button = gtk.Button("kill")
        self.crea_button = gtk.Button("Finestra %s" % title)
        self.w.add(self.h)
        self.h.add(self.crea_button)
        self.h.add(self.kill_button)
        self.w.show_all()
        self.kill_button.connect('clicked', self.destroy)

    def destroy(self, win=None):
        self.w.destroy()


if __name__ == '__main__' :
    if len(sys.argv) == 2:
        n = int(sys.argv[1])
    else:
        n = 10
    obj = Father()
    obj.w.connect('destroy', gtk.main_quit)
    try:
        gtk.main()
    except KeyboardInterrupt:
        sys.exit()
import os
import gc
import sys
import weakref
import gtk


class G(object):
    def __init__(self, title=''):
        self.windows = []
        self.objects = []
        self.title = title
        self.w = gtk.Window()
        self.w.set_title(title)
        self.h = gtk.HBox()
        self.kill_button = gtk.Button("kill")
        self.crea_button = gtk.Button(title and "Finestra %s" % title or "crea %s finestre" % n)
        self.w.add(self.h)
        self.h.add(self.crea_button)
        self.h.add(self.kill_button)
        self.w.show_all()
        self.w.connect('delete-event', self.delete_event_cb)
        self.kill_button.connect('clicked', self.clicked_cb)
        self.crea_button.connect('clicked', self.crea_molte_finestre)

    def delete_event_cb(self, win, ev=None):
        self.w.get_toplevel().destroy()
        del self.w

    def crea_molte_finestre(self, win, ev=None):
        if self.title:
            return
        for i in range(n):
            #r = G(title=str(i))
            obj = G(title=str(i))
            r = weakref.ref(obj)
            self.windows += [r]
            self.objects.append(obj)

    def clicked_cb(self, win):
        if self.title:
            self.delete_event_cb(win)
        else:
            for g in self.windows:
                if g():
                    g().delete_event_cb(None, None)
                #if g:  # se non usi weakref
                #    g.delete_event_cb(None, None)
            self.windows = []
            del self.objects[:]


if __name__ == '__main__' :

    if len(sys.argv) == 2:
        n = int(sys.argv[1])
    else:
        n = 10
    obj = G()
    obj.w.connect('destroy', gtk.main_quit)
    try:
        gtk.main()
    except KeyboardInterrupt:
        sys.exit()
_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a