Fehler im Menu beim wechsel zu einem anderen Frame

Fragen zu Tkinter.
Antworten
Dextinator
User
Beiträge: 6
Registriert: Samstag 19. August 2017, 20:42

Guten Abend,
ich bin recht neu in Python und in Tkinter und ich versuche gerade ein kleines Programm mit gui zu entwickeln. Ich versuche gerade, dass man zwischen den verschiedenen Fenstern hin und her wechseln kann. Mit Hilfe von Buttons funktioniert das ganze schon. Wenn ich das ganze allerdings auf mein Menu anwenden möchte erhalte ich einen Error. ( Manager -> Bildschirmeinstellungen) Die genaue Fehlermeldung lautet:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Jona\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:\Users\Jona\other\Desktop\testtestest123.py", line 60, in <lambda>
command=lambda: show_frame(Benutzereinstellungen,cont))
NameError: name 'cont' is not defined

Mein Code:

Code: Alles auswählen

import tkinter as tk
from tkinter import *
from tkinter import ttk

LARGE_FONT= ("Verdana", 12)

def close():
    exit()

class SeaofBTCapp(tk.Tk):

    def __init__(self, *args, **kwargs):


        
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)

        container.pack(side="top", fill="both", expand = True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}



        for F in (RemoteManager, Benutzereinstellungen, PageTwo):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(RemoteManager)




#Menu ohne Funktion

        def show_frame(lable,cont):

            frame= self.frames[cont]
            frame.tkraise()


        menubar = tk.Menu(container)
        filemenu = tk.Menu(menubar, tearoff=0)
        hilfemenu = tk.Menu (menubar, tearoff=0)
        filemenu.add_command(label="Komplettes Setup")
        filemenu.add_separator()
        filemenu.add_command(label="Benutzereinstellungen",
                            command=lambda: show_frame(Benutzereinstellungen,cont))
        
        filemenu.add_command(label="Bildschirmeinstellungen")
        filemenu.add_command(label="Servereinstellungen")
        filemenu.add_separator()
        filemenu.add_command(label="Beenden", command=close)
        menubar.add_cascade(label="Manager", menu=filemenu)
        

        menubar.add_cascade(label="Hilfe", menu=hilfemenu)
        hilfemenu.add_command(label="Info")


        tk.Tk.config(self, menu=menubar)


          

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()


 #Buttons mit Funktion       
