frame contents update?

Fragen zu Tkinter.
Antworten
aga
User
Beiträge: 18
Registriert: Montag 12. März 2007, 15:36

Hallo miteinander!

Ich hoffe, irgendwer kann mir auch diesmal wieder helfen. Die Codeteile sollen einen busy indicator in einer GUI darstellen. Leider funkt's nicht so, wie ich mir das gedacht habe. Manchmal funktioniert's, dass busy dargestellt wird, aber ein Aurfuf von setIdle/steBusy bewirkt meistens auf der GUI rein gar nix - die Anzeige bleibt auf busy. Wunderbar funktioniert es nur, wenn im Zuge des weiteren Programmcodes ein Fenster geöffnet oder geschlossen wird - auch nur Zufall?

Warum??


Code: Alles auswählen

from Tkinter import *
import time

################################################################################

class StatusFrame(LabelFrame):

    def __init__(self, parent, **options):
        self.parent = parent
        LabelFrame.__init__(
                                      self,       
                                      master=self.parent, 
                                      bd=1, 
                                      #bg="yellow",
                                      relief="sunk", 
                                      fg="black", 
                                      labelanchor = NE, 
                                      height=20, 
                                      text = "state information",
                                      width=900)
        self.grid(row=0, column=0, sticky="N") 
        self.busyInd = BusyIndicator(self)     
       
    def setState(self, guiMode):
        pass
        
        
    def setBusy(self):
        self.busyInd.setBusy()
        LabelFrame.configure(self)
        
    def setIdle(self):
        self.busyInd.setIdle()
        LabelFrame.configure(self)
 

class BusyIndicator(Checkbutton):

    def __init__ (self, parent):
         self.parent = parent
         self.busyStr = StringVar()
         self.busyInd = Checkbutton     (
                                         master=self.parent, 
                                         variable=self.busyStr, 
                                         textvariable=self.busyStr, 
                                         state="disabled", 
                                         indicatoron=0, 
                                         bg="red", selectcolor="green", 
                                         offvalue="Busy", onvalue="Idle")
         self.busyInd.grid(row=0, column=0)
         self.busyInd.select()
         
    def setBusy(self):
         self.busyInd.deselect()
         self.busyInd.configure()

    def setIdle(self):
         self.busyInd.select()
         self.busyInd.configure()
danke im voraus
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Hi,
es wäre hilfreich, wenn du ein kleines Anwendungsbeispiel posten könntest, denn mit dem Script passiert ja noch nix. Und mit sowas:

Code: Alles auswählen

#...
t=Tk()
f=StatusFrame(t)
f.pack()
t.mainloop()
kommt da halt ein Fenster mit ner Anzeige. Ich hab nicht genau verstanden was du willst/was passieren soll/man machen können soll, und da hier sonst noch keiner was geschrieben hat, wird das auch anderen so gehen.
mfg, jj
aga
User
Beiträge: 18
Registriert: Montag 12. März 2007, 15:36

Hi!
sorry, hast natürlich recht.
Also - der Ablauf sollte so funktionieren: der User selektiert eine Funktion über einen Menüeintrag in der GUI. Bevor in den dafür zuständigen Code gesprungen wird, wird Statusframe-objekt.setBusy() aufgerufen. Das sollte bewirken, dass der BusyIndicator den Text Busy erhält und rot hinterlegt wird. Nachdem die Funktion beendet wird (kann u.U. mehrere Minuten dauern) wird der BusyIndicator durch StatusFrame-objekt.setIdle() wieder auf grün und den Text Idle umgeschalten.

Da gibt's jetzt (für mich unverständlich) mehrere Verhaltensweisen des Codes (ausgehend von Idle/grün):
- es ändert sich gar nix: setBusy wird aufgerufen, nichts ändert sich, der zuständige Code wird ausgeführt, setIdle() wird aufgerufen und nix ändert sich - nach Ende der Aktion ist der Indikator auf grün
- setBusy funktioniert: setBusy wird aufgerufen: der Indicator geht auf rot, der zuständige Code wird ausgeführt, setIdle() wird aufgerufen und nix ändert sich: nach Ende der Aktion ist der Indikator auf rot.
- beides funktioniert so wie's soll: setBusy wird aufgerufen - der Indicator geht auf rot, der zuständige Code wird ausgeführt, setIdle() wird aufgerufen und der Indikator geht auf grün. Das funktioniert allerdings nur, wenn die zuständige Aktion bedingt, dass ein Dialog geöffnet wird.


Der Code ist inzwischen schon ziemlich umfangreich, daher hab ich ihn nicht gepostet.
Hier ein paar Ausschnitte, die zeigen sollten, wie's gedacht ist: wenn runTestsuite aufgerufen wird, soll der Indikator auf busy gehen, nach Ende des testruns auf Idle und das wars.

Code: Alles auswählen

class GUI():

    def __init__(self):
        ::::
        self.createStatusFrame()
        ::::
        self.showFrames()
        ::::
        
    def createStatusFrame(self):
        self.statusFrame = StatusFrame(master=self.root, 
                                      parent = self.root,
                                      bd=1, 
                                      #bg="yellow",
                                      relief="raised", 
                                      fg="black", 
                                      labelanchor = NE, 
                                      height=20, 
                                      width=800)                                      
        log.info ("statusframe created") 
  
    def showFrames(self):
        ::::
        self.statusFrame.grid(row=0, columnspan=3)
        ::::
    
    def runTestsuite(self):
        log.debug ("TC.runTestsuite")
        self.setBusy()
        
        # der auszuführende Code
        ::::
        
        self.setBusy()
    
    def setBusy(self) :
        log.debug ("WC.setBusy")
        self.statusFrame.setBusy()
        self.statusFrame.configure()
                 
    def setIdle(self) :
        log.debug ("WC.setIdle")
        self.statusFrame.setIdle()
        self.statusFrame.configure()        
   

if __name__ == '__main__':
    
    f = GUI()
    f.root.mainloop()

Die configure calls haben übrigens nichts geholfen - eine Hoffnung weniger....

thx
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Hi aga!
Ich hab grad leider keine Pythoninstallation, darum kann ichs nicht testen.
Es ist aber so, das das Fenster im mainloop erst erneuert wird, wenn keine Rechnungen mehr laufen, und da dann das Feld wieder zurückgesetzt worden ist, ändert sich zwar was, aber du siehst es nicht.

-> Mit der update-Methode müsste es gehen, bzw. zumindest etwas zu sehen sein.

Schöner wäre es natürlich, wenn du das mit tix.Meter löst.

Gruß, jj
aga
User
Beiträge: 18
Registriert: Montag 12. März 2007, 15:36

Hi!

Danke für die schnelle Antwort; mir wäre eine BusyBar o.ä. auch lieber aber ich habe nur Tkinter zur Verfügung. Gibt's da sowas?



thx
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

aga hat geschrieben:Gibt's da sowas?
Ne gibts nicht. Kannst du Tix nicht installieren? Ansonsten könntest du tix.Meter halt nachbauen, indem du alle paar Rechenschritte den Statusbalken etwas weiter zeichnest. Du kannst es so einfach oder kompliziert machen wie du willst. Du kannst auch auf nem Canvas ein Gesicht zeichnen, oder ein Label mit Textvariable nehmen, wo du den Text Buchstabe für Buchstabe aufbaust..naja, vlt. gehts auch simpler..
Gruß, jj
Antworten