Topic: problema con menu tkinter  (Letto 165 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline botbotler919

  • python unicellularis
  • *
  • Post: 2
  • Punti reputazione: 0
    • Mostra profilo
problema con menu tkinter
« il: Marzo 23, 2019, 06:17 »
grazie in anticipo a chi vorrà aiutarmi
sono un novizio di python ....
ho questo frammento di codice funzionante ma vorrei passare un valore alla funzione 'mod_comm'
menu_archivi.add_command(label = "Commerciali",command = mod_comm)

tipo:
menu_archivi.add_command(label = "Commerciali",command = mod_comm(valore))

ma non funziona, inoltre come faccio se devo anche avere un return dalla funzione ?
ribadisco che sono un novizio e ho difficoltà a spigarmi
grazie

Offline nuzzopippo

  • python habilis
  • **
  • Post: 56
  • Punti reputazione: 0
    • Mostra profilo
Re:problema con menu tkinter
« Risposta #1 il: Marzo 23, 2019, 10:37 »
sono un novizio di python ....
...
ma non funziona, inoltre come faccio se devo anche avere un return dalla funzione ?

Ciao @bot, mi perdonerai se rispondo più per fare esercizio che per dare una risposta esaustiva, la programmazione di interfacce grafiche è complessa e mi ci sono ancora avventurato poco.

Complessa è anche la risposta in merito all'argomento che poni, dipendendo in notevole misura dal design progettuale della applicazione, mio parere (gli esperti correggano) è che di per se le funzioni di callback dovrebbero limitarsi a gestire gli eventi, delegando al corpo delle funzioni di ottenere ciò che occorre ed eseguire le azioni opportune.
È opportuno, posto il "problema" progettare il proprio codice e le proprie classi in modo idoneo ad ottenere il risultato voluto tenendo presente che in sede di inizializzazione (ed anche dopo, spesso) non è che conoscano i valori dei parametri che Tu vorresti passare ... Ti ho preparato un esempio in tal senso partendo da codice recentemente postato in questo post, l'idea è semplicemente di ottenere che al comando di menu "Cerca Libro" una funzione si occupi di interrogare uno specifico oggetto per ottenere i dati inseriti nei controlli e li stampi.
Se copi il codice e lo modifichi come sotto indicato:
RIGA 71
        menu_libri.add_command(label='Cerca libro', command=self._cerca_libro)


CLASSE FinestraPrincipale - aggiugere metodo

    def _cerca_libro(self):
        if isinstance(self.sfondo, FrmLibro):
            valori = self.sfondo.dai_valori()
            print(valori)
        else:
            print('Nessun pannello libri presente')


CLASSE FrmLibro - aggiungere metodo

    def dai_valori(self):
        valori = {'autore': self.autore.get(),
                  'titolo': self.titolo.get()
                  }
        return valori

vedrai che lo farà SE starai utilizzando un pannello di classe "FrmLibro".
Sotto un output senza e con utilizzo di tale pannello (Frame, per meglio dire)
>>> %Run con_classi.py
Nessun pannello libri presente
{'autore': 'Nicola Aloia - Fausto Rabitti', 'titolo': 'SQL Sintassi e utilizzo'}


Andiamo ora ad una parte specifica del Tuo post, ossia : come inserire un parametro "variabile" nella definizione del command di un menu?

Risposta non semplice al mio (basso) livello di conoscenza (gli esperti potranno, bontà loro, integrare) , la prima domanda da porsi è : come fa l'istanza di menu a conoscere il parametro da utilizzare, , come si ottiene tale parametro?
Alla sua definizione, la funzione di callback potrà al più conoscere le variabili di classe ed istanza della classe in cui viene definita, potrà leggerli direttamente e/o  ottenerli se tali variabili sono "oggetti" grafici (widgets) riportando il discorso all'esempio prima esposto.

Comunque, diciamo che voglia "per forza" passare un "parametro" ad una funzione di callback invocata alla selezione di una voce di menu, non potrai farlo direttamente, provaci, una definizione con parametro alla definizione di un command di menu viene eseguito alla sola inizializzazione (mi si corregga se sbaglio), ma puoi ricorrere ad uno "sporco trucco" e definire una funzione lambda da richiamare al "command=...", a patto che tale "parametro" sia un oggetto conoscibile (una entry, una istanza StringVar, etc...), ciò riporta sempre alla considerazione iniziale ma voglio proporti n esempio funzionante in tal senso, è una variante all'esempio precedente (compattato ai soli "libri") che legge e richiama una funzione esterna alla classe di ricerca, in una lista di tuple, una stringa inserita nel titolo.
Il codice :

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

import tkinter as tk
import tkinter.messagebox as tm

libri = [('SQL Sintassi ed utilizzo', 'Nicola Aloia - Fausto Rabitti'),
         ('Core Java 2 volume 1 - Fondamenti', 'Cay S. Horstmann - Gary Cornell'),
         ('Core Java 2 volume 2 - Tecniche avanzate', 'Cay S. Horstmann - Gary Cornell'),
         ('La svastica sul sole', 'Philip K. Dick'),
         ('Universo Orbitsville', 'Bob Shaw'),
         ('scienza e coscienza', 'A.C. Bhaktivedanta Swami Pabhupada')
         ]


# *** CLASSI DELLE FINESTRE ***

class LoginFrame(tk.Toplevel):
   
    def __init__(self, master=None):
        self.master = master
        super().__init__(self.master)
        self.label_nome_utente = tk.Label(self, text="Nome Utente")
        self.label_password = tk.Label(self, text="Password")
        self.entry_nome_utente = tk.Entry(self)
        self.entry_password = tk.Entry(self, show="*")
        self.label_nome_utente.grid(row=0, sticky=tk.E)
        self.label_password.grid(row=1, sticky=tk.E)
        self.entry_nome_utente.grid(row=0, column=1)
        self.entry_password.grid(row=1, column=1)
        self.logbtn = tk.Button(self, text="Login", command=self._login_btn_clicked)
        self.logbtn.grid(columnspan=2)
        self.update()
        centra_finestra(self)
       
    def _login_btn_clicked(self):
        nome_utente = self.entry_nome_utente.get()
        password = self.entry_password.get()

        if nome_utente == "marco" and password == "password":
            self.destroy()
            self.master.mostra()
        else:
            self.master.chiudi()


class FinestraPrincipale(tk.Tk):
   
    def __init__(self):
        super().__init__()
        # configurazione
        self.title('pyLibri 0.1')
        self.geometry('960x640')
       
        f = tk.Frame(self)
        f.pack(expand=True, fill='both')
        subf1 = tk.Frame(f, padx=5, pady=5)
        subf1.pack(expand=True, fill='x', padx=5, pady=5)
        lbl1 = tk.Label(subf1, text='Titolo :', width=7, justify='left')
        lbl1.pack(side='left', anchor='n')
        self.titolo = tk.Entry(subf1, width=15)
        self.titolo.pack(side='left', expand=True, fill='x', anchor='n')
        subf2 = tk.Frame(f, padx=5, pady=5)
        subf2.pack(expand=True, fill='x', padx=5, pady=5)
        lbl2 = tk.Label(subf2, text='Autore :', width=7, justify='left')
        lbl2.pack(side='left', anchor='n', padx=5, pady=5)
        self.autore = tk.Entry(subf2, width=15)
        self.autore.pack(side='left', expand=True, fill='x', anchor='n', padx=5, pady=5)
       
        barra_menu = tk.Menu(self)
        self.config(menu=barra_menu)
        menu_libri = tk.Menu(barra_menu)
        barra_menu.add_cascade(label='Libri', menu=menu_libri)
        menu_libri.add_command(label='Nuovo libro')
        x = lambda: self._cerca_libro(self.titolo.get())
        menu_libri.add_command(label='Cerca libro', command=x)
        menu_libri.add_command(label='Cancella libro')
        menu_uscita = tk.Menu(barra_menu)
        barra_menu.add_cascade(label='Uscita', menu=menu_uscita)
        menu_uscita.add_command(label='Esci', command=self.destroy)
        self.sfondo = tk.Frame(self, padx=0, pady=0)
        self.sfondo.pack(expand=True, fill='both', padx=0, pady=0)
        self.nascondi()
        LoginFrame(self)
       
    def nascondi(self):
        ''' Nasconde la finestra.'''
        self.withdraw()

    def mostra(self):
        ''' Mostra la finestra '''
        self.deiconify()
        centra_finestra(self)
   
    def chiudi(self):
        ''' Chiude la finestra.'''
        tm.showerror("Errore", "Nome utente o password errata")
        self.destroy()
   
    def _cerca_libro(self, titolo):
        if titolo:
            print('Cerco libri con', titolo, 'nel titolo')
            risult = cerca_titolo(titolo)
            if risult:
                for libro in risult:
                    print(libro)
            else:
                print('Nessun elemento trovato')
        else:
            print('Nessun titolo inserito')
       

# *** FUNZIONI GLOBALI ****

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


def cerca_titolo(titolo):
    ''' Simula una ricerca in una lista di titoli'''
    risult = []
    for libro in libri:
        if libro[0].lower().find(titolo.lower()) != -1:
            risult.append(libro)
    return risult


# *** START APPLICAZIONE ***

if __name__ == '__main__':
    app = FinestraPrincipale()
    app.mainloop()


Personalmente, non conosco o immagino metodi per ottenere un valore di ritorno alla selezione di una voce di menu.
La selezione di una voce di menu è e rimane, un evento, suo compito è scatenare azioni non restituire "risultati", sono le azioni avviate a dover produrre risultati.

Spero che ciò che credo (si correggano i miei eventuali abbagli) di aver capito ed ho cercato di esporre Ti sia utile.

Offline botbotler919

  • python unicellularis
  • *
  • Post: 2
  • Punti reputazione: 0
    • Mostra profilo
Re:problema con menu tkinter
« Risposta #2 il: Marzo 23, 2019, 11:33 »
Ti ringrazio
per la risposta  e per il tempo che mi hai dedicato per scriverla (non poco, grazie)
me la leggo per bene e vedo cosa riesco a fare .