Ciao
anche dal Tuo ultimo stralcio non si evince un "perché" della segnalazione "'NoneType' object has no attribute 'select_range" iniziale ... Se il problema persiste ancora, dovresti ingegnarTi ad emularlo con codice ridotto e completo come efficacia su cui discorrere.
Per altro :
In effetti, un metodo java/swing non è che vada bene in tkinter
chiedo venia, mi capita spesso di pensare in java e, come detto prima, il codice proposto è in sviluppo e non ancora testato adeguatamente, era una routine recente che mi son ricordato analoga alle Tue problematiche.
Riguardo alle altre Tue domande : utilizzo 7 computer diversi (3 in ufficio e 4 a casa) con diverse versioni di python, da 3.5 a 3.7 (N.B. - non faccio il programmatore, anche se diverse cose al lavoro sono opera mia), dipendentemente dalla macchina uso prevalentemente gedit o thonny, sto guardando in giro per IDE adeguati, ben documentati, sin ora non ho trovato roba che mi convinca ... con un po' di pudore devo dire che son tentato dal 'Visual Studio Code' della Microsoft ma ancora non mi son convinto ad installarlo.
Detto questo, passiamo al Tuo codice.
Mi perdonerai l'opinione ma gestire nella Tua modalità le date è una brutta idea ... per i bisestili come ti metti? E per i mesi di 30gg? Ritengo che Ti convenga utilizzare i mezzi messi a disposizione da datetime.
Un po' per farmi perdonare quel "set_focus()" mi son permesso, questa mattina, di sviluppare un piccolo esempio di "valutazione di data" con una finestra creata sub-classando Tk ed utilizzando le metodologie che abitualmente uso, giusto per esempio provvista di una gestione del focus per le entry e selezione del testo in caso di data incompatibile, questo il codice completo (~150 righe) :
Codice: Seleziona tutto
# -*- coding: utf-8 -*-
import datetime
import tkinter as tk
import tkinter.messagebox as msgb
class MyTopWin(tk.Tk):
'''
Finestra di esempio per controllo immissione data - versione 1.0
In questo scenario non uso oggetti StringVar ne' validatori, si affrontano la
verifica della data immessa, gestione del focus e selezione del testo.
La verifica dati viene scatenata da un evento esterno al widget dedicato.
'''
def __init__(self):
super().__init__()
self.title('CTRL Input data per @robdevo')
# blocco per la data
lbl_1 = tk.Label(self, text='data (gg/mm/yyyy) : ', justify='left')
lbl_1.grid(row=0, column=0, sticky='w', padx=4)
self.e_data = tk.Entry(self, bg='white')
self.e_data.grid(row=0, column=1, sticky='ew', pady=4, padx=4)
# blocchi testo per riempimento
lbl_2 = tk.Label(self, text='testo 1 : ', justify='left')
lbl_2.grid(row=0, column=2, sticky='w', padx=4)
self.e_txt1 = tk.Entry(self, bg='white')
self.e_txt1.grid(row=0, column=3, sticky='ew', pady=4, padx=4)
lbl_3 = tk.Label(self, text='testo 2 : ', justify='left')
lbl_3.grid(row=1, column=0, sticky='w', padx=4)
self.e_txt2 = tk.Entry(self, bg='white')
self.e_txt2.grid(row=1, column=1, sticky='ew', pady=4, padx=4)
lbl_4 = tk.Label(self, text='testo 3 : ', justify='left')
lbl_4.grid(row=1, column=2, sticky='w', padx=4)
self.e_txt3 = tk.Entry(self, bg='white')
self.e_txt3.grid(row=1, column=3, sticky='ew', pady=4, padx=4)
# pulsanti di comando
self.bt_evaluate = tk.Button(self, text='Valuta data')
self.bt_evaluate.grid(row=2, column=0, columnspan=2, sticky='ew',
pady=4, padx=4)
self.bt_end = tk.Button(self, text='Chiudi programma')
self.bt_end.grid(row=2, column=2, columnspan=2, sticky='ew',
pady=4, padx=4)
# configurazione colonne
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure(3, weight=1)
# binders
# *** cambio Focus ***
self.e_data.bind('<FocusIn>', self.__in_focus)
self.e_data.bind('<FocusOut>', self.__out_focus)
self.e_txt1.bind('<FocusIn>', self.__in_focus)
self.e_txt1.bind('<FocusOut>', self.__out_focus)
self.e_txt2.bind('<FocusIn>', self.__in_focus)
self.e_txt2.bind('<FocusOut>', self.__out_focus)
self.e_txt3.bind('<FocusIn>', self.__in_focus)
self.e_txt3.bind('<FocusOut>', self.__out_focus)
# tasti invio
self.e_data.bind('<Return>', self.__move_to_entry)
self.e_data.bind('<KP_Enter>', self.__move_to_entry)
self.e_txt1.bind('<Return>', self.__move_to_entry)
self.e_txt1.bind('<KP_Enter>', self.__move_to_entry)
self.e_txt2.bind('<Return>', self.__move_to_entry)
self.e_txt2.bind('<KP_Enter>', self.__move_to_entry)
self.e_txt3.bind('<Return>', self.__move_to_entry)
self.e_txt3.bind('<KP_Enter>', self.__move_to_entry)
# pulsanti
self.bt_end.bind('<Button>', self.__on_close)
self.bt_evaluate.bind('<Button>', self.__evaluate_time)
# visualizzazione finale
self.update()
self.minsize(self.winfo_reqwidth(), self.winfo_reqheight())
win_center(self)
def __in_focus(self, evt):
evt.widget.configure(bg='#ffffc0')
def __out_focus(self, evt):
evt.widget.configure(bg='white')
def __move_to_entry(self, evt):
if evt.widget == self.e_data:
self.e_txt1.focus_set()
elif evt.widget == self.e_txt1:
self.e_txt2.focus_set()
elif evt.widget == self.e_txt2:
self.e_txt3.focus_set()
elif evt.widget == self.e_txt3:
self.e_data.focus_set()
def __on_close(self, evt):
self.destroy()
def __evaluate_time(self, evt):
str_time = self.e_data.get()
if not str_time:
msgb.showerror('Data non valida',
'Non è stata inserita nessuna data')
self.e_data.focus_set()
return
try:
my_date = datetime.datetime.strptime(str_time,'%d/%m/%Y')
except ValueError as e:
msgb.showerror('Data non valida',
e)
self.e_data.focus_set()
self.e_data.select_range(0, tk.END)
return
# blocco controlli personalizzati robdevo
to_day = datetime.date.today()
interv = datetime.timedelta(days=20)
if my_date.date() < to_day - interv or my_date.date() > to_day + interv:
msgb.showerror('Data fuori intervallo',
'ammesso : ' + to_day.strftime('%d/%m/%Y') + ' ± 20 gg.')
self.e_data.focus_set()
self.e_data.select_range(0, tk.END)
return
# codice se la data è buona, esempio
msgb.showinfo('Data OK', my_date.strftime('%d/%m/%Y') + ' va bene...')
# così le combini come vuoi, p.e.
gg = my_date.day
mm = my_date.month
yy = my_date.year
msg = 'Un esempio di combinazione : ' + str(yy) + ' ' + str(mm) + ' ' + str(gg)
msgb.showinfo('Esempio', msg)
# ****************************
# *** FUNZIONI DI SERVIZIO ***
# ****************************
def win_center(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))
# ****************************
# *** LANCIO APPLICAZIONE ***
# ****************************
if __name__ == '__main__':
root_win = MyTopWin()
root_win.mainloop()
Vedi che Ti sembra la gestione alternativa della data immessa che Ti propongo.
... di solito i miei "esercizi" sono più complessi ma questa è solo una base di partenza, dato che a tempo perso ho intenzione di vedermi, finalmente, le StringVar() et similia oltre che i validatori, se Ti va potremmo anche parlarne in merito,
Ciao