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: 1528
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: 1275
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: 1528
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: 1389
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: 1528
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
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1153
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: 1528
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
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1153
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: 1389
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: 499
Iscrizione: novembre 2013

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda nuzzopippo » giovedì 14 dicembre 2017, 16:43

Ciao, rieccomi sull'argomento :)

Finalmente, anche se in maniera senz'altro rozza, mi è riuscito di far funzionare un sistema tipo quello indicato a @maresama nel mio precedente post, ossia un articolato di classi-finestra che comunicano tra loro tramite un oggetto di intermediazione che le possiede.

Son partito dal seguente codice di una semplice calcolatrice che ho trovato in giro:
Codice: Seleziona tutto
from tkinter import *

def frame(root, side):
    w = Frame(root)
    w.pack(side=side, expand=YES, fill=BOTH)
    return w

def button(root, side, text, command=None):
    w = Button(root, text=text, command=command)
    w.pack(side=side, expand=YES, fill=BOTH)
    return w


class Calculator(Frame):

    def __init__(self):
        Frame.__init__(self)
        self.pack(expand=YES, fill=BOTH)
        self.master.title('Semplice calcolatrice')
        self.master.iconname('calc1')

        display = StringVar()
        Entry(self, relief=SUNKEN,
              textvariable=display).pack(side=TOP, expand=YES,
                                         fill=BOTH)

        for key in ('123', '456', '789', '-0.'):
            keyF = frame(self, TOP)
            for char in key:
                button(keyF, LEFT, char,
                       lambda w=display, s='%s'%char: w.set(w.get()+s))

        opsF = frame(self, TOP)
        for char in "+-*/=":
            if char == '=':
                btn = button(opsF, LEFT, char)
                btn.bind('<ButtonRelease-1>',
                         lambda e, s=self, w=display: s.calc(w), '+')
            else:
                btn = button(opsF, LEFT, char,
                             lambda w=display, c=char: w.set(w.get()+' '+c+' '))

        clearF = frame(self, BOTTOM)
        button(clearF, LEFT, 'Clr', lambda w=display: w.set(''))

    def calc(self, display):
        try:
            display.set(eval(display.get()))
        except ValueError:
            display.set("ERRORE")
        except SyntaxError:
            display.set("ERRORE")


if __name__ == '__main__':
    Calculator().mainloop()


ed ho cercato di creare una finestra, in una classe completamente separata, che funzionasse da "lavagna" per le operazioni effettuate.
Il codice di questa classe (ho denominato il file "lavagna.py")
Codice: Seleziona tutto
from tkinter import *

class Lavagna(Toplevel):
    '''
Definisce una lavagna su cui esporre i calcoli di Calculator
'''
    def __init__(self, root=None):
        self.fin = Toplevel(root)
        self.fin.title('Calcoli effettuati')
        self.sfondo = Frame(self.fin)
        self.sfondo.pack()
        self.text =  Text(self.sfondo)
        self.text.pack()
        #self.fin.grab_set()

    def addRiga(self, testo):
        '''Aggiunge una riga di testo'''
        self.text.insert(INSERT, testo + '\n')



if __name__ == '__main__':
    Lavagna()

Ovviamente, son partito dall'esempio di @Claudio_F, quel grab_set() commentato mi ha dato filo da torcere sin quando non mi è riuscito di trovare la docs relativa nella documentazione generale dei widgets ... si prendeva in modalità esclusiva la gestione degli eventi e mi faceva impazzire per capire cosa NON succedeva :lol:

ho, quindi, creato un oggetto, che ho chiamato "Coordinator" (file coordinator.py) che sfrutta il metodo addRiga() di Lavagna per far immettere una riga di testo nell'area di testo della finestra.
Coordinator si incarica di avviare Tk e definire le finestre, il codice :
Codice: Seleziona tutto
from tkinter import *
import calculator
from lavagna import *

class Coordinator():
    '''
Coordina tra loro le classi Calculator e Lavagna, che non si conoscono
'''
    def __init__(self, radice):
        self.root = radice
        self.lav = Lavagna(self.root)
        self.calc = calculator.Calculator(self.root, self)
        self.root.mainloop()
       
    def esponi(self, testo):
        '''Trasmette a Lavagna del testo'''
        if self.lav != None:
            self.lav.addRiga(testo)



if __name__ == '__main__':
    radix = Tk()
    Coordinator(radix)


