Αντρω δι Νεξυνω

[Python] TK : un controllo "personalizzato", Pensieri e riscontri nella creazione di un oggetto

« Older   Newer »
  Share  
nuzzopippo
view post Posted on 26/4/2019, 08:56 by: nuzzopippo
Avatar

Nubbio x Sempre

Group:
Moderazione globale
Posts:
7,226

Status:


Testare il "controllo"



Conte anticipato nei post precedenti, procedendo nella fase di realizzazione del controllo ho sentito la necessità di testare la resa dello stesso, vuoi per sperimentare la miriadi di opzioni di configurazione disponibili per i vari widget, vuoi per verificare la resa grafica delle impostazioni adottate.
Verifiche che mi hanno portato ad esaminare numerose ipotesi prima di decidere l'iter di sviluppo da seguire.

Preparazione dell'ambiente di controllo


Data la natura del controllo da realizzare ho sbrigativamente collezzionato una dozzina di immagini, per lo più sfondi di desktop, di varia risoluzione, dal 500x500 pixel al Full HD, e mediamente "leggere" come peso, tra i 100 ed i 500 Kb, rinominandole dal 01.* al 12.* e stipandole in una sotto-directory della direttrice con il codice in sviluppo (risorse).

Tale accorgimento scaturisce dalla decisione di adottare un approccio a linea di comando, un paio dei test vertono sul colo controllo "FRMTumbnail" e prevedono l'inserimento del nome del file da miniaturizzare tra i parametri, inserire un percorso relativo seguito da uno "01.jpg" è molto più sbrigativo del path completo di un generico file.

Il test (file test.py)


Come già detto in precedenza, il controllo prevede l'utilizzo di dati con una singola riga strutturamente rappresentata da un dizionario contenente obbligatoriamente le chiavi "img", il cui valore indica il path di un file, e "dida", il cui valore è una stringa di testo rappresentante una didascalia associata all'immagine.
Data l'idea finalizzante il controllo in esame, cioè la creazione di un "Foto-Diario", un diario fotografico, nel test si è preparata una lista di dizionari (img_coll), uno per ogni immagine selezionata, contenenti oltre le chiavi prima dette una ulteriore chiave "testo" destinata ad una striga di testo più estesa atta a rappresentare commenti più estesi ... nel codice, dozzinali versi venuti d'impulso nell'associare le immagini, li lascio alla vostra ilarità.
Detta lista "img_coll" simula i dati applicativi di una eventuale applicazione utilizzante il controllo.

Oltre alla simulazione dei dati, nel codice di test vengono definite 8 classi, tutte estendenti direttamente la classe Tk di tkinter, in qualità di finestra principale applicativa, di cui quattro, denominate "GUI_num", ove num varia da 01 a 04, sono dedicate all'utilizzo del gestore di geometria "pack()", e quattro, denominate "GUI_num_G", ove num varia da 01 a 04, sono dedicate all'utilizzo del gestore di geometria "grid()".
Non si è voluto realizzare una variante adottante il gestore di geometria "place()" dato l'alto numero di "conticini" necessari al ridimensionamento della finestra, passate esperienze in Visual Basic, versioni pre-.NET, che hanno solo un simile piazzamento, mi rendono convinto non valga la pena, salvo casi estremi, adottare una simile geometria, stante i buoni effetti ottenibili con gli altri due gestori.

Le varianti con gestore di geometria "pack()", per la versione originaria del controllo, le avete già viste in calce al precedente post, ordinate secondo la successione GUI_01 - GUI_04, il funzionamento delle finestre è uniforme per tutte e tre le versioni, è la diversa "composizione" del controllo a far vedere delle differenze.
Anche se non è cosa buona e giusta mischiare più gestori di geometria nella stessa finestra, una finestra utilizzante il gestore grid può visualizzare decentemente il controllo che utilizza il gestore pack, di seguito esempio della rappresentazione della versione iniziale del controllo con finestre adottanti il gestore grid:

png



png



png



png