class RemoteManager(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        
        label = tk.Label(self, text="Willkommen im Remote Manager")
        label.pack(pady=15,padx=25)

    
        Benutzeranlegen_button = Button(self, text="Benutzereinstellungen", height= 0, width= 18,
                            command=lambda: controller.show_frame(Benutzereinstellungen))
        Benutzeranlegen_button.pack()

        label1 = tk.Label(self, text="")
        label1.pack(pady=1,padx=25)
        
        Bildschirmeinstellungen_button = Button(self, text="Bildschirmeinstellungen", height= 0, width= 18,
                            command=lambda: controller.show_frame(PageOne))
        Bildschirmeinstellungen_button.pack()

        label2 = tk.Label(self, text="")
        label2.pack(pady=1,padx=25)
                            
        Servereinstellungen_button = Button(self, text="Servereinstellungen", height= 0, width= 18,
                            command=lambda: controller.show_frame(PageOne))
        Servereinstellungen_button.pack()

        label2 = tk.Label(self, text="")
        label2.pack(pady=5,padx=25)



class Benutzereinstellungen(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
        label.pack (pady=20,padx=10)


        button1 = tk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()

        button2 = tk.Button(self, text="Page Two",
                            command=lambda: controller.show_frame(PageTwo))
        button2.pack()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = tk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()

        button2 = tk.Button(self, text="Page One",
                            command=lambda: controller.show_frame(PageOne))
        button2.pack()
        


app = SeaofBTCapp()
app.mainloop()
Ich hoffe Ihr könnt mir weiterhelfen. Vielen Dank schonmal!
Zuletzt geändert von Dextinator am Samstag 19. August 2017, 21:15, insgesamt 2-mal geändert.
BlackJack

@Dextinator: Und was verstehst Du an dieser Meldung nicht? Der Name `PageOne` ist ja in der Tat nirgends definiert. Was soll Python da auch machen?
Dextinator
User
Beiträge: 6
Registriert: Samstag 19. August 2017, 20:42

BlackJack hat geschrieben:@Dextinator: Und was verstehst Du an dieser Meldung nicht? Der Name `PageOne` ist ja in der Tat nirgends definiert. Was soll Python da auch machen?
Guten Abend, danke für deine Antwort. Ich habe leider den falschen Fehlercode angegeben. Hab es jetzt aktualisiert. Mein Problem ist, dass cont nicht definiert ist. Allerdings funktioniert es ein paar Zeilen problemlos mit cont. Was habe ich falsch gemacht und wie kann ich das Problem lösen? Vielen Dank.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dextinator: Du solltest verstehen, was Gültigkeitsbereiche für Variablennamen sind. In Zeile 75 ist `cont` das Argument der Methode show_frame, in Zeile 55 bist Du aber in der Methode __init__, wo nirgends ein `cont` definiert ist. Dass es auch noch eine verschachtelte Funktion mit dem Namen »show_frame« gibt, ist ungünstig, das kann zu Verwirrungen führen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Dextinator hat geschrieben: File "C:\Users\Jona\other\Desktop\testtestest123.py", line 60, in <lambda>
command=lambda: show_frame(Benutzereinstellungen,cont))
NameError: name 'cont' is not defined
Dazu ist zu sagen, dass der hier gepostete Code nicht zur Fehlermeldung passt, denn dort ist die betreffende Zeile in Zeile 55. Und die Fehlermeldung stimmt auch so, denn cont ist nirgends definiert.

Dann ist zu sagen, dass Du Dich mit lambda anscheinend nicht auskennst. Statt lambda nimmst du besser partial:

Code: Alles auswählen

from functools import partial
Damit dürftest Du besser zurechtkommen und wenn Du so einen Fehler machst, merkst Du das gleich und nicht erst, wenn der Aufruf erfolgt.

Ach so, ein cont gibt es schon, nämlich innerhalb der Funktion show_frame aber außerhalb gibt es kein cont
Zuletzt geändert von Alfons Mittelmeyer am Samstag 19. August 2017, 22:05, insgesamt 1-mal geändert.
BlackJack

@Dextinator: `PageOne` ist allerdings trotzdem nicht definiert und es wird versucht an mehr als einer Stelle zu verwenden. Gilt auch für `StartPage`.

Kann es sein das Du eigentlich ein `ttk.Notebook` verwenden möchtest statt so etwas selber zu implementieren?
Dextinator
User
Beiträge: 6
Registriert: Samstag 19. August 2017, 20:42

Alfons Mittelmeyer hat geschrieben:
Dextinator hat geschrieben: File "C:\Users\Jona\other\Desktop\testtestest123.py", line 60, in <lambda>
command=lambda: show_frame(Benutzereinstellungen,cont))
NameError: name 'cont' is not defined
Dazu ist zu sagen, dass der hier gepostete Code nicht zur Fehlermeldung passt, denn dort ist die betreffende Zeile in Zeile 55. Und die Fehlermeldung stimmt auch so, denn cont ist nirgends definiert.

Dann ist zu sagen, dass Du Dich mit lambda anscheinend nicht auskennst. Statt lambda nimmst du besser partial:

Code: Alles auswählen

from functools import partial
Damit dürftest Du besser zurechtkommen und wenn Du so einen Fehler machst, merkst Du das gleich und nicht erst, wenn der Aufruf erfolgt.

