Tkinter - Python - Interferenza tra GUI

Linguaggi di programmazione: php, perl, python, C, bash, ecc.

Tkinter - Python - Interferenza tra GUI

Messaggioda maresama » sabato 2 dicembre 2017, 0:34

Anni fa avevo chiesto al forum una spiegazione relativa al fatto che se usavo una funzione che usava un widget in una callback di un'altra funzione
con tkinter, questo non funzionava.
Mi era stato spiegato che in effetti erano due GUI complete vere e proprie e che si influenzavano l'una con l'altra. L'unico consiglio era mettere tutto
sotto la stessa istanza di tkinter. E il bravissimo Claudio mi aveva fatto anche un esempio.
Penso che sia tutto giusto e cerco di adeguarmi.
Però mi spiace di non poter usare delle funzioni fatte già per particolari problemi senza doverle modificare e perdendo il grossissimo concetto di una
'funzione' vista come soluzione asettica di un determinato problema
Cosa invece perfettamente valida in Python: scatole chiuse con dati in entrata e dati in uscita. Cosa accade dentro è del tutto indipendente dal resto (sempre che si voglia che sia così)

Però ho un dubbio: forse c'è qualche altra soluzione.
La mia perplessità nasce dalla constatazione che se nelle callback uso Tkmessagebox, tkFileDialog e analoghi va tutto bene (mai avuto problemi).
Eppure sono delle GUI complete vere e proprie anche loro....
D'altra parte se io nella callback (l'ho fatto per prova) chiamo un programma dove eseguo quella funzione e mi faccio restituire il risultato. va tutto bene (in pratica il programma emula la funzione)
Forse mi sfugge qualcosa o mi preoccupo di qualcosa che forse interessa pochi.
Ma sono curioso... molto curioso... e questo forse il mio vero problema.
Mi piacerebbe proprio capire come hanno fatto in Tkmessagebox e simili!.
Grazie.
maresama
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1463
Iscrizione: gennaio 2008

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda melfnt » sabato 2 dicembre 2017, 19:41

Ciao! Così, senza esempi non sono riuscito a capire bene il problema: potresti postare il codice non funzionante su tkinter, e magari quello funzionante sulle altre GUI?

Grazie :)
melfnt
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1188
Iscrizione: ottobre 2011

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda maresama » domenica 3 dicembre 2017, 23:27

E' difficile ricostruire il problema ma ci provo:
Le due funzioni che riporto sono solo quale esempio, sono incomplete e forse senza senso: sono solo per far capire quello che dico.
Lanciando la prima funzione (zzz) si ottiene il risultato giusto (indice +1) della riga scelta
Questo solo a dimostrazione che la funzione zzz va bene
Lanciando la seconda funzione (xxx) e premendo scelte viene preso il terzo elemento e messo nella casella scelte. E anche questo va tutto bene
Ora ripetiamo il secondo lancio ma attiviamo la funzione zzz, la quale ci darà il numera scelta in sostituzione di quello impostato prima della disattivazione
Dovrebbe funzionare tutto come prima (w=3 prima volta e w=scelta la volta dopo). Ma tutto non va come prima. le due funzioni si influenzano (sarà per il clima rigido? .... in inverno l'influenza c'è sempre!)
Devo dire che questo è il caso più semplice e meno fastidioso, ma non è sempre cosi.
Come detto se anzichè la funzione zzz uso un programma esterno sempre con la funzione zzz e che mi restituisce la scelta fatta, va tutto bene (uguale a w preimpostato della prima volta). Quindi il problema non è l'uso delle due funzioni, ma l'uso contemporaneo di esse nello stesso programma

Codice: Seleziona tutto
def xxx (dipt=[""],ipt=[""],tit="",lu=30,mis=11, scelte=[]):
   global rc2
   def onSelEx():  master.quit()
   def evesc():    sys.exit()
   def evescir(x): master.quit()
   def re_entry2_fields():
       global rc2
       print 551
       w=3
#             w=zzz(scelte)              # zzz da attivare per la seconda prova   w non sarà piu 3 ma il risultato di zzz     
       print w,552
       val=scelte[w-1]
       print val,553
       ent[0].delete(0,END); ent[0].insert(0,val); ent[0].icursor=0
       ct[0]=0; ent[0].focus_set();
