@moccajoghurt: Es darf nur ein `Tk`-Exemplar geben und man darf nur aus dem Hauptthread aus GUI-Objekte manipulieren. Solange Du das nicht repariert hast, kann nahezu *alles* passieren, denn Dein Programm hat schlicht kein definiertes Verhalten mehr.
Ansonsten: Am Ende von `download_bar.__init__()` rufst Du eine `mainloop()` auf. Dieser Aufruf kehrt erst zurück wenn das zugehörige Widget zerstört wurde. Du bindest also tatsächlich `mainclass.dl_bar` an keinen Wert bevor es benutzt wird, denn der Aufruf kehrt nicht zurück. Ähnlich wie es nur ein `Tk`-Exemplar geben darf, sollte man nur eine `mainloop()` aufrufen. Das heisst auf deutsch *Haupt*schleife.
Klassenattribut ist nach Erstellung nicht mehr ansprechbar
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Ok jetzt verstehe ich!
Ist es denn möglich eine Progressbar in die Mitte des Hauptfensters zu setzen, ohne dass die anderen Widgets berücksichtigt werden müssen? Das war nämlich der Hauptgrund aus dem ich einfach ein neues Tk() erstellt habe. Ich möchte die Progressbar als unabhängige über den Hauptfenster schwebende Leiste. Geht das?
Ansonsten erstmal danke für die hilfreichen Antworten.
Ist es denn möglich eine Progressbar in die Mitte des Hauptfensters zu setzen, ohne dass die anderen Widgets berücksichtigt werden müssen? Das war nämlich der Hauptgrund aus dem ich einfach ein neues Tk() erstellt habe. Ich möchte die Progressbar als unabhängige über den Hauptfenster schwebende Leiste. Geht das?
Ansonsten erstmal danke für die hilfreichen Antworten.
@moccajoghurt: `Tk` ist sozusagen das Hauptfenster. Wenn man weitere Fenster haben möchte kann man `Toplevel` dafür verwenden.
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Hätte ich das vorher gewusst, hätte ich mir viele Stunden rumprobieren gespart. Aber jetzt weiß ich es.BlackJack hat geschrieben:@moccajoghurt: `Tk` ist sozusagen das Hauptfenster. Wenn man weitere Fenster haben möchte kann man `Toplevel` dafür verwenden.
Vielen Dank nochmal an alle, Thema ist gelöst.
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Habe jetzt ein anderes Problem mit der Scrollbar. Alles funktioniert eigentlich wie gewollt, nur wenn die Scrollbar zusammen mit dem Toplevel zerstört werden soll, dann bleibt sie, obwohl das Toplevel zerstört wurde, immernoch sichtbar.
Hier die Klasse:
Wie bekomme ich es hin, dass die Progressbar auch nicht mehr sichtbar ist?
Hier die Klasse:
Code: Alles auswählen
from ttk import Progressbar
import Tkinter
class download_bar():
def __init__(self, main):
self.mainclass = main
self.window = Tkinter.Toplevel()
self.window.overrideredirect(True)
self.bar = Progressbar(self.window, length=200)
self.bar.pack(expand=True, fill=Tkinter.BOTH)
self.bar.configure(mode="indeterminate", length=150)
self.loop_bar()
def loop_bar(self):
self.bar.start(interval=1)
def kill_bar(self):
self.bar.stop()
#~ self.bar.pack_forget()
#~ self.bar.destroy()
#~ self.window.withdraw()
self.window.destroy()
@moccajoghurt: Das kann ich nicht nachvollziehen. Das kann aber eventuell daran liegen, dass Du `Toplevel` kein „Master”-Widget übergibst. Das hier funktioniert bei mir jedenfalls — nach zwei Sekunden (2000 ms) verschwindet der Balken:
Bei Python 2.x sollte man immer von `object` erben um „new style”-Klassen zu bekommen, bei denen alles so funktioniert wie in der Dokumentation beschrieben (Vererbungshierarchie, `property()`, …).
Wie schon gesagt: Typen sollte man wenn möglich aus Namen heraus halten. Zumal wenn sie wie bei `self.mainclass` wahrscheinlich nicht stimmen, denn ich gehe mal davon aus, dass an das Attribut keine *Klasse* gebunden wird, sondern ein Exemplar.
Das `overrideredirect()` würde mich in den Wahnsinn treiben. Da bekommt man ein GUI-Element irgendwo auf den Bildschirm geklatscht — bei mir ist es anscheinend immer links oben in der Ecke — das man als Benutzer überhaupt nicht beeinflussen kann.
Code: Alles auswählen
import Tkinter as tk
from ttk import Progressbar
class DownloadBar(object):
def __init__(self, master, main=None):
self.mainclass = main
self.window = tk.Toplevel(master)
self.window.overrideredirect(True)
self.bar = Progressbar(self.window, length=150, mode='indeterminate')
self.bar.pack(expand=True, fill=tk.BOTH)
self.loop_bar()
def loop_bar(self):
self.bar.start(interval=1)
def kill_bar(self):
self.bar.stop()
self.window.destroy()
def main():
root = tk.Tk()
bar = DownloadBar(root)
root.after(2000, bar.kill_bar)
root.mainloop()
if __name__ == '__main__':
main()
Wie schon gesagt: Typen sollte man wenn möglich aus Namen heraus halten. Zumal wenn sie wie bei `self.mainclass` wahrscheinlich nicht stimmen, denn ich gehe mal davon aus, dass an das Attribut keine *Klasse* gebunden wird, sondern ein Exemplar.
Das `overrideredirect()` würde mich in den Wahnsinn treiben. Da bekommt man ein GUI-Element irgendwo auf den Bildschirm geklatscht — bei mir ist es anscheinend immer links oben in der Ecke — das man als Benutzer überhaupt nicht beeinflussen kann.
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Ich habe die Klasse so umgeschrieben, dass nurnoch ein Toplevel erstellt wird, dass danach zerstört werden soll:
Die .destroy() Funktion wird zwar aufgerufen (der print wird ausgegeben), allerdings ist das Fenster noch sichtbar. Es antwortet allerdings nicht mehr auf Klicks (z.B. minimieren, maximieren, schließen). Verschieben kann ich es noch.
Woran kann das liegen?
Die andern angesprochenen Punkte werde ich wenn ich das Problem gelöst habe noch korrigieren.
Code: Alles auswählen
from ttk import Progressbar
import Tkinter
class download_bar(object):
def __init__(self, main):
self.mainclass = main
self.window = Tkinter.Toplevel(self.mainclass.main_window.window)
def kill_bar(self):
self.window.destroy()
print("######DESTROYED######")
Woran kann das liegen?
Die andern angesprochenen Punkte werde ich wenn ich das Problem gelöst habe noch korrigieren.
@moccajoghurt: Für das verschieben ist die Fensterverwaltung zuständig und nicht das GUI-Toolkit.
Von wo aus wird denn die `kill_bar()`-Methode aufgerufen? Aus einem anderen Thread als dem impliziten Hauptthread wo die `mainloop()` läuft? Und kehrt der Aufruf der Methode auch zu der `mainloop()` zurück?
Bei ``self.mainclass.main_window.window`` würde ich sagen da hat die Klasse zu viel Wissen über das als `main` übergebene Objekt. Und ``main_window.window`` bedeutet eventuell, dass es eine Ebene gibt, genau wie bei ``download_bar.window`` die man sich durch Vererbung sparen könnte.
Von wo aus wird denn die `kill_bar()`-Methode aufgerufen? Aus einem anderen Thread als dem impliziten Hauptthread wo die `mainloop()` läuft? Und kehrt der Aufruf der Methode auch zu der `mainloop()` zurück?
Bei ``self.mainclass.main_window.window`` würde ich sagen da hat die Klasse zu viel Wissen über das als `main` übergebene Objekt. Und ``main_window.window`` bedeutet eventuell, dass es eine Ebene gibt, genau wie bei ``download_bar.window`` die man sich durch Vererbung sparen könnte.
Hi moccajoghurt
Funktioniert bei mir ohne Probleme:
Gruß wuf
Funktioniert bei mir ohne Probleme:
Code: Alles auswählen
from ttk import Progressbar
import Tkinter as tk
class DownLoadBar(object):
def __init__(self, main):
self.mainclass = main
self.window = tk.Toplevel(self.mainclass)
self.window.title('Top')
self.window.protocol("WM_DELETE_WINDOW", self.kill_bar)
def kill_bar(self):
self.window.destroy()
print("######DESTROYED######")
#----- MODUL_TEST -------------------------------------------------------------#
if __name__ == '__main__':
root = tk.Tk()
root.title('Main')
down_load = DownLoadBar(root)
root.mainloop()
Take it easy Mates!
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Kann es sein, dass es daran liegt, dass ich das Toplevel erst erzeuge, wenn ein event in der mainloop stattfindet und es dadurch erst "nach" der mainloop erstellt wird?
Ich werde es jetzt mal so probieren, dass ich das Toplevel vor dem Start der mainloop erstelle und es erst nach dem event sichtbar mache.
Ich werde es jetzt mal so probieren, dass ich das Toplevel vor dem Start der mainloop erstelle und es erst nach dem event sichtbar mache.
@moccajoghurt: Nein das kann nicht das Problem sein. Natürlich kann man zur Laufzeit neue Fenster erstellen. Denk mal an IDLE, da kannst Du doch zu beliebigen Zeitpunkten beliebig viele neue Editorfenster öffnen.
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Ok ich habe festgestellt, dass ich das Toplevel in einem anderen Thread zerstören möchte, als es erstellt wurde. Es handelt sich dabei um einen Thread, der parallel zur mainloop läuft. Ich gehe gerade davon aus, dass es daran liegen könnte.
Jetzt brauche ich eine Möglichkeit der mainloop mitzuteilen, dass der Vorgang des anderen Threads abgeschlossen ist und er das Toplevel zerstören kann.
Wie löse ich das am elegantesten?
Mein Ansatz ist es jetzt eine Warteschleife in die mainloop zu packen, die eine Variable überprüft, die vom anderen Thread geändert wird, sobald dieser fertig ist. Bei Java sind für solche Variablen das Schlüsselwort "volatile" nötig. Gibt es sowas auch für Python?
Oder ist ein anderer Ansatz vielleicht besser?
Jetzt brauche ich eine Möglichkeit der mainloop mitzuteilen, dass der Vorgang des anderen Threads abgeschlossen ist und er das Toplevel zerstören kann.
Wie löse ich das am elegantesten?
Mein Ansatz ist es jetzt eine Warteschleife in die mainloop zu packen, die eine Variable überprüft, die vom anderen Thread geändert wird, sobald dieser fertig ist. Bei Java sind für solche Variablen das Schlüsselwort "volatile" nötig. Gibt es sowas auch für Python?
Oder ist ein anderer Ansatz vielleicht besser?
@moccajoghurt: Eine warteschleife würde ja die `mainloop()` blockieren. Du kannst mit hilfe der `after()`-Methode regelmässig eine Funktion im richtigen Thread aufrufen der das Ende des Threads testet und dann gegebenenfalls das Fenster schliesst.
-
- User
- Beiträge: 23
- Registriert: Freitag 20. Juli 2012, 15:12
Es klappt!
Danke.
Danke.