Come potete vedere dalle immagini, per questa versione del controllo la differenza visibile è quasi impercettibile, praticamente il solo bottone "mostra immagine/i", trattando la variante "con scrollbar" del controllo mostrerò e motiverò la decisione di testare con differenti gestori di geometria quanto in sviluppo.
Per altro, solo per la terza versione del controllo, quella che ho deciso di adottare per mio uso, ho deciso di fare una doppia versione dello stesso, che motiverò, adottanti specificatamente una il gestore pack e l'altra il gestore grid.

Di per se, le classi implementate sono semplicissime, limitandosi a costruire la finestra ed implementando, le versioni 01 e 02, soltanto una funzione "mostra()" che si limita ad inviare nome file e dimensione a FRMTumbnail la 01 e la lista dati "img_coll" a FRMTmbCollection la 02.

Leggermente più articolate le versioni 03 e 04, ove sono implementati il metodo pubblico* "set_selezione(self, indice)", che riceve l'indice di lista corrispondente ad una immagine/didascalia selezionata in FRMTmbCollection, cliccando con il tasto sinistro del mouse, e provvede a visualizzare, adattandola all'area disponibile, la corrispondente immagine tramite il metodo privato* "_mostra_img(self, env=None)".

* - N.B : Ovviamente, per quel che vale la distinzione tra metodo "pubblico" e metodo "privato" in python, si veda a tal proposito la "Pep 8 -- Style Guide for Python Code".

Il ccodice ora (file test.py : 631 righe)

CODICE
# -*- coding: utf-8 -*-

import sys
import tkinter as tk
from PIL import Image
from PIL import ImageTk
import my_object as fd

img_coll = [{'img'   : 'risorse/01.jpg',
            'dida'  : 'La Fonte',
            'testo' : ('Ciò che per primo\n' +
                       'placò la mia sete,\n' +
                       'nutrì anima\n' +
                       'e corpo,\n' +
                       'strumento di madre,\n' +
                       'orgoglio di donna,\n' +
                       'a me\n' +
                       'da sempre caro.'
                       )
            },
           {'img'   : 'risorse/02.jpg',
            'dida'  : 'Pensiero',
            'testo' : ('Lontano è volto il tuo sguardo\n'+
                       'conturbante donzella,\n' +
                       'di me ignara,\n' +
                       'ai palpiti sorda.\n' +
                       'Cosa mai\n' +
                       "al di la dell'orizzonte,\n" +
                       'te attrae?\n' +
                       'Non ti accorgi?\n' +
                       'Dietro te\n' +
                       'ogni cosa svanisce.'
                       )
            },
           {'img'   : 'risorse/03.png',
            'dida'  : 'La gatta',
            'testo' : ('Facesti le fusa,\n'+
                       'enigmatica guardavi\n' +
                       'me.\n' +
                       'Ti accolsi\n' +
                       'e con i tuoi artigli\n' +
                       'lacerasti\n' +
                       '... ma solo la mia pelle.'
                       )
            },
           {'img'   : 'risorse/04.jpg',
            'dida'  : 'Mi tocca?',
            'testo' : ('Erculea fatica\n'+
                       'ogni giorno me aspetta.\n' +
                       'E scrutare il nascosto\n' +
                       'che errore mio attende!\n' +
                       'Stanco oramai\n' +
                       'altrove mi volgo,\n' +
                       'non sarà mai\n' +
                       'un dì del ritorno.'
                       )
            },
           {'img'   : 'risorse/05.jpg',
            'dida'  : 'Eleanor',
            'testo' : ('Una fonte\n'+
                       'per Te creai,\n' +
                       'la illuminò mai\n' +
                       'un tuo sorriso?\n' +
                       'Ancor secca in me zampilla,\n' +
                       'vi è una carezza\n' +
                       'per Eleanor la bella.'
                       )
            },
           {'img'   : 'risorse/06.jpg',
            'dida'  : 'Afflizione',
            'testo' : ('Apristi le braccia\n'+
                       'e me cullasti.\n' +
                       'Il tuo calore disperse\n' +
                       'il decennio oscuro.\n' +
                       'Ti amero mai abbastanza\n' +
                       "nell'eterno futuro?"
                       )
            },
           {'img'   : 'risorse/07.jpg',
            'dida'  : 'Corazza',
            'testo' : ('Grazioso è il nasino che arricci,\n'+
                       'in tono con le tue grazie,\n' +
                       'altera bellezza\n' +
                       'che nascondi dietro il tuo dispetto?\n' +
                       "Forse, l'animo vuoto che non sa dire?\n" +
                       "Vattene! È un'altra la mia strada."
                       )
            },
           {'img'   : 'risorse/08.jpg',
            'dida'  : 'Speranza',
            'testo' : ("Per quanto la notte\n"+
                       "possa essere cupa,\n" +
                       "un'alba verrà ancora\n" +
                       "se non mia\n" +
                       "sia tua."
                       )
            },
           {'img'   : 'risorse/09.jpg',
            'dida'  : 'Addolorata',
            'testo' : ("Sei sola, amica mia,\n"+
                       "il tempo\n" +
                       "ha corroso il tuo amore,\n" +
                       "la noia\n" +
                       "il suo epitafio.\n" +
                       "Che importa s'egli\n" +
                       "ama ancora?\n" +
                       "Dentro te, sei persa."
                       )
            },
           {'img'   : 'risorse/10.jpg',
            'dida'  : 'Pater',
            'testo' : ("Da Te, padre,\n"+
                       "deriva la mia essenza.\n" +
                       "Come il Tuo\n" +
                       "è al mio sguardo,\n" +
                       "orizzonte il tetto."
                       )
            },
           {'img'   : 'risorse/11.jpg',
            'dida'  : 'Emotico',
            'testo' : ("A chi rivolge\n"+
                       "la tua ira?\n" +
                       "Chi ti è accanto\n" +
                       "ha maggior peso\n" +
                       "della tua colpa?"
                       )
            },
           {'img'   : 'risorse/12.jpg',
            'dida'  : 'Vindicta',
            'testo' : ("Dove andrai mai\n"+
                       "domine?\n" +
                       "Le leggi creasti\n" +
                       "per me spolpare,\n" +
                       "te credi più forte.\n" +
                       "\nDimentichi :\n" +
                       "sei solo carne!\n" +
                       "Avrò fame,\n"  +
                       "ti divorerò\n" +
                       "ancora palpitante."
                       )
            }
           ]