#----
   master = Tk()
   master.title(tit)
   rc2=""
   fnt=("Courier", mis,"bold"); fnb=("Roman", 10,"bold")
   w="....:....1....:....2....:....3....:....4....:....5....:....6....:....7....:....8....:....9....:....0"
   uso2=""
   while len(dipt)<len(ipt):dipt.append("")
   xr=2; ent=[]
   label1 = Label(master,text=w[0:lu],fg="#0000FF",font=fnt); label1.grid(row=xr,column=1); xr+=1
   ct=[0]; nc=0
   for nc,x in enumerate(ipt):
       xd=""
       if nc<len(dipt): xd=dipt[nc];#xco=tel[nc]; # xd=xd+" "*(lmx-len(xd))    #xcoe=teli[nc];
       lb=Label(master, text=xd, justify="left", font=fnt); lb.grid(row=nc+1+xr,column=0,ipadx=4)
       w=Entry(master)
       if nc==0: w.focus_set()
       ent.append(w)
       ent[nc].insert(lu,ipt[nc].encode('utf-8')); ent[nc].grid(row=nc+1+xr,column=1); ent[nc].config(width=lu, font=fnt,bg="#F6F7EE")
       nc+=1;   w.icursor(0)
       ipt[nc-1]=""
   master.protocol("WM_DELETE_WINDOW", onSelEx)                                   # conferma per exit
   master.bind('<Down>',lambda e: evescir2(1))
   master.bind('<Up>',lambda e: evescir2(-1))
   master.bind('<Return>',lambda e: master.quit())
   master.bind('<Escape>',lambda e: evesc())
   Button(master, text=' OK (=invio)',font=fnb, command=master.quit,bg="#D5FDD5").grid(row=nc+1+xr, column=2, sticky=W,pady=4,padx=12)
   if scelte <> []: nc+=1; Button(master, text="Scelte...",font=fnb,  command=re_entry2_fields,bg="#F8C7FA").grid(row=nc+1+xr, column=0, sticky=W, pady=4)
   if len(ipt)==1: master.bind('<Return>',lambda e: master.quit())
   mainloop( )
   return rc2

def zzz(sce):
   global rc
   def onSelect(ev):                                     
       global rc
       select=listb.get(listb.curselection())         
       lab.configure(text=select)                     
       rc=sce.index(select)+1
       root.destroy()
   rc=0
   root=Tk()
   listb=Listbox(root, width=30, height=4); listb.pack()
   lab=Label(root,text="Doppio Click sulla Voce"); lab.pack()
   for c in sce: listb.insert(END,c)
   listb.bind('<Double-1>',onSelect)                     
   root.mainloop()
   return rc


ipt=["aaaa","bbbb"]
sce=["aa","bb","cc"]

rc=zzz(sce)
print rc                                     
# zzz restituisce il giusto valore (numero di scelta fatta a partire da 1)- zzz funziona correttamente

# ora in xxx vado su scelta uno e premo scelte:
# nella callback chiamo zzz
# quel che accade non è quello che ci si aspetta
a=xxx (dipt=["prova"],ipt=ipt,tit="",lu=30,mis=11, scelte=sce)
print a



Spero di essermi spiegato (non è mai facile farlo.....)
Ripeto: le funzioni sono incomplete ed inesatte: sono valide solo per l'esempio!
maresama
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1463
Iscrizione: gennaio 2008

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda Claudio_F » lunedì 4 dicembre 2017, 19:18

Immagino che Il problema dipenda dal fatto che entrambe quelle funzioni creano una GUI da zero completa e indipendente "come se fosse l'unica", mentre in un'applicazione con tk il mainloop deve essere uno solo per tutte le finestre. E immagino che questa sia stata la risposta nella discussione precedente, che sarebbe utile ritrovare.

Le dialog box *non* creano ciascuna una nuova istanza di tk, ma funzionano come finestre secondarie.

Qui dovrebbe esserci tutto quello che serve:
effbot.org/tkinterbook/tkinter-dialog-windows.htm
(purtroppo informazioni come queste in italiano non ne ho mai trovate)
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1323
Iscrizione: maggio 2012
Desktop: Unity/Mate/Gnome
Distribuzione: Ubu16.04/Mint17

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda maresama » lunedì 4 dicembre 2017, 20:16

A parte il discorso delle dialog box la risposta che mi avevi data era simile a questa nuova.
Dici che le dialog box usano una finestra secondaria.... Però fanno esattamente quello che vorrei fare io.
Però non ho chiaro cosa intendi per una finestra secondaria.
Premesso che io se le uso non modifico niente della mia funzione che le chiama, come potrei fare per ottenere lo stesso risultato con una mia funzione?
E'possibile?

ps: Sei sempre molto gentile e disponibile. Grazie !
maresama
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1463
Iscrizione: gennaio 2008

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda nuzzopippo » martedì 5 dicembre 2017, 6:31

