Newsgroup: it.comp.os.linux.development
Titolo: TreeView, segnali emessi

Sto lavorando un po' con i Treview, in particolare sto portando del 
codice che avevo scritto con le vecchie GTK1.2 usando CList e CTree. Mi 
sono imbattuto in un problemino che non ho capito come risolvere.
Ho bisogno di sapere quando una riga viene selezionata, e anche di 
prendere il valore contenuto in una cella della riga selezionata. Per 
quanto riguarda il grabbing del valore non ci sono particolari problemi,
uso il metodo get_selection, il problema sta nel segnale.
I vecchi CTree e CList emettevano il segnale select_row e 
tree_select_row che fanno esattamente cio' che voglio. 
Con i TreeView non sono riuscito a trovare qualcosa di analogo, ci 
sarebbe il segnale row_activated, ma questo pero' viene emesso solo 
quando si fa un doppio click su una riga oppure si preme la barra 
spaziatrice su una riga gia selezionata.
Oppure ci sarebbe anche il segnale select_cursor_row che a leggere la 
descrizione potrebbe andare bene, ma non reagisce in alcun modo ai click
col mouse, il segnale viene emesso anche in questo caso quando viene 
premuta la barra spaziatrice.
Insomma in poche parole ... non c'e' un modo per sapere quando una riga 
di un TreeView viene selezionata?
-- 
 |\ |       |HomePage   : 
http://nem01.altervista.org
 | \|emesis |XPN (my nr): 
http://xpn.altervista.org

 uso il metodo get_selection, il problema sta nel segnale.
Il trucco sta nel fatto che esistono più classi che fanno un lavoro
solo, invece di una classe che fa tutto il lavoro. ;-)
 
	def on_row_selected (selection):
		(model, iter) = selection.get_selected
		path = model.get_path(iter)
		print "Hi! I'm a new selection at path %s" % path
 
	s = treeview.get_selection()
	s.connect('changed', on_row_selected)
[codice non testato: sono partito dall'equivalente Perl]
Ciao,
 Emmanuele.
-- 
Emmanuele Bassi (Zefram)                 [ 
http://www.emmanuelebassi.net
 ]
GnuPG Key fingerprint = 4DD0 C90D 4070 F071 5738  08BD 8ECC DB8F A432 0FF4

[codice non testato: sono partito dall'equivalente Perl]
Non va! Andiamo con ordine. Nel frattempo ho fatto altre prove ed ho 
trovato che probabilmente il segnale "cursor-changed" fa al caso mio. Lo
connetto, pero' mi accorgo di un piccolo problemino la prima volta che 
seleziono una riga col click del mouse in realta' mi partono due 
segnali, il primo dei quali in realta' parte come se la riga 
selezionata fosse la prima, il secondo invece parte quando la riga e' 
quella giusta. Se invece uso uno short-cut da tastiera che mi fa un 
cursor-set, tutto funziona correttamente. Ah, una volta selezionata una 
riga per ogni successiva riga che seleziono col mouse ricevo giustamente
un unico segnale.
La tua soluzione si comporta esattamente nello stesso modo! :-/
Any idea?


URL:
http://developer.gnome.org/doc/API/2.0/gtk/GtkTreeSelection.html#GtkTreeSelection-changed
Attacchi un callback a quel segnale, e hai la selezione che è cambiata;
da quella, come ho scritto, puoi recuperare modello e iteratore. A quel
punto è facile fare quello che vuoi.
Come dice la documentazione, però:
| One of the important things to remember when monitoring the selection
| of a view is that the "changed" signal is mostly a hint. That is, it may
| only emit one signal when a range of rows is selected. Additionally, it
| may on occasion emit a "changed" signal when nothing has happened
| (mostly as a result of programmers calling select_row on an already
| selected row).
Quindi, attenzione. Potresti usare una variabile di lock che memorizza
il path selezionato, e se è lo stesso, esce dalla funzione.


 il path selezionato, e se è lo stesso, esce dalla funzione.
Il problema non è quello.
Quando clicchi per la prima volta sul TreeView,anche in un riga non
riempita, questo prende il focus e seleziona la prima riga (e ti parte
anche il segnale). Se tu clicchi su una riga non vuota che non sia la
prima, il segnale ti parte nel momento in cui il TreeView prende il focus,
e poi te ne parte un altro nel momento in cui la riga su cui hai cliccato
diviene selezionato. In questo modo ti partono due segnali con un solo
click. Una soluzione barbara e' quella di usare un contatore di quante
volte la corrispondente callback viene chiamata e di evitare di entrare
nel corpo della callback al primo incremento del contatore. Questa
soluzione risolve il problema, pero' ne introduce un altro, come ho
anticipato uso anche uno shortcut da tastiera che mi effettua un
set_cursor sul path+1, oppure sul primo path se nulla e' selezionato, ed
in questo caso il problema del doppio segnale non si presenta, quindi
perderei una selezione.
Giusto per provare riporto un piccolo programmillo che riproduce il
problema:
import gtk
import gobject
class Prova:
    def destroy(self,widget):
        gtk.main_quit()
    def append(self,values):
        iter=self.model.append()
        for i in range(len(values)):
            self.model.set_value(iter,i,values[i])
    def print_changed(self,obj):
        model,iter=self.selection.get_selected()
        print model.get_value(iter,0),model.get_value(iter,1)
    def __init__(self):
        self.win=gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.win.connect("destroy",self.destroy)
        self.model=gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self.lista=gtk.TreeView(self.model)
        text_renderer=gtk.CellRendererText()
        column1=gtk.TreeViewColumn("Colonna 1",text_renderer,text=0)
        column2=gtk.TreeViewColumn("Colonna 2",text_renderer,text=1)
        self.lista.append_column(column1)
        self.lista.append_column(column2)
        self.select_counter=0
        self.selection=self.lista.get_selection()
        self.selection.connect("changed",self.print_changed)
        self.win.add(self.lista)
        self.win.show_all()
        #inserisco qualche riga
        self.append(("1","2"))
        self.append(("3","4"))
        self.append(("5","6"))
        self.append(("7","8"))
prova=Prova()
gtk.mainloop()


On Tue, 02 Dec 2003 20:04:07 +0000, Nemesis wrote:
[megacut]
Giusto un aggiornamento per dire che ho risolto il problema ... o meglio
l'ho aggirato. Ho deciso di usare il segnale row_activated, questo anche
perche' usando "changed" sul treview, a parte i problemi esposti nei
precedenti post, avevo altre situazioni che non mi piacevano. In
particolare il segnale viene emesso anche se sposto la selezione con le
freccette della tastiera (giustamente), ed io volevo evitare questa
situazione. Per emettere row_activated bisogna invece premere la barra o
Enter una volta che la riga e' selezionata. L'unico problema che restava
e' che tale segnale viene emesso solo con un doppio click del mouse,
mentre io volevo un singolo click. Per risolvere ho connesso il segnale
"button_release_event" e la callback esegue un row_activate. 
A questo punto direi che resto con questa soluzione. In definitiva ho
dovuto fare un casotto per replicare il comportamento che con i cTree
ottenevo semplicemente connettendo selected_row ... saranno anche evoluti
ma a me sti TreeView continuano a non convincermi.


 ma a me sti TreeView continuano a non convincermi.
Sta tutto in quello che vuoi fargli fare. C'è meno roba precotta,
sicuramente.


sicuramente.
Ecco appunto, abbiamo un modello piu' potente e flessibile, ma 
paradossalmente per fare quello che prima si faceva in modo banale con i
cTree cList bisogna adottare soluzioni generalmente piu' complesse.