class GUI_01(tk.Tk):
   ''' Finestra principale test 01 : singola riga. '''

   def __init__(self, fnome='', dim=60):
       super().__init__()
       self.f_nome = fnome
       self.title('Test 01')
       sfondo = tk.Frame()
       sfondo.pack(fill='both')
       self.f = fd.FRMTumbnail(sfondo, None, dim)
       self.f.pack(fill='x')
       f2 = tk.Frame(sfondo, relief='sunken', padx=2, pady=2)
       f2.pack(fill='x')
       btn = tk.Button(f2, text='Mostra immagine', command=self.mostra)
       btn.pack()
       self.minsize(300, self.winfo_reqheight())
       # self.update()
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_fileimg(self.f_nome)
       self.f.set_dida("un po' di testo a caso")


class GUI_01_G(tk.Tk):
   ''' Finestra principale test 05 - variante layout grid : singola riga. '''

   def __init__(self, fnome='', dim=60):
       super().__init__()
       self.f_nome = fnome
       self.title('Test 05-Grid')
       sfondo = tk.Frame().grid(sticky='nsew')
       self.f = fd.GriFRMTmb(sfondo, None, dim)
       btn = tk.Button(sfondo,
                       text='Mostra immagine',
                       command=self.mostra)
       self.f.grid(row=0, padx=2, pady=2, sticky='ew')
       btn.grid(row=1, padx=2, pady=2, sticky='nsew')
       self.columnconfigure(0, minsize=300, weight=1)
       self.update()
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_fileimg(self.f_nome)
       self.f.set_dida("un po' di testo a caso")