maresama Immagine ha scritto:Premesso che io se le uso non modifico niente della mia funzione che le chiama, come potrei fare per ottenere lo stesso risultato con una mia funzione?
E'possibile?


Se il problema è solo quello di far dialogare finestre costruite in modo indipendente, potresti provare ad utilizzare un approccio tramite le classi, in java ho realizzato dialoghi, in genere semplici ma anche complessi, tra finestre indipendenti prevedendo appositi metodi pubblici nella definizione di classe e poi definendo un oggetto che "possedeva" le finestre interessate (quali variabili) e che si occupava di controllare e smistare il traffico dati, ovviamente tramite metodi pubblici.
Naturalmente, l'oggetto "contenitore" era a sua volta variabile delle classi/GUI.

In python sono ancora troppo lontano per idee valide, mi limito, perciò, ad indicare l'approccio sopra :D

[Edit] Dimenticavo, variante che ho usato a volte è stata quella del rapporto Madre <=> Figlia, classi con metodi pubblici come sopra ma il contenitore" era una finestra che possedeva come variabili le finestre figlie occorrenti ed era conosciuta, come variabile, da esse,
[Ri-Edit] guardando il codice nel link postato da @claudio_F, l'oggetto "contenitore" da me indicato non è altro che il "parent" della dialog, solo conosciuto come oggetto e metodi pubblici ;)
Avatar utente
nuzzopippo
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 996
Iscrizione: ottobre 2006

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda maresama » martedì 5 dicembre 2017, 18:52

Grazie.... come al solito!
Ciao
maresama
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1463
Iscrizione: gennaio 2008

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda nuzzopippo » mercoledì 6 dicembre 2017, 8:52

maresama Immagine ha scritto:Grazie.... come al solito!


Se rivolto a me, il grazie è abbondantemente immeritato :shy:
Ieri sera ho voluto provare il metodo da me utilizzato spesso in java (oggetto padre e finestre figlie) con pytk solo per verificare che Tk() è un thread singolo bloccante, la metodologia non va, anche riuscendo ad aggirare il blocco alla costruzione della prima finestra gli effetti sono sconcertanti : le istruzioni per la costruzione di due distinte finestre vengono fusi in una.
Resta da vedere cosa succederebbe con la costruzione di eventuali oggetti di finestre figlie, mi sa che mie precedenti esperienze con altri ambienti grafici non abbiano poi molto in comune con TK.
Avatar utente
nuzzopippo
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 996
Iscrizione: ottobre 2006

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda Claudio_F » mercoledì 6 dicembre 2017, 21:27

Il problema fondamentale del codice di maresama credo sia il fare questo:
Codice: Seleziona tutto
try:                import Tkinter as tk
except ImportError: import tkinter as tk
###-------------------------------------------------
def funz():
    win2 = tk.Tk()
    lab1 = tk.Label(win2, text='second window')
    lab1.pack(padx=100, pady=100)
    win2.mainloop()
###-------------------------------------------------
root = tk.Tk()
bt1 = tk.Button(root, text='click-me', command=funz)
bt1.pack(padx=100, pady=100)
root.mainloop()

Invece di questo:
Codice: Seleziona tutto
try:                import Tkinter as tk
except ImportError: import tkinter as tk
###-------------------------------------------------
def funz():
    win2 = tk.Toplevel(root)
    win2.transient(root)
    lab1 = tk.Label(win2, text='second window')
    lab1.pack(padx=100, pady=100)
    win2.grab_set()
###-------------------------------------------------
root = tk.Tk()
bt1 = tk.Button(root, text='click-me', command=funz)
bt1.pack(padx=100, pady=100)
root.mainloop()

Va da sè che in questo secondo caso funz non funziona senza un'istanza di Tk (cioè root) già attiva.
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1323
Iscrizione: maggio 2012
Desktop: Unity/Mate/Gnome
Distribuzione: Ubu16.04/Mint17

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda ixamit » mercoledì 6 dicembre 2017, 23:30

Aggiungo che e' una filosofia comune e non valida solo per X11.
Le finestre sono gestite gerarchicamente, dove le top-level sono figlie di root (per analogia come tutti i processi sono figli di init).
Le top-level possono interagire con il WM di turno per la gestione e l'aspetto della "cornice".

Le ulteriori (sotto-)finestre (o widget) diventano a loro volta figlie alimentando cosi' l'albero genealogico.
La vera root window è sempre e solo UNA, dove il parent id e' zero.

$ xwininfo -root -children
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
 
Messaggi: 498
Iscrizione: novembre 2013


Torna a Programmazione

Chi c’è in linea

Visualizzano questa sezione: 0 utenti registrati e 3 ospiti