Warten auf das Toplevel-Ende

Fragen zu Tkinter.
Antworten
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Was muss ich machen, damit nach der Erzeugung eines Toplevel Fensters die Programmausführung auf das Beenden desselben wartet ?
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@Blackjack: Vielen Dank mal wieder für deine Antwort.
allerdings bin ich immernoch in einer C-Extension, deshalb kann ich diese Lösung nicht benutzen. Wenn ich "tkMessageBox" verwende - also einen Dialog, wartet das C-Modul auf den return Value, mit einem normalen "Toplevel", weiß ich nicht wie ich es einrichten soll, daß der return Value erst nach oder kurz vor "destroy" übergeben wird.
BlackJack

@hypnoticum: Was hat das denn damit zu tun, dass Du das von einer C-Erweiterung aus umsetzen willst? Wenn es in Python geht, dann geht es doch auch in C!? Ich verstehe auch nicht so ganz was Du willst -- die Programmausführung soll angehalten werden, aber es ist ein Problem wenn dabei das Programm anhält!? Das widerspricht sich irgendwie.
problembär

hypnoticum hat geschrieben:Wenn ich "tkMessageBox" verwende - also einen Dialog, wartet das C-Modul auf den return Value, mit einem normalen "Toplevel", weiß ich nicht wie ich es einrichten soll, daß der return Value erst nach oder kurz vor "destroy" übergeben wird.
Ganz ähnlich wie neulich:

Code: Alles auswählen

#!/usr/bin/env python
# coding: iso-8859-1

import Tkinter

class Command:
    def __init__(self, master):
        self.master = master
        self.Dia = Tkinter.Toplevel()
        self.master.wait_window(self.Dia)

    def getVal(self):
        return "A Value."
       
class TestGUIMain:
    def __init__(self):
        self.mw = Tkinter.Tk()
        self.RunBtn = Tkinter.Button(master = self.mw,
                                     text = 'Run',
                                     command = self.RunTest)
        self.RunBtn.grid()                
        self.mw.mainloop()

    def RunTest(self):
        print"Start"
        ComDia = Command(self.mw)
        print ComDia.getVal()
        print "Continued"
 
if __name__ == "__main__":
    TestGUIMain()
Gruß
problembär

Nochmal zur Erklärung: Wenn das Toplevel-Objekt mit ".destroy()" gelöscht wird, bleibt Dein darumherumgebautes Objekt (im Beispiel ein Objekt der Klasse "Command") trotzdem bestehen. Auch wenn es nicht als grafisches Element sichtbar ist.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Das Problem ist, daß ja nicht ein anderes Fenster auf den "return"-Wert warten soll, sondern die Extension nachdem von dieser eine Instanz der Klasse Command erzeugt wurde.
Es soll halt so funktionieren wie bei einer Messagebox
BlackJack

@hypnoticum: Können wir die C-Erweiterung vielleicht erst einmal aus der Gleichung heraus nehmen? Denn ob Du das nun von C oder von Python aus machen willst, sollte irrelevant sein. Wenn man das in Python ausdrücken kann, lässt es sich auch auf C übertragen. Aber in Python können wir einfacher darüber reden und lauffähigen, kurzen Quelltext verwenden.

Grundsätzlich habe ich den Verdacht, dass Du etwas machen möchtest, was sich mit der ereignisbasierten Programmierung von GUIs nicht verträgt. Da würdest Du Dein Toplevel erstellen und Funktionen für Ereignisse, zum Beispiel Button-Drücke und Fenster schliessen, registrieren, und dann nicht warten, sondern einfach zurück kehren, damit die `mainloop()` weiterlaufen kann, ohne welche die GUI sowieso "tot" ist und sich nicht bedienen lässt. Wenn der Benutzer dann das Fenster schliesst, wird Deine Funktion aufgerufen, und Du kannst den Wert abfragen.
problembär

hypnoticum hat geschrieben:Das Problem ist, daß ja nicht ein anderes Fenster auf den "return"-Wert warten soll, sondern die Extension nachdem von dieser eine Instanz der Klasse Command erzeugt wurde.
Es soll halt so funktionieren wie bei einer Messagebox
Zeig' doch mal, wie Du das jetzt nach den bisherigen Postings machen würdest. Dann könnte man das ggf. noch verbessern. Ansonsten stockt das Thema dann hier :(.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Alles in Ordnung - vielen Dank die Antworten. :D
Es funktioniert jetzt. Ich Habe "self.master = None" gesetzt, da ich wie gesagt keinen Handle vom Fenster aus C übergebe.