class GUI_02(tk.Tk):
   '''Finestra principale test 02 : solo contenitore miniature.'''
   
   def __init__(self, righe=2, dim=60):
       super().__init__()
       self.title('Test 02')
       sfondo = tk.Frame()
       sfondo.pack(fill='both')
       self.f = fd.FRMTmbCollection(sfondo, righe, dim)
       self.f.pack(fill='x')
       f2 = tk.Frame(sfondo, relief='sunken', padx=2, pady=2)
       f2.pack(fill='x')
       btn = tk.Button(f2, text='Mostra immagini', command=self.mostra)
       btn.pack()
       self.update()
       self.minsize(400, self.winfo_reqheight())
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_data(img_coll)
   
       
class GUI_02_G(tk.Tk):
   ''' Finestra principale test 05 - variante layout grid : solo miniature. '''
   
   def __init__(self, righe=2, dim=60):
       super().__init__()
       self.title('Test 06-Grid')
       self.f = fd.GriFRMTmbColl(self, righe, dim)
       btn = tk.Button(self, text='Mostra immagini', command=self.mostra)
       self.f.grid(row=0, column=0, sticky='ew')
       btn.grid(row=1, column=0, sticky='nsew')
       self.grid_columnconfigure(0, weight=1)
       self.grid_rowconfigure(1, weight=1)
       self.update()
       self.minsize(400, self.winfo_reqheight())
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_data(img_coll)



class GUI_03(tk.Tk):
   '''Finestra principale test 03, componenti :
- contenitore miniature;
- area di testo descrittivo;
- area visualizzazione immagine.

Disposizione tumbnail orizzontale

Implementa metodo pubblico per invocazione aggiornamento dati.
'''
   
   def __init__(self, righe=2, dim=60):
       super().__init__()
       self.title('Test 03')
       sfondo = tk.Frame(self)
       sfondo.pack(fill='both')
       self.img = None
       self.indice = None
       self.in_vis = False
       # area del testo
       txt_sf = tk.Frame(self)
       txt_sf.pack(side='left', ipadx=1, ipady=1, fill='y')
       self.testo =tk.Text(txt_sf, width=40)
       self.testo.pack(side='left', expand=True, fill='both')
       sy = tk.Scrollbar(txt_sf)
       sy.pack(side='right', expand=True, fill='y')
       sy.config(command=self.testo.yview)
       self.testo.config(yscrollcommand=sy.set)
       # contenitore del resto
       s_sf = tk.Frame(self)
       s_sf.pack(side='left', ipadx=1, ipady=1, expand=True, fill='both')
       # immagine        
       self.cnv_img = tk.Canvas(s_sf,
                                width=300,
                                height=300,
                                bg='#ffffc0',
                                relief='raised',
                                border=2
                                )
       self.cnv_img.pack(expand=True, fill='both')
       self.cnv_img.bind("<Configure>", self._mostra_img)
       self.f = fd.FRMTmbCollection(s_sf, righe, dim, self)
       self.f.pack(fill='x')
       f2 = tk.Frame(s_sf, relief='sunken', padx=2, pady=2)
       f2.pack(fill='x')
       btn = tk.Button(f2, text='Mostra immagini', command=self.mostra)
       btn.pack()
       self.update()
       self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_data(img_coll)
   
   def set_selezione(self, indice):
       self.in_vis = True
       self.testo.delete('1.0', tk.END)
       self.cnv_img.delete('all')
       if indice >= len(img_coll): return
       self.indice = indice
       self.testo.insert(tk.END, img_coll[indice]['testo'])
       self._mostra_img(None)
   
   def _mostra_img(self, env=None):
       #if not self.img: return
       if not self.in_vis: return
       ''' Riscala e mostra l'immagine.'''
       # Import l'immagine tramite PIL (per i file *.jpg)
       img = Image.open(img_coll[self.indice]['img'])
       # proporzionamento immagine all'area disponibile
       img_x, img_y = img.size
       # calcola i rapporti di scala
       r_img = img_x / img_y
       r_cnv = self.cnv_img.winfo_width() / self.cnv_img.winfo_height()
       if r_cnv <= r_img:
           f_scala = self.cnv_img.winfo_width() / img_x
       else:
           f_scala = self.cnv_img.winfo_height() / img_y
       fx = int(img_x * f_scala)
       fy = int(img_y * f_scala)
       img = img.resize((fx, fy), Image.ANTIALIAS)
       # converto per il canvas
       self.img = ImageTk.PhotoImage(img)
       x = self.cnv_img.winfo_width() // 2
       y = self.cnv_img.winfo_height() // 2
       self.cnv_img.create_image(x, y, image=self.img, anchor='center')
       
       
