2 command Befehle mit einem Button verbinden - lambda

Fragen zu Tkinter.
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

Hallo :) Versuche den Button B0 gerade so zu konfigurieren, dass er einerseits das vorherige Fenster schließt (was mir mit der myfunction Funktion auch gelingt), andererseits soll das Programm nach Betätigung von B0 in eine weitere Funktion namens Initialisierung springen, die dann ein weiteres Fenster öffnet.
Ich benutze die lambda Funktion, um dem command Befehl des Buttons 2 Anweisungen zu übertragen.
Verstehe allerdings nicht, wie ich der zweiten Funktion myfunction2 sagen soll, dass sie zu Initialisierung springen soll. Einen jump Befehl oä gibt es ja nicht..

Code: Alles auswählen


def myfunction(root):


    root.quit()
    return
def myfunction2():



B0 = Button(root,text="Prüfprogramm starten",command = lambda: [myfunction(root),myfunction2()])



wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

Ich will mit der zweiten Funktion einfach nur den "command = Initalisierung" Befehl ersetzen
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Es gibt gar keine Initialisierung. Bitte posten vollständigen Code.
Man erzeugt keine Listen, nur um Funktionen aufzurufen. Rufe in myfunction einfach myfunction2 auf, oder schreib eine dritte Funktion, die beides aufruft.
Benutzeravatar
__blackjack__
User
Beiträge: 14085
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wulf3000: Du missbrauchst ``lambda`` hier, beziehungsweise die Liste. Wenn Du etwas komplizierteres als einen einfachen Ausdruck hast, dann definiere eine Funktion und versuche das nicht mit dreckigen Tricks in einen Lambda-Ausdruck zu pressen.

Falls `root` das ist was der Name suggeriert, nämlich ein `Tk`-Objekt, dann geht das *so* gar nicht, denn `myfunction2()` würde bei einem noch existierenden `Tk`-Objekt ausgeführt, würde aber nach Deiner Beschreibung ein weiteres, neues `Tk`-Objekt erstellen, womit für diese Zeit zwei davon gleichzeitig existieren würden.

Falls `myfunction()` inhaltlich tatsächlich *so* aussieht, ist die Funktion überflüssig, denn die macht ja nichts anderes als `root.quit()`.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

Ich habe nur einen Teil des Codes gepostet, weil es dann viel übersichtlicher ist. Die Funktion Initialisierung öffnet lediglich ein weiteres Fenster. Von dort aus geht dann das Programm weiter.

Ich will dass der command Befehl 2 Dinge ausführt:
1.Das alte Fenster schließen
2.Ein neues Fenster öffnen
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

@Sirius3: Die Funktion sieht also so aus

Code: Alles auswählen

 def Initialisierung():
 root = Tk()
 root.title = Laetus
 lab0 = Label (root, text = "Test")
 lab0.pack()
Sie soll also lediglich ein neues Fenster mit einem neuen GUI öffnen
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

@wulf3000: Sowohl hier als auch in deinem anderen Thread wurde dir doch gesagt, dass in einer Anwendung gleichzeitig nur ein tk.Tk-Objekt gleichzeitig existieren darf. Weitere Fenster erzeugt man mit tk.TopLevel.
So wie ich das sehe hast du alle anderen Hinweise dort auch ignoriert. So wie die Antworten hier.
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

@sparrow: Nein nicht ignoriert. Aber was hat das mit der Frage zutun. Dann steht da eben:

Code: Alles auswählen

top = Toplevel()
top.title("Prüfplatz")
Ist das nicht völlig irrelevant für meine eigentliche Frage die ganz oben steht. Alle Dinge die mir geraten werden versuche ich umzusetzten. Vielleicht wäre 1-2 Zeilen Code manchmal hilfreicher als weitere Änderungsvorschläge, die ich als Anfänger nicht umsetzen kann
Benutzeravatar
DeaD_EyE
User
Beiträge: 1253
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Code: Alles auswählen

from tkinter import Tk, Button, Toplevel, Label


COUNTER = 0
windows = []


def close_all():
    for window in windows:
        window.destroy()
    windows.clear()


def close_and_open():
    global COUNTER
    COUNTER += 1
    close_all()
    window = Toplevel()
    window.geometry("400x200+700+400")
    Label(window, text=str(COUNTER)).pack()
    Button(window, text="Fenster schließen", command=window.destroy).pack()
    windows.append(window)


root = Tk()
Button(root, text="Neues Fenster", command=close_and_open).pack()
Button(root, text="Beenden", command=root.destroy).pack()
root.mainloop()


Ich habe es mit Absicht nicht als Klasse geschrieben.
COUNTER ist eine globale Variable, die vermieden werden sollte.
In dem Beispiel dient sie lediglich zur Anzeige wie oft die Funktion ausgeführt worden ist.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

@DeaD_EyE: auch windows ist eine globale Variable. Da in der Liste immer nur ein Element sein kann, zu dem aber eventuell auch schon gar kein Fenster mehr existiert, ist das alles sehr komisch.
COUNTER ist wie eine Konstante geschrieben, das ist aber gar keine Konstante. Globale Variablen sind schon nicht gut, variable Konstanten aber noch viel weniger.
Das ist so ein typsiche Beispiel, wo man gar nicht um Klassen drumherum kommt.

Code: Alles auswählen

from tkinter import Tk, Button, Toplevel, Label

