Seite 1 von 2
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Donnerstag 2. August 2012, 18:04
von BlackJack
@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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Donnerstag 2. August 2012, 20:55
von moccajoghurt
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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Donnerstag 2. August 2012, 21:16
von BlackJack
@moccajoghurt: `Tk` ist sozusagen das Hauptfenster. Wenn man weitere Fenster haben möchte kann man `Toplevel` dafür verwenden.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Freitag 3. August 2012, 00:27
von moccajoghurt
BlackJack hat geschrieben:@moccajoghurt: `Tk` ist sozusagen das Hauptfenster. Wenn man weitere Fenster haben möchte kann man `Toplevel` dafür verwenden.
Hätte ich das vorher gewusst, hätte ich mir viele Stunden rumprobieren gespart. Aber jetzt weiß ich es.
Vielen Dank nochmal an alle, Thema ist gelöst.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Freitag 3. August 2012, 01:07
von moccajoghurt
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:
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()
Wie bekomme ich es hin, dass die Progressbar auch nicht mehr sichtbar ist?
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Freitag 3. August 2012, 07:33
von BlackJack
@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:
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()
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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Samstag 4. August 2012, 01:24
von moccajoghurt
Ich habe die Klasse so umgeschrieben, dass nurnoch ein Toplevel erstellt wird, dass danach zerstört werden soll:
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######")
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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Samstag 4. August 2012, 08:33
von BlackJack
@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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Samstag 4. August 2012, 11:22
von wuf
Hi moccajoghurt
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()
Gruß wuf

Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Sonntag 5. August 2012, 19:29
von moccajoghurt
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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Sonntag 5. August 2012, 20:02
von BlackJack
@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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Sonntag 5. August 2012, 20:14
von moccajoghurt
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?
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Sonntag 5. August 2012, 20:17
von BlackJack
@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.
Re: Klassenattribut ist nach Erstellung nicht mehr ansprechb
Verfasst: Sonntag 5. August 2012, 20:57
von moccajoghurt
Es klappt!

Danke.