class GUI_03_G(tk.Tk):        
   '''Finestra principale test 07-grid, componenti :
- contenitore miniature;
- area di testo descrittivo;
- area visualizzazione immagine.

Disposizione tumbnail orizzontale

Implementa metodo pubblico per invocazione aggiornamento dati.
'''
   
   def __init__(self, righe=2, dim=60):
       super().__init__()
       self.title('Test 07-grid')
       self.img = None
       self.indice = None
       self.in_vis = False
       self.testo = tk.Text(self, width=40)
       self.testo.grid(row=0, column=0, rowspan=2, sticky='ns')
       sy = tk.Scrollbar(self)
       sy.grid(row=0, column=1, rowspan=2, sticky='ns')
       sy.config(command=self.testo.yview)
       self.testo.config(yscrollcommand=sy.set)
       self.cnv_img = tk.Canvas(self,
                                width=300,
                                height=300,
                                bg='#ffffc0',
                                relief='raised',
                                border=2
                                )
       self.cnv_img.grid(row=0, column=2, sticky='nsew')
       self.cnv_img.bind("<Configure>", self._mostra_img)
       self.f = fd.GriFRMTmbColl(self, righe, dim, self)
       self.f.grid(row=1, column=2, sticky='ew')
       btn = tk.Button(self, text='Mostra immagini', command=self.mostra)
       btn.grid(row=3, column=0, columnspan=3, sticky='ew')
       self.grid_columnconfigure(2, weight=1)
       self.grid_rowconfigure(0, weight=1)
       self.update()
       self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_data(img_coll)
   
   def set_selezione(self, indice):
       self.in_vis = True
       self.testo.delete('1.0', tk.END)
       self.cnv_img.delete('all')
       if indice >= len(img_coll): return
       self.indice = indice
       self.testo.insert(tk.END, img_coll[indice]['testo'])
       self._mostra_img(None)
   
   def _mostra_img(self, env=None):
       #if not self.img: return
       if not self.in_vis: return
       ''' Riscala e mostra l'immagine.'''
       # Import l'immagine tramite PIL (per i file *.jpg)
       img = Image.open(img_coll[self.indice]['img'])
       # proporzionamento immagine all'area disponibile
       img_x, img_y = img.size
       # calcola i rapporti di scala
       r_img = img_x / img_y
       r_cnv = self.cnv_img.winfo_width() / self.cnv_img.winfo_height()
       if r_cnv <= r_img:
           f_scala = self.cnv_img.winfo_width() / img_x
       else:
           f_scala = self.cnv_img.winfo_height() / img_y
       fx = int(img_x * f_scala)
       fy = int(img_y * f_scala)
       img = img.resize((fx, fy), Image.ANTIALIAS)
       # converto per il canvas
       self.img = ImageTk.PhotoImage(img)
       x = self.cnv_img.winfo_width() // 2
       y = self.cnv_img.winfo_height() // 2
       self.cnv_img.create_image(x, y, image=self.img, anchor='center')
   
       


