risolto - proiezione foto con transizione inaccettabile

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
maresama
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1640
Iscrizione: mercoledì 9 gennaio 2008, 16:00

risolto - proiezione foto con transizione inaccettabile

Messaggio da maresama »

per gestire le mie foto sto facendo una funzione utilizzabile in due modi:
1 - singola foto (tempo=0) con visualizzazione di tasti decisionali
questa parte va abbastanza bene (anche se è da rivedere e devo fare la parte utilizzo)
2 - foto in sequenza (tempo>0) con proiezione a tempo
questa parte va ma ha un problema che non riesco a risolvere: tra una foto e l'altra compare, anche se
per breve tempo, la scrivania. Naturalmente questo disturba moltissimo la visione
Vorrei un vostro aiuto per:
a - avere il passaggio da una foto all'altra in modo istantaneo (un sistema più efficiente dal mio)
b . in alternativa avere uno sfondo nero anzichè la scrivania
forse non c'è soluzione, ma io spero sempre.... grazie. ( non vorrei gettare tutto il lavoro nel cestino...)

Codice: Seleziona tutto


def FOTO (tempo,ft,b1="",b2="",b3="",b4="",b5="",b6="",q="4",r=.9,tst="E",root=""):
#    tempo    : 0: visualizzazione singola foto, > 0  proiezione (tempo: da 2 in su)     
#    ft       : percorso foto da visualizzare  
#    b1       : etichetta eventuale bottone scelta 
#    b2...b6  : eventuali altri bottoni scelta
#    q        : qualità:  1=NEAREST    2=BILINEAR   3=BICUBIC   4=ANTIALIAS 
#    r        : coefficente riduzione (1=1:1   .5 metà    2=doppio)
#    tst      : opzioni= 'E' attiva tasto Escape,  'F' full screen + attivazione Escape  
# << PYscelta : exit   "+","-","I","F","=","",b1,...b6, "E"     
# è necessario installare Python-imaging e Python-imaging-tk 
# richiede: from PIL import Image, ImageTk, ImageFilter

    PYscelta=[""]
    def seclikE(x): seclikUN("E")   # escape
    def seclikF(x): seclikUN("F")   # fine (End)
    def seclikI(x): seclikUN("I")   # Inizio (home)
    def seclikD(x): seclikUN("+")   # pag. giu
    def seclikP(x): seclikUN("-")   # pag. su
    def seclikR(x): seclikUN("=")   # return (invio)
    def seclik1():  seclikUN(b1)    # bottone 1
    def seclik2():  seclikUN(b2)    # bottone 2   ecc.
    def seclik3():  seclikUN(b3)
    def seclik4():  seclikUN(b4)
    def seclik5():  seclikUN(b5)
    def seclik6():  seclikUN(b6)
#
    def seclikUN(z):
      PYscelta[0]=z
      print 77,PYscelta
      root.destroy()
    def cl1(xx): root.quit()
#
    if "F" in tst: tst+="E"           # se Full screen attiva Escape
#                                     gestione foto  
    ftw = Image.open(ft)
    a= ftw.size; ww=a[0]; hh=a[1]
    if hh>ww:r=r*0.62                                                 # foto verticale
    rp=970.00/ww
    r=r*rp
    ww=int(ww*r); hh=int(hh*r)
    if   q=="4":ftw = ftw.resize((ww, hh), Image.ANTIALIAS)           # best down-sizing filter
    elif q=="3":ftw = ftw.resize((ww, hh), Image.BICUBIC)             # cubic spline interpolation in a 4x4 environment
    elif q=="2":ftw = ftw.resize((ww, hh), Image.BILINEAR)            # linear interpolation in a 2x2 environment
    else:       ftw = ftw.resize((ww, hh), Image.NEAREST)             # use nearest neighbour
    try:
      if root <> "": root.destroy()       # foto precedente persistente                        
    except: pass         