Ach so, ein cont gibt es schon, nämlich innerhalb der Funktion show_frame aber außerhalb gibt es kein cont
Danke schon mal für die Antwort, ich denke ich weiß jetzt ungefähr worin das Problem besteht. Allerdings ist mein Versuch, dass Menü einfach in die Funktion show_frame zu stecken gescheitert, da daraus ein weiterer Error resultiert. Jetzt stehe ich leider ein bisschen auf dem Schlauch. Wie müsste der Code aussehen damit es funktioniert? Ich glaube ich würde das ganze besser verstehen wenn ich die Lösung vor Augen habe. Vielen Dank.
Dextinator
User
Beiträge: 6
Registriert: Samstag 19. August 2017, 20:42

Sirius3 hat geschrieben:@Dextinator: Du solltest verstehen, was Gültigkeitsbereiche für Variablennamen sind. In Zeile 75 ist `cont` das Argument der Methode show_frame, in Zeile 55 bist Du aber in der Methode __init__, wo nirgends ein `cont` definiert ist. Dass es auch noch eine verschachtelte Funktion mit dem Namen »show_frame« gibt, ist ungünstig, das kann zu Verwirrungen führen.
Danke für deine Antwort. Ich habe versucht das Menu einfach in die Methode show _frame zu verfrachten. Allerdings ergab das einen error. Wie definiere ich in der Methode __init__ cont? Ich glaube wenn ich die Lösung vor Augen habe, dann kann ich das ganz besser verstehen. Vielen Dank!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Dextinator hat geschrieben:Wie müsste der Code aussehen damit es funktioniert? Ich glaube ich würde das ganze besser verstehen wenn ich die Lösung vor Augen habe. Vielen Dank.
Du solltest nichts angeben, was noch nicht da ist, wie StartPage, PageOne und noch ein paar. Programmier nur rein, was Du hast und nicht, was noch nicht da ist.

Dann was soll des das? show_frame ist einmal als Funktion und dann nochmals als Klasse definiert. Kein Wunder, wenn Du nicht mehr weißt, was was ist.

Was mir auch nicht gefallen hatte, der Frame als Parent für das Menü. Wollte Dein Programm mit meinem GuiDesigner speichern. Da war es dann nicht mehr da, bzw. stürzte beim Exportieren ab.

Ich hab dann partial genommen, wäre mit lambda natürlich auch gegangen.

Code: Alles auswählen

import tkinter as tk
from tkinter import *
from tkinter import ttk
from functools import partial
 
LARGE_FONT= ("Verdana", 12)
 
def close():
    exit()
 
class SeaofBTCapp(tk.Tk):
 
    def __init__(self, *args, **kwargs):
 
 
       
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
 
        container.pack(side="top", fill="both", expand = True)
 
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
 
        self.frames = {}
 
        for F in (RemoteManager, Benutzereinstellungen, PageTwo):
 
            frame = F(container, self)
 
            self.frames[F] = frame
 
            frame.grid(row=0, column=0, sticky="nsew")
 
        self.show_frame(RemoteManager)
 
#Menu ohne Funktion
 
 
        menubar = tk.Menu(self)
        filemenu = tk.Menu(menubar, tearoff=0)
        hilfemenu = tk.Menu (menubar, tearoff=0)
        filemenu.add_command(label="Komplettes Setup")
        filemenu.add_separator()
        filemenu.add_command(label="Benutzereinstellungen",
                            command=partial(self.show_frame,Benutzereinstellungen))
       
        filemenu.add_command(label="Bildschirmeinstellungen")

        filemenu.add_command(label="Servereinstellungen")
        filemenu.add_separator()
        filemenu.add_command(label="Beenden", command=close)
        menubar.add_cascade(label="Manager", menu=filemenu)
 
        menubar.add_cascade(label="Hilfe", menu=hilfemenu)
        hilfemenu.add_command(label="Info")
 
 
        tk.Tk.config(self, menu=menubar)
 
 
    def show_frame(self, cont):
 
        frame = self.frames[cont]
        frame.lift()
 
 
 #Buttons mit Funktion      