ho quindi ridefinito la calcolatrice, in maniera che conoscesse l'oggetto-padre ed ho modificato il metodo "calc" in modo che invocasse il metodo "esponi" di Coordinator, che si incarica di informare la lavagna di una nuova immissione, la funzione variata:
Codice: Seleziona tutto
    def calc(self, display):
        tmp = str(display.get())
        try:
            display.set(eval(display.get()))
        except ValueError:
            display.set("ERRORE")
        except SyntaxError:
            display.set("ERRORE")
        tmp += ' = ' + str(display.get())
        if self.pater != None:
           self.pater.esponi(tmp)


Ovviamente, coordinator viene importato dalla calcolatrice, che ne utilizza i metodi, ma non dalla lavagna che non li usa e non sa nulla della sua esistenza.
Il codice della calcolatrice modificata (ho chiamato il file "calculator.py")
Codice: Seleziona tutto
from tkinter import *
from coordinator import *

def frame(root, side):
    w = Frame(root)
    w.pack(side=side, expand=YES, fill=BOTH)
    return w

def button(root, side, text, command=None):
    w = Button(root, text=text, command=command)
    w.pack(side=side, expand=YES, fill=BOTH)
    return w


class Calculator(Frame):

    def __init__(self, master=None, pater=None):
        root = Frame.__init__(self, master)
        self.pater = pater
        self.pack(expand=YES, fill=BOTH)
        self.master.title('Semplice calcolatrice')
        self.master.iconname('calc1')

        display = StringVar()
        Entry(self, relief=SUNKEN,
                       textvariable=display).pack(side=TOP,
                                                  expand=YES,
                                                  fill=BOTH)

        for key in ('123', '456', '789', '-0.'):
            keyF = frame(self, TOP)
            for char in key:
                button(keyF, LEFT, char,
                       lambda w=display, s='%s'%char: w.set(w.get()+s))

        opsF = frame(self, TOP)
        for char in "+-*/=":
            if char == '=':
                btn = button(opsF, LEFT, char)
                btn.bind('<ButtonRelease-1>',
                         lambda e, s=self, w=display: s.calc(w), '+')
            else:
                btn = button(opsF, LEFT, char,
                             lambda w=display, c=char: w.set(w.get()+' '+c+' '))

        clearF = frame(self, BOTTOM)
        button(clearF, LEFT, 'Clr', lambda w=display: w.set(''))

    def calc(self, display):
        tmp = str(display.get())
        try:
            display.set(eval(display.get()))
        except ValueError:
            display.set("ERRORE")
        except SyntaxError:
            display.set("ERRORE")
        tmp += ' = ' + str(display.get())
        if self.pater != None:
           self.pater.esponi(tmp)



if __name__ == '__main__':
    Calculator().mainloop()


Non me ne vogliate per la rozzezza dell'esempio, ho affrontato solo un pochino Tk, giusto per capire come mai non funzionava il metodo che spesso utilizzo con Java ... inutile dire che era la mia ignoranza su pytk il problema :D ... funziona anche con tkinter, quindi integro l'indicazione già fatta tanto per meritarmi quel "grazie", quanto perché ritengo sia una modalità semplice per far comunicare finestre tra loro... Penso che utilizzare metodi di classe dia molte possibilità di iterazione.
Avatar utente
nuzzopippo
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1153
Iscrizione: ottobre 2006

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda Claudio_F » sabato 16 dicembre 2017, 14:27

nuzzopippo ha scritto:quel grab_set() commentato mi ha dato filo da torcere sin quando non mi è riuscito di trovare la docs relativa nella documentazione generale dei widgets ... si prendeva in modalità esclusiva la gestione degli eventi e mi faceva impazzire per capire cosa NON succedeva :lol:

Ah si, si parlava di dialog window, e quindi era corretto bloccare le altre finestre fino alla chiusura della dialog.

Ovviamente, coordinator viene importato dalla calcolatrice, che ne utilizza i metodi

Ecco, questo invece ha spiazzato me che cercavo di capire come/dove/quando lanciando 'calculator' poteva comparire la finestra secondaria :shy:
Ma nel codice finale quell'import non serve: a quanto vedo 'calculator' non usa nulla —direttamente— di 'coordinator', e si deve invece lanciare 'coordinator'.

Penso che utilizzare metodi di classe dia molte possibilità di interazione.