#
    root = Tk()
    root.title(ft)
    if "E" in tst and "F" in tst: root.attributes('-fullscreen', True)
    ftw = ImageTk.PhotoImage(ftw)                            #converte
    wv = ftw.width(); hv = ftw.height()
    x=y=0                                                    #shift 
    root.geometry("%dx%d+%d+%d" % (wv, hv, x, y))
    panel1 = Label(root, image=ftw)
    panel1.pack(side='top', fill='both', expand='yes')
    if b6<> "": button6 = Button(panel1,text=b6, command=seclik6).pack(side='bottom',anchor="se")
    if b5<> "": button5 = Button(panel1,text=b5, command=seclik5).pack(side='bottom',anchor="se")
    if b4<> "": button4 = Button(panel1,text=b4, command=seclik4).pack(side='bottom',anchor="se")
    if b3<> "": button3 = Button(panel1,text=b3, command=seclik3).pack(side='bottom',anchor="se")
    if b2<> "": button2 = Button(panel1,text=b2, command=seclik2).pack(side='bottom',anchor="se")
    if b1<> "": button1 = Button(panel1,text=b1, command=seclik1).pack(side='bottom',anchor="se")
    root.bind('<End>',seclikF)                    # predefiniti
    root.bind('<Home>',seclikI)       
    root.bind('<Next>',seclikD)       
    root.bind('<Prior>',seclikP)       
    root.bind('<Return>',seclikR)       
    if "E" in tst: root.bind('<Escape>',seclikE)       
    panel1.image = ftw
    if tempo > 0:                          # proiezione temporizzata
       PYscelta=[""]
       action2=lambda nn=1:cl1(1000)
       root.after(int(tempo*1000),action2)    # per la gestione a tempo
       root.mainloop()
       try:  root.update()                    # per ridurre l'intervallo tra le due foto
       except: PYscelta=["E"] 
    else:
       root.mainloop()                        # visualizzazione di una foto
    return PYscelta[0], root 
####


listaft=[.....]     # lista foto jpg
xx=""
n=0
while n < len(listaft):
    ftx=PYfile[n]
    tempo=3
    z,xx=FOTO(tempo,ftx,b1="bottone 1",b2="bottone 2",r=1.2,tst="E",root=xx)
    print z
    if z=="E": sys.exit()
    n+=1
    if n>8: sys.exit()    # blocco di sicurezza per le prove

Ultima modifica di maresama il mercoledì 27 maggio 2015, 18:54, modificato 1 volta in totale.
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: Python - proiezione foto con transizione inaccettabile

Messaggio da Claudio_F »

Il problema è fondamentalmente di design: stai usando una GUI in modo procedurale come se fosse una singola funzione da richiamare "one shot", continuando a quittare/destroyare la root ad ogni giro.

Invece il mainloop deve rimanere *sempre* attivo, ed è lui che deve comandare l'avanzamento del programma tramite chiamate ai gestori degli eventi, in questo modo basta (ri)assegnare una nuova immagine alla label per vederla cambiare istantaneamente.
maresama
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1640
Iscrizione: mercoledì 9 gennaio 2008, 16:00

Re: Python - proiezione foto con transizione inaccettabile

Messaggio da maresama »

Ho provato a cambiare (brutalmente) la funzione per gestire una lista anzichè una singola foto

Codice: Seleziona tutto

def FOTO (tempo,ftt,b1="",b2="",b3="",b4="",b5="",b6="",q="4",r=.9,tst="E"):
#    tempo    : 0: visualizzazione singola foto, > 0  proiezione (tempo: da 2 in su)     
#                                     lista    ft       : percorso foto da visualizzare  
#    b1       : etichetta eventuale bottone scelta 
#    b2...b6  : eventuali altri bottoni scelta
#    q        : qualità:  1=NEAREST    2=BILINEAR   3=BICUBIC   4=ANTIALIAS 
#    r        : coefficente riduzione (1=1:1   .5 metà    2=doppio)
#    tst      : opzioni= 'E' attiva tasto Escape,  'F' full screen + attivazione Escape  
# << PYscelta : exit   "+","-","I","F","=","",b1,...b6, "E"     
# è necessario installare Python-imaging e Python-imaging-tk 
# richiede: from PIL import Image, ImageTk, ImageFilter
 
    PYscelta=[""]
    def seclikE(x): seclikUN("E")   # escape
    def seclikF(x): seclikUN("F")   # fine (End)
    def seclikI(x): seclikUN("I")   # Inizio (home)
    def seclikD(x): seclikUN("+")   # pag. giu
    def seclikP(x): seclikUN("-")   # pag. su
    def seclikR(x): seclikUN("=")   # return (invio)
    def seclik1():  seclikUN(b1)    # bottone 1
    def seclik2():  seclikUN(b2)    # bottone 2   ecc.
    def seclik3():  seclikUN(b3)
    def seclik4():  seclikUN(b4)
    def seclik5():  seclikUN(b5)
    def seclik6():  seclikUN(b6)
