Forum >> Principianti >> problemi con programmino

Pagina: 1

Ho modificato ed adattato questo programmino trovato su "Programming Python" O'Reilly, Mark Lutz, per esercitarmi con Python.

Il problema è che il tasto "load" funziona solo se faccio partire il programma con "edit with IDLE" --> "run"-->"run module",

se lo faccio partire con il doppio click mi apre la finestra di dialogo e come clicco su apri crasha.

Perché?




Perché il pulsante "quit" non funziona?




E' possibile non far comparire la finestra nera "C:\Windows\py.exe" quando lancio il programma?




Grazie in anticipo dell'aiuto.
Allegati
Ho risolto il problema del tasto quit usando:
command=root.destroy




Inspiegabilmente ora la funzione load non crasha più quando lancio il programma con un doppio click.
Mi sembra che ci siano diversi errori in quel codice. Sicuramente quit con le parentesi di chiamata. Poi la chiamata a mainloop senza specificare l'oggetto su cui chiamarlo (solitamente l'istanza root di Tk...). Anche l'uso di forget mi sembra strano, i widget vengono "dimenticati" dal gestore grafico (non vengono più visualizzati fino a eventuale successivo pack/grid/place), ma non eliminati.

Il differente comportamento tra il lancio diretto del programma e da dentro Idle si può spiegare con il fatto che lo stesso ambiente Idle è un programma grafico Tk, e il tuo viene lanciato all'interno di esso come thread figlio (ad esempio se un'applicazione Tk che crea thread demoni viene lanciata all'interno di Iidle, i thread demoni non muoiono finché non viene chiuso totalmente Idle stesso).

Il fatto che lanciando il programma con il doppio click si chiuda subito, significa che c'è un errore che Idle maschera (sospetto fortemente quel mainloop da solo). Il modo corretto per vedere gli errori e non avere effetti di "silenziamento" dovuti a un IDE è lanciare il programma dalla console comandi scrivendo per esteso: python nomeprogramma.py (con windows è un po' brigoso, bisogna aggiungere il nome dell'interprete al path di sistema e spostarsi a manina nella subdir contenente il programma).

Per la "finestra nera" (la console comandi) forse basta rinominare i .py in .pyw


*** Il codice va evidenziato con il simbolo di fianco ai colori per non perdere l'indentazione ***
Adesso funziona tutto.
Rinominando il file, come mi hai suggerito, ha funzionato alla grande. Grazie :).

Non credo di avere la preparazione sufficiente per capire a fondo gli errori che mi hai segnalato (ho studiato su "programmare con Python" di Mark Lutz e David Ascher della Hoepli informatica O'Reilly(per la sintassi base) e su "programming Python" 3rd Edition di Mark Lutz della O'Reilly (che da per scontato che si conosce la sintassi base e approfondisce alcuni argomenti come la creazione di interfacce grafiche con tkinter), ma per adesso li ho appena letti non studiati a fondo).

Comunque, stranamente, dopo che ho sostituito <> command=self.quit() <> con <>command=root.destroy<>, non solo funziona il tasto quit, ma non crasha più quando uso il tasto load (non so proprio spiegarmi il perché).

Comunque ora funziona tutto, allego la versione del file completamente funzionante.

Grazie ancora di tutto l'aiuto ricevuto.
Allegati
Per praticità gli esempi sui libri importano (quasi) sempre tutto il contenuto dei moduli, quindi fanno un bel
from tkinter import *
ma non sarebbe una cosa da fare perché tutto quello che è definito nel modulo diventa visibile a livello globale, basta fare
from tkinter import *
dir()
per accorgersi di quenti nomi, funzioni, costanti siano state importate. Questo vuol dire ad esempio non poter definite una nostra costante END perché andremmo a sovrascrivere quella importata. Se invece si importa solo il nome del modulo e ci si riferisce alle cose contenute tramite
nomemodulo.cosaconenuta
non avremo mai conflitti tra nomi.