class RemoteManager(tk.Frame):
 
    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
       
        label = tk.Label(self, text="Willkommen im Remote Manager")
        label.pack(pady=15,padx=25)
 
   
        Benutzeranlegen_button = Button(self, text="Benutzereinstellungen", height= 0, width= 18,
                            command=partial(controller.show_frame,Benutzereinstellungen))
        Benutzeranlegen_button.pack()
 
        label1 = tk.Label(self, text="")
        label1.pack(pady=1,padx=25)
       
        Bildschirmeinstellungen_button = Button(self, text="Bildschirmeinstellungen", height= 0, width= 18)
        Bildschirmeinstellungen_button.pack()
 
        label2 = tk.Label(self, text="")
        label2.pack(pady=1,padx=25)
                           
        Servereinstellungen_button = Button(self, text="Servereinstellungen", height= 0, width= 18,
                            command=partial(controller.show_frame,PageTwo))
        Servereinstellungen_button.pack()
 
        label2 = tk.Label(self, text="")
        label2.pack(pady=5,padx=25)
 
 
 
class Benutzereinstellungen(tk.Frame):
 
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
        label.pack (pady=20,padx=10)
 
 
        button1 = tk.Button(self, text="Back to Home")
                            #command=partial(controller.show_frame,StartPage))
        button1.pack()
 
        button2 = tk.Button(self, text="Page Two",
                            command=partial(controller.show_frame,PageTwo))
        button2.pack()
 
 
class PageTwo(tk.Frame):
 
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
        label.pack(pady=10,padx=10)
 
        button1 = tk.Button(self, text="Back to Home")
                            #command=partial(controller.show_frame,StartPage))
        button1.pack()
 
        button2 = tk.Button(self, text="Page One")
                            #command=partial(controller.show_frame,PageOne))
        button2.pack()
 
app = SeaofBTCapp()
app.mainloop()
Dextinator
User
Beiträge: 6
Registriert: Samstag 19. August 2017, 20:42

Alfons Mittelmeyer hat geschrieben:
Dextinator hat geschrieben:Wie müsste der Code aussehen damit es funktioniert? Ich glaube ich würde das ganze besser verstehen wenn ich die Lösung vor Augen habe. Vielen Dank.
Du solltest nichts angeben, was noch nicht da ist, wie StartPage, PageOne und noch ein paar. Programmier nur rein, was Du hast und nicht, was noch nicht da ist.

Dann was soll des das? show_frame ist einmal als Funktion und dann nochmals als Klasse definiert. Kein Wunder, wenn Du nicht mehr weißt, was was ist.

Was mir auch nicht gefallen hatte, der Frame als Parent für das Menü. Wollte Dein Programm mit meinem GuiDesigner speichern. Da war es dann nicht mehr da, bzw. stürzte beim Exportieren ab.

Ich hab dann partial genommen, wäre mit lambda natürlich auch gegangen.

Code: Alles auswählen

import tkinter as tk
from tkinter import *
from tkinter import ttk
from functools import partial
 
LARGE_FONT= ("Verdana", 12)
 
def close():
    exit()
 
class SeaofBTCapp(tk.Tk):
 
    def __init__(self, *args, **kwargs):
 
 
       
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
 
        container.pack(side="top", fill="both", expand = True)
 
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
 
        self.frames = {}
 
        for F in (RemoteManager, Benutzereinstellungen, PageTwo):
 
            frame = F(container, self)
 
            self.frames[F] = frame
 
            frame.grid(row=0, column=0, sticky="nsew")
 
        self.show_frame(RemoteManager)
 
#Menu ohne Funktion
 
 
        menubar = tk.Menu(self)
        filemenu = tk.Menu(menubar, tearoff=0)
        hilfemenu = tk.Menu (menubar, tearoff=0)
        filemenu.add_command(label="Komplettes Setup")
        filemenu.add_separator()
        filemenu.add_command(label="Benutzereinstellungen",
                            command=partial(self.show_frame,Benutzereinstellungen))
       
        filemenu.add_command(label="Bildschirmeinstellungen")

        filemenu.add_command(label="Servereinstellungen")
        filemenu.add_separator()
        filemenu.add_command(label="Beenden", command=close)
        menubar.add_cascade(label="Manager", menu=filemenu)
 
        menubar.add_cascade(label="Hilfe", menu=hilfemenu)
        hilfemenu.add_command(label="Info")
 
 
        tk.Tk.config(self, menu=menubar)
 
 
    def show_frame(self, cont):
 
        frame = self.frames[cont]
        frame.lift()
 
 
 #Buttons mit Funktion      