#
    def seclikUN(z):
      PYscelta[0]=z
      print 77,PYscelta
      root.destroy()
    def cl1(xx): root.quit()
#
    if "F" in tst: tst+="E"           # se Full screen attiva Escape
#                                     gestione foto  

    root = Tk()
    root.title("ft")

    for ft in ftt:

        ftw = Image.open(ft)
        a= ftw.size; ww=a[0]; hh=a[1]
        if hh>ww:r=r*0.62                                                 # foto verticale
        rp=970.00/ww
        r=r*rp
        ww=int(ww*r); hh=int(hh*r)
        if   q=="4":ftw = ftw.resize((ww, hh), Image.ANTIALIAS)           # best down-sizing filter
        elif q=="3":ftw = ftw.resize((ww, hh), Image.BICUBIC)             # cubic spline interpolation in a 4x4 environment
        elif q=="2":ftw = ftw.resize((ww, hh), Image.BILINEAR)            # linear interpolation in a 2x2 environment
        else:       ftw = ftw.resize((ww, hh), Image.NEAREST)             # use nearest neighbour
        if "E" in tst and "F" in tst: root.attributes('-fullscreen', True)
        ftw = ImageTk.PhotoImage(ftw)                            #converte
        wv = ftw.width(); hv = ftw.height()
        x=y=0                                                    #shift 
        root.geometry("%dx%d+%d+%d" % (wv, hv, x, y))
        panel1 = Label(root, image=ftw)
        panel1.pack(side='top', fill='both', expand='yes')
        if b6<> "": button6 = Button(panel1,text=b6, command=seclik6).pack(side='bottom',anchor="se")
        if b5<> "": button5 = Button(panel1,text=b5, command=seclik5).pack(side='bottom',anchor="se")
        if b4<> "": button4 = Button(panel1,text=b4, command=seclik4).pack(side='bottom',anchor="se")
        if b3<> "": button3 = Button(panel1,text=b3, command=seclik3).pack(side='bottom',anchor="se")
        if b2<> "": button2 = Button(panel1,text=b2, command=seclik2).pack(side='bottom',anchor="se")
        if b1<> "": button1 = Button(panel1,text=b1, command=seclik1).pack(side='bottom',anchor="se")
        root.bind('<End>',seclikF)                    # predefiniti
        root.bind('<Home>',seclikI)       
        root.bind('<Next>',seclikD)       
        root.bind('<Prior>',seclikP)       
        root.bind('<Return>',seclikR)       
        if "E" in tst: root.bind('<Escape>',seclikE)       
        panel1.image = ftw
        root.mainloop()
    return PYscelta[0], root 
#################### > 025 +    428102 +    169440 #################### FOTO
Il primo problema è che non ho capito come visualizzare la foto se mainloop è alla fine del ciclo
E' la conferma della mia scarsa comprensione di Tkinter!
Avevo l'idea anche io che le continue chiamate non erano una soluzione giusta, ma non ho mai pensato che si potesse fare il cambio immagine nel loop stesso. Ho sempre pensato che l'immagine apparisse solo al momento del mainloop,