Direi che è il modo "normale" per fare interagire gli oggetti.
Ma meglio chiamarlo metodo di istanza.
Il classmethod (stile obbligato Java dove mancano le funzioni "isolate") è meno comune in Python (benché possibile attraverso l'apposito decoratore).


Per il resto ok, è un esempio, ma attenzione all'uso di 'eval', che su campi di input ad accesso libero permette code injection malevolo.

Un'altra cosa che può spiazzare è la possibilità di avviare una GUI senza istanziare una Tk esplicita (come in 'calculator' se il file viene lanciato direttamente), e poter chiamare mainloop su qualsiasi widget (come il Frame in 'calculator'). C'è qualche differenza tra i due modi di procedere che non mi è ancora chiara, ma ad esempio 'coordinator' continua a funzionare anche senza Tk:
Codice: Seleziona tutto
from tkinter import *
import calculator
from lavagna import *

class Coordinator():

    def __init__(self):
        self.lav = Lavagna()
        self.calc = calculator.Calculator(None, self)
        self.lav.fin.mainloop()
       
    def esponi(self, testo):
        '''Trasmette a Lavagna del testo'''
        if self.lav != None:
            self.lav.addRiga(testo)


if __name__ == '__main__':
    Coordinator()
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1389
Iscrizione: maggio 2012
Desktop: Unity/Mate/Gnome
Distribuzione: Ubu16.04/Mint17

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda nuzzopippo » sabato 16 dicembre 2017, 17:02

Anche se un po' OT rispetto al quesito di @maresama (ebbene si!, rileggendo e provando alla fine ho capito di aver completamente frainteso il problema di @maresama :shy: chiedo scusa), trovo l'argomento interessante

Claudio_F Immagine ha scritto:
Ovviamente, coordinator viene importato dalla calcolatrice, che ne utilizza i metodi

Ecco, questo invece ha spiazzato me che cercavo di capire come/dove/quando lanciando 'calculator' poteva comparire la finestra secondaria :shy:
Ma nel codice finale quell'import non serve: a quanto vedo 'calculator' non usa nulla —direttamente— di 'coordinator', e si deve invece lanciare 'coordinator'.


Per il primo punto : ho cercato di configurare le classi in maniera che possano funzionare in maniera indipendente dall'esistenza delle altre, mio vezzo/abitudine, calculator funziona anche da solo, senza la "lavagna" e coordinator.
Per il secondo punto, non è esatto che calculator non usa coordinator, "pater" è, appunto, un oggetto coordinator, vedi l'invocazione comparata con il costruttore di calculator
Codice: Seleziona tutto
#invocazione
self.calc = calculator.Calculator(self.root, self)
#costruttore
class Calculator(Frame):
    def __init__(self, master=None, pater=None):

e ne viene utilizzato il metodo "esponi", nella istruzione finale del metodo "calc" di calculator
Codice: Seleziona tutto
        if self.pater != None:
           self.pater.esponi(tmp)


Claudio_F Immagine ha scritto:Per il resto ok, è un esempio, ma attenzione all'uso di 'eval', che su campi di input ad accesso libero permette code injection malevolo.
...
C'è qualche differenza tra i due modi di procedere che non mi è ancora chiara, ma ad esempio 'coordinator' continua a funzionare anche senza Tk:

La prima riga citata è la cosa più interessante, come può ovviarsi ad eval? ... ovviamente, chiedo una semplice indicazione di ciò che devo andar a vedere.

Che coordinator funzionasse anche senza Tk(), lo sapevo, è stata una deliberata scelta quella di richiamarlo li, giusto per avere un punto chiaro di uscita ... ho molto da masticare su pytk e sono tutt'altro che certo di ciò che faccio, perciò le finestre chiamate usano QUEL root.

Ti ringrazio dei chiarimenti @Claudio_F

@maresama, nuovamente scusa per l'intervento fuori luogo, in genere l'unicità dei thread grafici è trasparente al programmatore, non me l'aspettavo ed ho frainteso il problema.
Avatar utente
nuzzopippo
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1153
Iscrizione: ottobre 2006

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda Claudio_F » sabato 16 dicembre 2017, 20:11

nuzzopippo ha scritto:Per il secondo punto, non è esatto che calculator non usa coordinator, "pater" è, appunto, un oggetto coordinator, vedi l'invocazione comparata con il costruttore di calculator

Appunto, il passaggio del contesto (mi piace di più context che pater ma magari è una convenzione Java) avviene tramite un parametro e non usando direttamente il modulo. In calculator l'import di coordinator non serve.

come può ovviarsi ad eval?

eval esegue il contenuto di una stringa come codice facente parte del programma, quindi la stringa deve provenire da una fonte sicura, oppure essere sanitizzata/filtrata. In questo caso banalmente prima di invocare eval si controlla che contenga solo caratteri numerici e matematici.

Che coordinator funzionasse anche senza Tk(), lo sapevo, è stata una deliberata scelta quella di richiamarlo li, giusto per avere un punto chiaro di uscita ... ho molto da masticare su pytk e sono tutt'altro che certo di ciò che faccio, perciò le finestre chiamate usano QUEL root.
tk ha ancora molto da svelare anche a me, ad esempio io sto cercando di usare grab_set su due diverse dialog, ma su una si rifiuta di funzionare.
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1389
Iscrizione: maggio 2012
Desktop: Unity/Mate/Gnome
Distribuzione: Ubu16.04/Mint17

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda melfnt » sabato 16 dicembre 2017, 21:30

Claudio_F Immagine ha scritto:
nuzzopippo ha scritto:Per il secondo punto, non è esatto che calculator non usa coordinator, "pater" è, appunto, un oggetto coordinator, vedi l'invocazione comparata con il costruttore di calculator

Appunto, il passaggio del contesto (mi piace di più context che pater ma magari è una convenzione Java) avviene tramite un parametro e non usando direttamente il modulo. In calculator l'import di coordinator non serve.



Avete un po' di ragione entrambi: Python usa il duck typing, una tecnica che consente di risolvere i tipi usati a tempo di esecuzione basandosi solamente sulla presenza o assenza di metodi.
Nel vostro esempio, per come è definito il calculator, il parametro pater può essere di qualsiasi tipo, basta che abbia il metodo esponi. Non importa caricare il modulo coordinator, né questo import avviene in maniera automatica.


come può ovviarsi ad eval?

eval esegue il contenuto di una stringa come codice facente parte del programma, quindi la stringa deve provenire da una fonte sicura, oppure essere sanitizzata/filtrata. In questo caso banalmente prima di invocare eval si controlla che contenga solo caratteri numerici e matematici.



Oppure parsando direttamente l'equazione: è più difficile da implementare ma molto più sicuro.
melfnt
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1275
Iscrizione: ottobre 2011

Re: Tkinter - Python - Interferenza tra GUI

Messaggioda nuzzopippo » domenica 17 dicembre 2017, 10:50

melfnt Immagine ha scritto:
Claudio_F Immagine ha scritto:
nuzzopippo ha scritto:Per il secondo punto, non è esatto che calculator non usa coordinator, "pater" è, appunto, un oggetto coordinator, vedi l'invocazione comparata con il costruttore di calculator

Appunto, il passaggio del contesto (mi piace di più context che pater ma magari è una convenzione Java) avviene tramite un parametro e non usando direttamente il modulo. In calculator l'import di coordinator non serve.



Avete un po' di ragione entrambi: Python usa il duck typing, una tecnica che consente di risolvere i tipi usati a tempo di esecuzione basandosi solamente sulla presenza o assenza di metodi.
Nel vostro esempio, per come è definito il calculator, il parametro pater può essere di qualsiasi tipo, basta che abbia il metodo esponi. Non importa caricare il modulo coordinator, né questo import avviene in maniera automatica.


Avevo letto dell'argomento ma non avevo compreso che arrivasse ad un tale livello, ovviamente ho verificato ... interessante, da un lato offre molte possibilità, dall'altro aumenta il rischio confondersi, comunque, progettandosi per bene il flusso del programma ...

In ogni caso, @Claudio_F, i miei "usi" NON sono convenzioni java, sono solo abitudini di un disordinato autodidatta che scrive solo per se e non per il mondo, se "qualcosa" è chiamato da un oggetto cui deve tener traccia, allora l'oggetto è "pater", nel caso sia una finestra diventa "mater", distinguo a colpo d'occhio se tratto processi gui o altro ... ma vale solo per me :D

Grazie delle info su eval, ci starò attento operativamente, in sintesi : mai passarle niente senza esserselo analizzato prima.
Avatar utente
nuzzopippo
Entusiasta Emergente
Entusiasta Emergente
 
Messaggi: 1153
Iscrizione: ottobre 2006


Torna a Programmazione

Chi c’è in linea

Visualizzano questa sezione: 0 utenti registrati e 26 ospiti