class RemoteManager(tk.Frame):
 
    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
       
        label = tk.Label(self, text="Willkommen im Remote Manager")
        label.pack(pady=15,padx=25)
 
   
        Benutzeranlegen_button = Button(self, text="Benutzereinstellungen", height= 0, width= 18,
                            command=partial(controller.show_frame,Benutzereinstellungen))
        Benutzeranlegen_button.pack()
 
        label1 = tk.Label(self, text="")
        label1.pack(pady=1,padx=25)
       
        Bildschirmeinstellungen_button = Button(self, text="Bildschirmeinstellungen", height= 0, width= 18)
        Bildschirmeinstellungen_button.pack()
 
        label2 = tk.Label(self, text="")
        label2.pack(pady=1,padx=25)
                           
        Servereinstellungen_button = Button(self, text="Servereinstellungen", height= 0, width= 18,
                            command=partial(controller.show_frame,PageTwo))
        Servereinstellungen_button.pack()
 
        label2 = tk.Label(self, text="")
        label2.pack(pady=5,padx=25)
 
 
 
class Benutzereinstellungen(tk.Frame):
 
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page One!!!", font=LARGE_FONT)
        label.pack (pady=20,padx=10)
 
 
        button1 = tk.Button(self, text="Back to Home")
                            #command=partial(controller.show_frame,StartPage))
        button1.pack()
 
        button2 = tk.Button(self, text="Page Two",
                            command=partial(controller.show_frame,PageTwo))
        button2.pack()
 
 
class PageTwo(tk.Frame):
 
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Page Two!!!", font=LARGE_FONT)
        label.pack(pady=10,padx=10)
 
        button1 = tk.Button(self, text="Back to Home")
                            #command=partial(controller.show_frame,StartPage))
        button1.pack()
 
        button2 = tk.Button(self, text="Page One")
                            #command=partial(controller.show_frame,PageOne))
        button2.pack()
 
app = SeaofBTCapp()
app.mainloop()
Vielen Dank, dass du dir die Arbeit gemacht hast. Funktioniert einwandfrei und ich kann es auch nachvollziehen. Danke nochmal!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Dextinator hat geschrieben: Vielen Dank, dass du dir die Arbeit gemacht hast. Funktioniert einwandfrei und ich kann es auch nachvollziehen. Danke nochmal!
In er Root hast Du einen Frame definiert (container). Dem sollte man unbedingt eine eigene Klasse spendieren. Das ist sogar eine Basisklasse, die Du überall in Deinen Programmen einsetzen kannst. Daher bekommt sie die Klassenliste auch als Parameter.

Dann was auch sehr zu empfehlen ist, ist ein Eventbroker. Damit kann man dann Komponenten der Anwendung unabhängig vom GUI Aufbau durch eine Message aufrufen. Die GUI Struktur ist generiert. sorry, dass ich dann nicht alle labels und Buttons benannt habe.

Code: Alles auswählen

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

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

from functools import partial


# so etwas würde man importieren =================
class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def subscribe(self,message_id,callback):
        self._dictionary_[message_id] = callback
 
    def publish(self,message_id,*args,**kwargs):
        self._dictionary_[message_id](*args,**kwargs)
 
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
# ==============================================


class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.lift_frame = LiftFrame(self,'SHOW_FRAME',(RemoteManager, Benutzereinstellungen, PageTwo))
        self.menu = MainMenu(self)
        self['menu'] = self.menu
        self.lift_frame.pack(fill='both', expand=1)