Come ho fatto la modifica mainloop è per ogni foto. Ma anche così al cambio foto non mi visualizza la seguente.
Errore:
RuntimeError: Too early to create image
Exception AttributeError: "PhotoImage instance has no attribute '_PhotoImage__photo'" in <bound method PhotoImage.__del__ of <PIL.ImageTk.PhotoImage instance at 0x7f096733d128>> ignored

Se puoi consigliarmi ancora, ti sarei grato (anche perchè da te le soluzioni sono anche molto istruttive!)
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: Python - proiezione foto con transizione inaccettabile

Messaggio da Claudio_F »

Avevo l'idea anche io che le continue chiamate non erano una soluzione giusta, ma non ho mai pensato che si potesse fare il cambio immagine nel loop stesso. Ho sempre pensato che l'immagine apparisse solo al momento del mainloop,
Come ho fatto la modifica mainloop è per ogni foto. Ma anche così al cambio foto non mi visualizza la seguente.
Riguarda sempre il design, se insisti a fare il ciclo "a mano" tramite un for non se ne viene fuori. Una GUI è event driven, le cose si fanno solo quando le comanda il mainloop, tra queste cose ovviamente c'e` la possibilita` di impostare un timer per chiamare una funzione dopo un certo tempo (root.after(tempo, funzione)), e la funzione può riavviarsi continuamente impostando un nuovo timer.

In particolare una struttura di base (che in questo caso stampa solo i nomi a terminale) può essere questa:

Codice: Seleziona tutto

import Tkinter as tk

#------------------------------------------------------------------------------

def photo_slider(nomi_foto, tempo=0):


    def cambia_foto(direzione):
        nome = ciclatore.prossimo(direzione)
        print nome


    def richiama():
        cambia_foto(1)
        root.after(int(tempo*1000), richiama)


    root = tk.Tk()
    root.bind('<Escape>', lambda evt: root.destroy())   # fine
    root.bind('<Next>',   lambda evt: cambia_foto(1))   # avanti
    root.bind('<Prior>',  lambda evt: cambia_foto(-1))  # indietro
    ciclatore = Ciclatore(nomi_foto)
    cambia_foto(1)
    if tempo > 0:
        root.after(int(tempo*1000), richiama)
    root.mainloop()

#------------------------------------------------------------------------------

nomi_foto = 'foto1', 'foto2', 'foto3', 'foto4', 'foto5', 'foto6'
photo_slider(nomi_foto, 1.5)
Per aiutarci nel compito di scorrere avanti e indietro la sequenza dei nomi senza usare variabili globali (strutturando tutto come una classe sarebbe più ordinato e naturale), ci aiutiamo comunque con un piccolo oggetto istanziato dalla classe Ciclatore:

Codice: Seleziona tutto

class Ciclatore(object):

    def __init__(self, lista):
        self.lista = lista
        self.indice = 0

    def prossimo(self, direzione=1):
        if direzione not in (1, -1):
            raise ValueError(
                "invalid literal for Ciclatore.prossimo(): '%s'" % direzione)
        result = self.lista[self.indice]
        self.indice = (self.indice + direzione) % len(self.lista)
        return result
maresama
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1640
Iscrizione: mercoledì 9 gennaio 2008, 16:00

Re: Python - proiezione foto con transizione inaccettabile

Messaggio da maresama »

In effetti l'impostazione è completamente diversa!
Ora avrò da studiare per un po! Grazie!

Però non va bene con le foto.
Ho accodato alla print nome, la parte gestione foto:
la foto resta sempre la stessa (la prima). Non ho capito se è sempre fissa o se è sostituita velocemente, ma sempre dalla stessa.
Da notare però che i nomi foto della print cambiano. Quindi andrebbe veramente bene come avanzamento (dovrò solo vedere come fermare a fine lista senza riiniziare)
Forse occorre fare un refresh della foto ? (ma come?)

Codice: Seleziona tutto

def photo_sliderm(nomi_foto, tempo=0):
    def cambia_foto(direzione):
        nome = ciclatore.prossimo(direzione)
        print nome                                                   # modificato
        
