Warten auf das Toplevel-Ende
-
- 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: Hier wird das recht ausführlich erklärt: http://www.pythonware.com/library/tkint ... indows.htm
-
- 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.
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.
@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.
Ganz ähnlich wie neulich: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.
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()
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.
-
- 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
Es soll halt so funktionieren wie bei einer Messagebox
@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.
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.
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 hierhypnoticum 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

-
- User
- Beiträge: 132
- Registriert: Dienstag 15. März 2011, 15:43
Alles in Ordnung - vielen Dank die Antworten.
Es funktioniert jetzt. Ich Habe "self.master = None" gesetzt, da ich wie gesagt keinen Handle vom Fenster aus C übergebe.
(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)

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)
Ich weiß nicht wie es sich verhält, wenn man nur das Toplevel öffnen will)
Hmm, "self.TxtBx" war jedenfalls in dem Beispiel noch gar nicht definiert. Ist wohl nur ein Code-Auszug.
Aber:
Das ist falschrum. Es muß heißen:
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ß:
Das bedeutet so viel wie:
Gruß
Aber:
Code: Alles auswählen
self.Dia.wait_window(self.master)
Code: Alles auswählen
self.master.wait_window(self.Dia)
Code: Alles auswählen
class Command:
def __init__(self, master):
self.master = master
self.Dia = Tkinter.Toplevel()
self.master.wait_window(self.Dia)
Ist doch logisch, oder?Hauptfenster, warte bitte, bis das Dialogfenster wieder geschlossen ist.
Gruß
-
- 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)
(assembler wär mir lieber, da kann man noch "sehen" was passiert)
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 ...
"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.
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.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 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.hypnoticum hat geschrieben:logisch ist es - funktionieren tut es aber nur anders herum, weil ich kein master habe.
Gruß
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.
-
- 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:
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)
@hypnoticum: Du wartest auf ein `master`, dass Du `slave` nennst und findest das weniger verwirrend!? 