class Application:
    def __init__(self):
        self.window = None
        self.counter = 0
        self.root = Tk()
        Button(self.root, text="Neues Fenster", command=self.open_window).pack()
        Button(self.root, text="Beenden", command=self.root.destroy).pack()
    
    def close_window(self):
        if self.window is not None:
            self.window.destroy()
        self.window = None
    
    def open_window(self):
        self.close_window()
        self.counter += 1
        self.window = Toplevel()
        Label(self.window, text=self.counter).pack()
        Button(self.window, text="Fenster schließen", command=self.close_window).pack()

def main():
    application = Application()
    application.root.mainloop()
    
if __name__ == '__main__':
    main()
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

Also erst einmal danke für ihre Antworten und ihr Bemühen mir weiterzuhelfen!


Der Button "neues Fenster" führt ja lediglich zum Öfnnen des zweiten Fensters.
Leider schließt das erste Fenster aber nicht beim Öffnen des zweiten Fensters, was ja ursprünglich mal mein Problem war.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

@wulf3000: das root-Fenster sollte auch nicht geschlossen werden, weil es üblicherweise das Hauptfenster ist, das immer offen ist.
Was willst Du denn eigentlich machen. Erzähl doch mal mehr von Deinem Programm.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1253
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

@DeaD_EyE: auch windows ist eine globale Variable.
Für mich sind globale "Variablen" ausschließlich Namen, denen ich in einer Funktion ein neues Objekt zuweise und dafür das Schlüsselwort `global` verwenden muss.
`windows` wird hingegen mutiert und nicht neu zugewiesen. Das ist ein wichtiger Unterschied.

Da in der Liste immer nur ein Element sein kann, zu dem aber eventuell auch schon gar kein Fenster mehr existiert, ist das alles sehr komisch.
Trick 2000: Meine Intention war, keine globale Variable und keine Klasse zu verwenden. Je nachdem welchen Knopf man zuerst anklickt, wird die Methode `destroy` zweimal aufgerufen. Das ist nicht schön.
COUNTER ist wie eine Konstante geschrieben, das ist aber gar keine Konstante. Globale Variablen sind schon nicht gut, variable Konstanten aber noch viel weniger.
Konnte ich in der PEP8 leider nicht finden. Ich habe bezüglich dessen schon unterschiedliche Meinungen gelesen.
Das ist so ein typsiche Beispiel, wo man gar nicht um Klassen drumherum kommt.
Ja, aber für Anfänger nicht gerade der beste Einstiegspunkt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Oh Gott, der Geist von Alfons M weilt unter uns. “Es kein globaler Zustand, denn ich habe global nicht benutzt, sondern modifiziere ein Objekt, das nur einmal im Interpreter existiert” ist semantisch das gleiche wie eine globale Variable. Das als Verteidigung anzuführen ist wie ein kleines Kind, das sagt “ich habe Timmi nicht gehauen, es war der Stock in meiner Hand!” 🙄
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

DeaD_EyE hat geschrieben: Dienstag 1. September 2020, 15:58Konnte ich in der PEP8 leider nicht finden. Ich habe bezüglich dessen schon unterschiedliche Meinungen gelesen.
Wenn man danach sucht, ist es kaum zu übersehen.
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

@Sirius 3: Also zu meinem Programm: Es ist ein Prüfplatz. Am Anfang erscheint ein kleines Fensterchen in dem man ausschließlich "Prüfprogramm starten" oder das ganze wieder schließen kann. Nach Betätigung von Prüfprogramm starten, öffnet sich das eigentliche Testfenster, was beim gesamten Test offen bleiben soll. Das erste Fenster soll dann zugehen, da es nicht mehr gebraucht wird.
Klickt man auf Test starten öffnen sich weitere Fenster mit Anweisungen an den User, damit jener den Test richtig ausführt.

Meine Frage bezog sich jetzt allein auf das Problem, dass ich das allererste Fenster bei Klicken auf "Prüfprogramm starten" sowohl schließen, als auch das zweite Fenster öffnen will.

Da ich bei der command Funktion nur einen Befehl für den Button "Prüfprogramm starten" übergeben kann, war meine Frage, wie ich die umgehe und ob es da eine Möglichkeit gibt.
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Für was braucht man ein Fenster, in dem nur "Prüfprogramm starten" angeklickt werden kann? Orientiere Dich bei der Programmführung an dem, was Du aus anderen Programmen her kennst.
Und wie schon im anderen Thread geschrieben, mußt Du Dich von der Vorstellung lösen, dass es einen roten Faden in Deinem Programm gibt, wo verschiedene Dinge nacheinander Ablaufen. Bei GUI-Programmen gibt es eine Hauptschleife, die alles steuert, und Du kannst da nur für kurze Zeit kleine isolierte Dinge tun.
Was Deiner beschreibung am Nächsten kommt, ist, dass das Testfenster das Hauptfenster ist, und dass Du zusätzlich noch ein Dialogfenster öffnest, das den Zugriff auf das Hauptfenster erst erlaubt, wenn es geschlossen wird (warum auch immer das sinnvoll sein soll).
wulf3000
User
Beiträge: 20
Registriert: Montag 31. August 2020, 10:46

@Sirius: Na das ist einfach eine Vorgabe meines Chefs. Und optisch ist ein Prüfplatz mit einem Startfenster halt einfach schöner.

Ja genau, dein letzter Satz beschreibt die Funktion ganz gut
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Warum ersetzt du denn nicht den Inhalt des Fensters statt ein neues aufzumachen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

„Vorgabe meines Chefs“ - es gibt viel Zuviel Unsinn in dieser Welt, der durch so eine Nummer das Licht derselben erblickt hat 🤦‍♂️
Antworten