class GUI_04(tk.Tk):
   '''Finestra principale test 04, componenti :
- contenitore miniature;
- area di testo descrittivo;
- area visualizzazione immagine.

Disposizione tumbnail verticale

Implementa metodo pubblico per invocazione aggiornamento dati.
'''
   
   def __init__(self, righe=2, dim=60):
       super().__init__()
       self.title('Test 04')
       sfondo = tk.Frame(self)
       sfondo.pack(fill='both')
       self.img = None
       self.indice = None
       self.in_vis = False
       sftmb = tk.Frame(self, width=200)
       sftmb.pack(side='left', ipadx=1, ipady=1, fill='y')
       self.f = fd.FRMTmbCollection(sftmb, righe, dim, self)
       self.f.pack(side='left', fill='y')
       sftmb.configure(width=4*dim)
       s_sf = tk.Frame(self)
       s_sf.pack(side='left', ipadx=1, ipady=1, expand=True, fill='both')
       # immagine        
       self.cnv_img = tk.Canvas(s_sf,
                                width=300,
                                height=300,
                                bg='#ffffc0',
                                relief='raised',
                                border=2
                                )
       self.cnv_img.pack(expand=True, fill='both')
       self.cnv_img.bind("<Configure>", self._mostra_img)
       # area del testo
       f2 = tk.Frame(s_sf, relief='sunken', padx=2, pady=2)
       f2.pack(fill='x')
       txt_sf = tk.Frame(f2)
       txt_sf.pack(expand=True, fill='x')
       self.testo =tk.Text(txt_sf, height=10)
       self.testo.pack(side='left', expand=True, fill='x')
       sy = tk.Scrollbar(txt_sf)
       sy.pack(side='left', fill='y')
       sy.config(command=self.testo.yview)
       self.testo.config(yscrollcommand=sy.set)
       btn = tk.Button(f2, text='Mostra immagini', command=self.mostra)
       btn.pack()
       self.update()
       self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_data(img_coll)
   
   def set_selezione(self, indice):
       self.in_vis = True
       self.testo.delete('1.0', tk.END)
       self.cnv_img.delete('all')
       if indice >= len(img_coll): return
       self.indice = indice
       self.testo.insert(tk.END, img_coll[indice]['testo'])
       self._mostra_img(None)
   
   def _mostra_img(self, env=None):
       if not self.in_vis: return
       ''' Riscala e mostra l'immagine.'''
       # Import l'immagine tramite PIL (per i file *.jpg)
       img = Image.open(img_coll[self.indice]['img'])
       # proporzionamento immagine all'area disponibile
       img_x, img_y = img.size
       # calcola i rapporti di scala
       r_img = img_x / img_y
       r_cnv = self.cnv_img.winfo_width() / self.cnv_img.winfo_height()
       if r_cnv <= r_img:
           f_scala = self.cnv_img.winfo_width() / img_x
       else:
           f_scala = self.cnv_img.winfo_height() / img_y
       fx = int(img_x * f_scala)
       fy = int(img_y * f_scala)
       img = img.resize((fx, fy), Image.ANTIALIAS)
       # converto per il canvas
       self.img = ImageTk.PhotoImage(img)
       x = self.cnv_img.winfo_width() // 2
       y = self.cnv_img.winfo_height() // 2
       self.cnv_img.create_image(x, y, image=self.img, anchor='center')


class GUI_04_G(tk.Tk):
   '''Finestra principale test 08 - versione grid, componenti :
- contenitore miniature;
- area di testo descrittivo;
- area visualizzazione immagine.

Disposizione tumbnail verticale

Implementa metodo pubblico per invocazione aggiornamento dati.
'''
   
   def __init__(self, righe=2, dim=60):
       super().__init__()
       self.title('Test 08-grid')
       self.img = None
       self.indice = None
       self.in_vis = False
       #self.f = fd.GriFRMTmbColl(self, righe, dim, self)
       self.f = fd.FRMTmbCollection(self, righe, dim, self)
       self.f.grid(row=0, column=0, rowspan=2, sticky='nsew')
       # immagine        
       self.cnv_img = tk.Canvas(self,
                                width=300,
                                height=300,
                                bg='#ffffc0',
                                relief='raised',
                                border=2
                                )
       self.cnv_img.grid(row=0, column=1, columnspan=2, sticky='nsew')
       self.cnv_img.bind("<Configure>", self._mostra_img)
       # area del testo
       self.testo =tk.Text(self, height=10)
       self.testo.grid(row=1, column=1, sticky='ew')
       sy = tk.Scrollbar(self)
       sy.grid(row=1, column=2, sticky='ns')
       sy.config(command=self.testo.yview)
       self.testo.config(yscrollcommand=sy.set)
       btn = tk.Button(self, text='Mostra immagini', command=self.mostra)
       btn.grid(row=3, column=0, columnspan=3, sticky='ew')
       self.grid_columnconfigure(0, minsize=300)
       self.grid_columnconfigure(1, weight=1)
       self.grid_rowconfigure(0, weight=1)
       self.update()
       self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
       centraFinestra(self)
   
   def mostra(self):
       self.f.set_data(img_coll)
   
   def set_selezione(self, indice):
       self.in_vis = True
       self.testo.delete('1.0', tk.END)
       self.cnv_img.delete('all')
       if indice >= len(img_coll): return
       self.indice = indice
       self.testo.insert(tk.END, img_coll[indice]['testo'])
       self._mostra_img(None)
   
   def _mostra_img(self, env=None):
       if not self.in_vis: return
       ''' Riscala e mostra l'immagine.'''
       # Import l'immagine tramite PIL (per i file *.jpg)
       img = Image.open(img_coll[self.indice]['img'])
       # proporzionamento immagine all'area disponibile
       img_x, img_y = img.size
       # calcola i rapporti di scala
       r_img = img_x / img_y
       r_cnv = self.cnv_img.winfo_width() / self.cnv_img.winfo_height()
       if r_cnv <= r_img:
           f_scala = self.cnv_img.winfo_width() / img_x
       else:
           f_scala = self.cnv_img.winfo_height() / img_y
       fx = int(img_x * f_scala)
       fy = int(img_y * f_scala)
       img = img.resize((fx, fy), Image.ANTIALIAS)
       # converto per il canvas
       self.img = ImageTk.PhotoImage(img)
       x = self.cnv_img.winfo_width() // 2
       y = self.cnv_img.winfo_height() // 2
       self.cnv_img.create_image(x, y, image=self.img, anchor='center')