# ------------- gestione foto
        ftw = Image.open(nome)
        a= ftw.size; ww=a[0]; hh=a[1]
        if hh>ww:r=r*0.62                                                 # foto verticale
        rp=970.00/ww
        r=0.9
        q=4
        r=r*rp
        tst=""
        ww=int(ww*r); hh=int(hh*r)
        if   q=="4":ftw = ftw.resize((ww, hh), Image.ANTIALIAS)           # best down-sizing filter
        elif q=="3":ftw = ftw.resize((ww, hh), Image.BICUBIC)             # cubic spline interpolation in a 4x4 environment
        elif q=="2":ftw = ftw.resize((ww, hh), Image.BILINEAR)            # linear interpolation in a 2x2 environment
        else:       ftw = ftw.resize((ww, hh), Image.NEAREST)             # use nearest neighbour
        if "E" in tst and "F" in tst: root.attributes('-fullscreen', True)
        ftw = ImageTk.PhotoImage(ftw)                            #converte
        wv = ftw.width(); hv = ftw.height()
        x=y=0                                                    #shift 
        root.geometry("%dx%d+%d+%d" % (wv, hv, x, y))
        panel1 = Label(root, image=ftw)
        panel1.pack(side='top', fill='both', expand='yes')
        panel1.image = ftw
#------------------------------------

    def richiama():
        cambia_foto(1)
        root.after(int(tempo*1000), richiama)
    root = Tk()
#    root = tk.Tk()                                                                                                                                # modificato
    root.bind('<Escape>', lambda evt: root.destroy())   # fine
    root.bind('<Next>',   lambda evt: cambia_foto(1))   # avanti
    root.bind('<Prior>',  lambda evt: cambia_foto(-1))  # indietro
    ciclatore = Ciclatore(nomi_foto)
    cambia_foto(1)
    if tempo > 0:
       root.after(int(tempo*1000), richiama)
    root.mainloop()
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: Python - proiezione foto con transizione inaccettabile

Messaggio da Claudio_F »

Credo che il problema sia nel fatto che 'panel1' è una variabile locale (quindi temporanea) della funzione 'cambia_foto'. La label andrebbe creata solo una volta nel corpo principale della funzione 'photo_sliderm':

Codice: Seleziona tutto

root = Tk()
panel1 = Label(root)
panel1.pack(side='top', fill='both', expand='yes')
root.bind('<Escape>', lambda evt: root.destroy())   # fine
....
e solo modificata dentro 'cambia_foto':

Codice: Seleziona tutto

....
root.geometry("%dx%d+%d+%d" % (wv, hv, x, y))
panel1.configure(image=ftw)
panel1.image = ftw
Non dovrebbe essere necessario nessun update esplicito.

Per fermarsi agli estremi della lista basta modificare il comportamento del ciclatore:

Codice: Seleziona tutto

def prossimo(self, direzione=1):
    if direzione not in (1, -1):
        raise ValueError(
            "invalid literal for Ciclatore.prossimo(): '%s'" % direzione)
    result = self.lista[self.indice]
    self.indice += direzione
    if self.indice < 0:
        self.indice += 1
    elif self.indice == len(self.lista):
        self.indice -= 1
    return result
Ultima modifica di Claudio_F il giovedì 28 maggio 2015, 11:44, modificato 2 volte in totale.
maresama
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1640
Iscrizione: mercoledì 9 gennaio 2008, 16:00

Re: Python - proiezione foto con transizione inaccettabile

Messaggio da maresama »

Era quello il problema.
Ho fatto quanto hai detto e ora il programma (il tuo!) va benissimo. Fa esattamente quello che doveva fare.
Non so come ringraziarti. Ora cercherò, nel fare i piccoli adattamenti, di capire tutto. Ma è una gran cosa farlo su un qualcosa che funziona!
Prometto (è la seconda volta!) di non disturbarti con altri problemi, se non sono per me irrisolvibili.
Ti ringrazio per la cortesia, la pazienza e la rapidità! Sei veramente di grande aiuto.
Ciao.
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 4 ospiti