Code: Alles auswählen

class Command(object):
    def __init__(self, InstrumentHdl):
        self.Hdl = InstrumentHdl
        self.master = None
        self.Dia = Tkinter.Toplevel()
        self.__widgets_start__()
        self.TxtBx.focus_set()
        self.Dia.wait_window(self.master)
(Es öffnet sich dann der Dialog ohne ein weiteres Fenster, allerdings habe ich schon ein Fenster offen.
Ich weiß nicht wie es sich verhält, wenn man nur das Toplevel öffnen will)
problembär

Hmm, "self.TxtBx" war jedenfalls in dem Beispiel noch gar nicht definiert. Ist wohl nur ein Code-Auszug.
Aber:

Code: Alles auswählen

self.Dia.wait_window(self.master)
Das ist falschrum. Es muß heißen:

Code: Alles auswählen

self.master.wait_window(self.Dia)
Aber auch das kann natürlich nicht klappen, wenn "self.master" gleich "None" ist. "self.master" muß dafür das "Tkinter.Tk()"-Fenster sein, das zu diesem Zweck der "Command"-Klasse mit übergeben werden muß:

Code: Alles auswählen

class Command:
    def __init__(self, master):
        self.master = master
        self.Dia = Tkinter.Toplevel()
        self.master.wait_window(self.Dia)
Das bedeutet so viel wie:
Hauptfenster, warte bitte, bis das Dialogfenster wieder geschlossen ist.
Ist doch logisch, oder?

Gruß
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

logisch ist es - funktionieren tut es aber nur anders herum, weil ich kein master habe.
(assembler wär mir lieber, da kann man noch "sehen" was passiert)
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Sagt mal, täusch ich mich oder erfindet ihr den "tkSimpleDialog.Dialog" gerade neu ?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
problembär

Hast schon recht, aber manchmal sind mir die fertigen Dialoge nicht flexibel genug. Dann muß ein eigener her. Ich bin mal davon ausgegangen, daß bei dem OP so ein Fall vorliegt. Wenn nicht, nicht mein Problem ...
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

"tkSimpleDialog.Dialog" ist doch extra zum Bau von eigenen Dialogen gemacht. Einfach ableiten und die "body"-Methode überschreiben, dort kann man die Widgets die sich auf diesem befinden sollen festlegen. Wenn man das Ok, Abbrechen nicht haben möchte muss man die "buttonbox"-Methode mit einem "pass" als Anweisung überschreiben. So schwer ist das nun nicht und man fängt nicht an das Rad neu zu erfinden.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
problembär

Xynon1 hat geschrieben:"tkSimpleDialog.Dialog" ist doch extra zum Bau von eigenen Dialogen gemacht. Einfach ableiten und die "body"-Methode überschreiben, dort kann man die Widgets die sich auf diesem befinden sollen festlegen. ... So schwer ist das nun nicht und man fängt nicht an das Rad neu zu erfinden.
Das mag schon sein. Manchmal brauche ich aber wirklich große Dialogfelder, auf denen sich neben den Buttons noch 5 Labels, 5 Entries, ein paar Radiobuttons und vieleicht noch ein/zwei Scales befinden. Wahrscheinlich kann man da auch mit "tkSimpleDialog" arbeiten, aber dann muß man sowieso so viel überschreiben, da kann man auch gleich eine eigene Klasse schreiben.
hypnoticum hat geschrieben:logisch ist es - funktionieren tut es aber nur anders herum, weil ich kein master habe.
Das sieht vielleicht so aus, aber irgendwann wird Dir so der Mainloop abstürzen. Dein Programm ist dann also instabil. Bevor ich ein sauberes ".wait_window()" hinbekommen habe, ist mir ein paarmal ein Absturz passiert.

Gruß
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Nach dem Prinzip kann bzw. muss man immer was eigenes schreiben. Aber der Dialog bietet einen guten Ansatz ohne selbst "rumprobieren" zu müssen. Letztlich ist es sicherlich egal.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Beim nächsten mal werde ich den tkSimpleDialog.Dialog ausprobieren.
vielleicht sollte man es besser statt "master" als "slave" bezeichnen um etwas Verwirrung rauszunehmen:

Code: Alles auswählen

self.slave = None
...
self.Dia.wait_window(self.slave)
BlackJack

@hypnoticum: Du wartest auf ein `master`, dass Du `slave` nennst und findest das weniger verwirrend!? :shock:
Antworten