class LiftFrame(tk.Frame):

    def __init__(self,master,message,class_list,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=0, pad=0, weight=1)
        self.columnconfigure(0,minsize=0, pad=0, weight=1)
        # widget definitions ===================================

        self.frames = {}
        for F in class_list:
            frame = F(self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.lift_frame(class_list[0])

        # message callback ================
        subscribe(message,self.lift_frame)

    def lift_frame(self,frame_id):
        self.frames[frame_id].lift()

class RemoteManager(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.label = tk.Label(self,text='Willkommen im Remote Manager')
        self.button = tk.Button(self,text='Benutzereinstellungen', width=18,command=partial(publish,'SHOW_FRAME',Benutzereinstellungen))
        self.label_2 = tk.Label(self)
        self.button_2 = tk.Button(self,text='Bildschirmeinstellungen', width=18)
        self.label_3 = tk.Label(self)
        self.button_3 = tk.Button(self,text='Servereinstellungen', width=18,command=partial(publish,'SHOW_FRAME',PageTwo))
        self.label_4 = tk.Label(self)
        self.label.pack(pady=15, padx=25)
        self.button.pack()
        self.label_2.pack(pady=1, padx=25)
        self.button_2.pack()
        self.label_3.pack(pady=1, padx=25)
        self.button_3.pack()
        self.label_4.pack(pady=5, padx=25)


class Benutzereinstellungen(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.label = tk.Label(self,text='Page One!!!', font='Verdana 12')
        self.button = tk.Button(self,text='Back to Home',command=partial(publish,'SHOW_FRAME',RemoteManager))
        self.button_2 = tk.Button(self,text='Page Two',command=partial(publish,'SHOW_FRAME',PageTwo))
        self.label.pack(pady=20, padx=10)
        self.button.pack()
        self.button_2.pack()

class PageTwo(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.label = tk.Label(self,text='Page Two!!!', font='Verdana 12')
        self.button = tk.Button(self,text='Back to Home',command=partial(publish,'SHOW_FRAME',RemoteManager))
        self.button_2 = tk.Button(self,text='Page One',command=partial(publish,'SHOW_FRAME',Benutzereinstellungen))
        self.label.pack(pady=10, padx=10)
        self.button.pack()
        self.button_2.pack()

class MainMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.manager_menu = ManagerMenu(self,tearoff=0)
        self.add_cascade(menu=self.manager_menu,label='Manager')
        self.hilfe_menu = HilfeMenu(self,tearoff=0)
        self.add_cascade(menu=self.hilfe_menu,label='Hilfe')

class ManagerMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        self.config(tearoff=0)
        # widget definitions ===================================
        self.add_command(label='Komplettes Setup',command=partial(publish,'SHOW_FRAME',RemoteManager))
        self.add_separator()
        self.add_command(label='Benutzereinstellungen',command=partial(publish,'SHOW_FRAME',Benutzereinstellungen))
        self.add_command(label='Bildschirmeinstellungen')
        self.add_command(label='Servereinstellungen',command=partial(publish,'SHOW_FRAME',PageTwo))
        self.add_separator()
        self.add_command(label='Beenden')

class HilfeMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        self.config(tearoff=0)
        # widget definitions ===================================
        self.add_command(label='Info')

if __name__ == '__main__':
    Application().mainloop()
In Zeile 12 bis 24 ein ganz simpler Eventbroker, mit dem Komponenten der Anwendung über ein callback interface miteinander kommunizieren.

In Zeile 33 wird der LiftFrame angelegt. Die Message und die Klassenliste sin Parameter, damit man diese Klasse auch mehrmals oder auch in anderen Anwendungen mit anderen Messages und Listen einsetzen kann.

Die GUI Struktur ist fein gegliedert, für jedes Container Widget eine eigene Klasse, damit man sich gut zurechtfindet.

Ach so: in RemoteManager hast Du leere Labels als Zwischenräume. Stattdessen nimmt man normalerweise bei pack den Parameter expand=1
Dextinator
User
Beiträge: 6
Registriert: Samstag 19. August 2017, 20:42

Alfons Mittelmeyer hat geschrieben:
Dextinator hat geschrieben: Vielen Dank, dass du dir die Arbeit gemacht hast. Funktioniert einwandfrei und ich kann es auch nachvollziehen. Danke nochmal!
In er Root hast Du einen Frame definiert (container). Dem sollte man unbedingt eine eigene Klasse spendieren. Das ist sogar eine Basisklasse, die Du überall in Deinen Programmen einsetzen kannst. Daher bekommt sie die Klassenliste auch als Parameter.

Dann was auch sehr zu empfehlen ist, ist ein Eventbroker. Damit kann man dann Komponenten der Anwendung unabhängig vom GUI Aufbau durch eine Message aufrufen. Die GUI Struktur ist generiert. sorry, dass ich dann nicht alle labels und Buttons benannt habe.

Code: Alles auswählen

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

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

from functools import partial


# so etwas würde man importieren =================
class EventBroker():
    def __init__(self):
        self._dictionary_ = {}
 
    def subscribe(self,message_id,callback):
        self._dictionary_[message_id] = callback
 
    def publish(self,message_id,*args,**kwargs):
        self._dictionary_[message_id](*args,**kwargs)
 
eventbroker = EventBroker()
publish = eventbroker.publish
subscribe = eventbroker.subscribe
# ==============================================


class Application(tk.Tk):

    def __init__(self,**kwargs):
        tk.Tk.__init__(self,**kwargs)
        # widget definitions ===================================
        self.lift_frame = LiftFrame(self,'SHOW_FRAME',(RemoteManager, Benutzereinstellungen, PageTwo))
        self.menu = MainMenu(self)
        self['menu'] = self.menu
        self.lift_frame.pack(fill='both', expand=1)

class LiftFrame(tk.Frame):

    def __init__(self,master,message,class_list,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # individual grid definition ===========================
        self.rowconfigure(0,minsize=0, pad=0, weight=1)
        self.columnconfigure(0,minsize=0, pad=0, weight=1)
        # widget definitions ===================================

        self.frames = {}
        for F in class_list:
            frame = F(self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.lift_frame(class_list[0])

        # message callback ================
        subscribe(message,self.lift_frame)

    def lift_frame(self,frame_id):
        self.frames[frame_id].lift()

class RemoteManager(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.label = tk.Label(self,text='Willkommen im Remote Manager')
        self.button = tk.Button(self,text='Benutzereinstellungen', width=18,command=partial(publish,'SHOW_FRAME',Benutzereinstellungen))
        self.label_2 = tk.Label(self)
        self.button_2 = tk.Button(self,text='Bildschirmeinstellungen', width=18)
        self.label_3 = tk.Label(self)
        self.button_3 = tk.Button(self,text='Servereinstellungen', width=18,command=partial(publish,'SHOW_FRAME',PageTwo))
        self.label_4 = tk.Label(self)
        self.label.pack(pady=15, padx=25)
        self.button.pack()
        self.label_2.pack(pady=1, padx=25)
        self.button_2.pack()
        self.label_3.pack(pady=1, padx=25)
        self.button_3.pack()
        self.label_4.pack(pady=5, padx=25)


class Benutzereinstellungen(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.label = tk.Label(self,text='Page One!!!', font='Verdana 12')
        self.button = tk.Button(self,text='Back to Home',command=partial(publish,'SHOW_FRAME',RemoteManager))
        self.button_2 = tk.Button(self,text='Page Two',command=partial(publish,'SHOW_FRAME',PageTwo))
        self.label.pack(pady=20, padx=10)
        self.button.pack()
        self.button_2.pack()

class PageTwo(tk.Frame):

    def __init__(self,master,**kwargs):
        tk.Frame.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.label = tk.Label(self,text='Page Two!!!', font='Verdana 12')
        self.button = tk.Button(self,text='Back to Home',command=partial(publish,'SHOW_FRAME',RemoteManager))
        self.button_2 = tk.Button(self,text='Page One',command=partial(publish,'SHOW_FRAME',Benutzereinstellungen))
        self.label.pack(pady=10, padx=10)
        self.button.pack()
        self.button_2.pack()

class MainMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        # widget definitions ===================================
        self.manager_menu = ManagerMenu(self,tearoff=0)
        self.add_cascade(menu=self.manager_menu,label='Manager')
        self.hilfe_menu = HilfeMenu(self,tearoff=0)
        self.add_cascade(menu=self.hilfe_menu,label='Hilfe')

class ManagerMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        self.config(tearoff=0)
        # widget definitions ===================================
        self.add_command(label='Komplettes Setup',command=partial(publish,'SHOW_FRAME',RemoteManager))
        self.add_separator()
        self.add_command(label='Benutzereinstellungen',command=partial(publish,'SHOW_FRAME',Benutzereinstellungen))
        self.add_command(label='Bildschirmeinstellungen')
        self.add_command(label='Servereinstellungen',command=partial(publish,'SHOW_FRAME',PageTwo))
        self.add_separator()
        self.add_command(label='Beenden')

class HilfeMenu(tk.Menu):

    def __init__(self,master,**kwargs):
        tk.Menu.__init__(self,master,**kwargs)
        self.config(tearoff=0)
        # widget definitions ===================================
        self.add_command(label='Info')

if __name__ == '__main__':
    Application().mainloop()
In Zeile 12 bis 24 ein ganz simpler Eventbroker, mit dem Komponenten der Anwendung über ein callback interface miteinander kommunizieren.

In Zeile 33 wird der LiftFrame angelegt. Die Message und die Klassenliste sin Parameter, damit man diese Klasse auch mehrmals oder auch in anderen Anwendungen mit anderen Messages und Listen einsetzen kann.

Die GUI Struktur ist fein gegliedert, für jedes Container Widget eine eigene Klasse, damit man sich gut zurechtfindet.

Ach so: in RemoteManager hast Du leere Labels als Zwischenräume. Stattdessen nimmt man normalerweise bei pack den Parameter expand=1
Vielen vielen Dank! Damit kann ich gut weiter arbeiten. Einen schönen Sonntag noch.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Dextinator hat geschrieben:Vielen vielen Dank! Damit kann ich gut weiter arbeiten. Einen schönen Sonntag noch.
Übrigens: es geht auch wesentlich kürzer: viewtopic.php?f=18&t=41126
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Dextinator: es gibt auch noch eine Art ein GUI Programm zu schreiben, nämlich:

Wenn der GUI Code keine Logik enthält, hann man ihn x-beliebig schreiben, Haupsache es sind Namen drin. Die Logik schreibt man dann nach Laden der GUI. Bei kleineren Programmen ist das sicher sehr übersichtlich:

Code: Alles auswählen

import tkinter as tk
import screen
import builder
from functools import partial

def main():

    root = tk.Tk()
    screen.screen(root) # screen laden

    widget = builder.Builder(root).get_object

    frames = {
        'remote_manager' : widget('remote_manager'),
        'page_one' : widget('page_one'),
        'page_two' : widget('page_two'),
    }

    def show_frame(frame_id):
        frames[frame_id].lift()

    remote_manager = partial(show_frame,'remote_manager')
    page_one = partial(show_frame,'page_one')
    page_two = partial(show_frame,'page_two')

    manager_menu = widget('manager_menu')
    manager_menu.entryconfig(manager_menu.items['remote_manager_index'],command=remote_manager)
    manager_menu.entryconfig(manager_menu.items['page_one_index'],command=page_one)
    manager_menu.entryconfig(manager_menu.items['page_two_index'],command=page_two)

    widget('remote_manager_button_for_page_one')['command'] = page_one
    widget('remote_manager_button_for_page_two')['command'] = page_two
    widget('page_one_button_for_remote_manager')['command'] = remote_manager
    widget('page_one_button_for_page_two')['command'] = page_two
    widget('page_two_button_for_remote_manager')['command'] = remote_manager
    widget('page_two_button_for_page_one')['command'] = page_one

    root.mainloop()

if __name__ == '__main__':
    main()
Siehe: viewtopic.php?f=18&t=41126&start=15
Antworten