def centraFinestra(gui):
   ''' Centra una finestra, passata come parametro, sullo schermo '''
   l = gui.winfo_screenwidth()
   a = gui.winfo_screenheight()
   wx = gui.winfo_reqwidth()
   wy = gui.winfo_reqheight()
   gui.geometry('{}x{}+{}+{}'.format(wx, wy, (l-wx)//2, (a-wy)//2))

   

if __name__ == '__main__':
   if len(sys.argv) < 3:
       print('Numero argomenti errato')
       sys.exit('Numero argomenti errato')

   step = int(sys.argv[1])
   
   if step == 1:                                # test x layout pack
       # verifica singola riga di miniatura
       f_nome = sys.argv[2]
       dim = int(sys.argv[3])
       win = GUI_01(f_nome, dim)
   elif step == 2:
       righe = int(sys.argv[2])
       dim = int(sys.argv[3])
       win = GUI_02(righe, dim)
   elif step == 3:
       righe = int(sys.argv[2])
       dim = int(sys.argv[3])
       win = GUI_03(righe, dim)
   elif step == 4:
       righe = int(sys.argv[2])
       dim = int(sys.argv[3])
       win = GUI_04(righe, dim)
   if step == 5:                                # test x layout grid
       # verifica singola riga di miniatura
       f_nome = sys.argv[2]
       dim = int(sys.argv[3])
       win = GUI_01_G(f_nome, dim)
   if step == 6:
       righe = int(sys.argv[2])
       dim = int(sys.argv[3])
       win = GUI_02_G(righe, dim)
   if step == 7:
       righe = int(sys.argv[2])
       dim = int(sys.argv[3])
       win = GUI_03_G(righe, dim)
   if step == 8:
       righe = int(sys.argv[2])
       dim = int(sys.argv[3])
       win = GUI_04_G(righe, dim)
       

   win.mainloop()


Questo codice è la versione finale del test, specifica per la terza versione del controllo, le classi "GUI_num_G" richiamano esplicitamente le versioni "grid" del controllo, qualora si vogliano visualizzare le versioni "pack" dei controlli, si sostituiscano le chiamate "self.f = fd.GriFRMTmb(sfondo, None, dim)" con "self.f = fd.FRMTumbnail(sfondo, None, dim)" e "self.f = fd.GriFRMTmbColl(self, righe, dim)" con "self.f = fd.FRMTmbCollection(sfondo, righe, dim)".

Il test si avvia da shell, comando :
CODICE
python3 test.py numtest opzione1 opzione2

ove
  • numtest è un numero intero da 1 ad 8 che definisce quale classe "GUI..." utilizzare;
  • opzione1 è un nome di file per i test 1 e 5, il numero di righe di miniatura da visualizzare per gli altri test;
  • opzione2 la dimensione, in pixel, dell'aria per la miniatura.

Buon divertimento.

Il prossimo post riguarderà la versione del controllo con scrollbar ed i "perché" si è deciso di trovare i costrutti del gestore di geometria grid.
 
Web  Top
4 replies since 31/3/2019, 12:09   1066 views
  Share