Tra l'altro il famoso 'mainloop' che dicevo è una funzione importata assieme a tutto il resto, per quello funziona, altrimenti si doveva scrivere (più correttamente)
root.mainloop()

Per quanto riguarda 'quit()' il problema sono le parentesi di chiamata alla funzione quit. A command si assegna il nome della funzione da eseguire (giustamente root.destroy), non il risultato della chiamata alla funzione (anche root.destroy() non andrebbe bene).

La logica nella funzione 'onload' invece è sbagliata (lo si dovrebbe notare da un'estrema lentezza nell'aggiornamento delle celle). Le entry vanno distrutte e ricreate ex novo (meglio ancora sarebbe fare questo solo se cambia il numero di colonne o righe), ho perciò corretto un po' il codice come spunto. Non è ancora perfetto (basta lasciare una casella vuota per accorgersene) e si potrebbe discutere sul design scelto dagli autori (sempre per ragioni di semplicità espositiva), ad esempio il nome 'root' globale... tra l'altro anche subclassare Frame in quel modo non mi sembra una cosa adatta ad un esempio per principianti (a meno che l'esempio non riguardi il subclassamento ovviamente). Nota: gli import iniziali rendono il tutto compatibile con Python2.

try:
    import tkinter as tk
    import tkinter.filedialog as filedialog
except ImportError:
    import Tkinter as tk
    import tkFileDialog as filedialog
import os

 
class portaeppendorf(tk.Frame):
 
    def __init__(self, parent=None, numrow=10, numcol=10):
        tk.Frame.__init__(self, parent)
        self.numrow = numrow
        self.numcol = numcol
        self.makewidgets(numrow, numcol)
 
    def makewidgets(self, numrow, numcol):
        self.rows = []
        for i in range(numrow):
            cols = []
            for j in range(numcol):
                en = tk.Entry(self, relief=tk.RIDGE)
                en.grid(row=i+1, column=j, sticky=tk.NSEW)
                en.insert(tk.END, '%d.%d' % (i, j))
                cols.append(en)
            self.rows.append(cols)
        tk.Button(self, text='Load', command=self.onload).grid(row=11, column=0)
        tk.Button(self, text='Clear', command=self.onclear).grid(row=11, column=2)
        tk.Button(self, text='Save', command=self.onsave).grid(row=11, column=1)
        tk.Button(self, text='Quit', command=root.destroy).grid(row=11, column=9)
 
    def onclear(self):
        for row in self.rows:
            for en in row:
                en.delete('0', tk.END)
                en.insert(tk.END, '0.0')
 
    def onload(self):
        load = filedialog.askopenfilename()
        if load:
            with open(load, 'r') as loadfile:
                filelines = loadfile.readlines()
            self.numrow = len(filelines)
            self.numcol = len(filelines[ 0 ].split())
            ### Distrugge vecchie entry e ricrea ###
            for row in self.rows:
                for en in row:
                    en.destroy()
            self.makewidgets(self.numrow, self.numcol)
            ### Scrive nelle entry i dati letti da file ###
            for row, line in enumerate(filelines):
                for col, value in enumerate(line.split()):
                    en = self.rows[ row ][ col ]
                    en.delete('0', tk.END)
                    en.insert(tk.END, value)
 
    def onsave(self):
        save = filedialog.asksaveasfilename()
        if save:
            check = os.listdir('.')
            if save in check:
                os.remove(save)
            with open(save, 'w') as savefile:
                for row in self.rows:
                    savefile.write(' '.join(str(en.get()) for en in row)+'\n')
 
 
if __name__ == '__main__':
    root = tk.Tk()
    root.title('Eppendorf')
    portaeppendorf(root).pack()
    root.mainloop()

*** Il codice va evidenziato con il simbolo di fianco ai colori per non perdere l'indentazione ***


Pagina: 1



Esegui il login per scrivere una risposta.