Seite 1 von 2

Label im applet aktualisieren?

Verfasst: Montag 13. Juni 2011, 21:50
von Arp
Hallo,

Da ich mich grad langweile, wollte ich mal aus spaß ein applet fürs gnome unter python schreiben. Soweit hab ichs auch fertig. Allerdings krieg ich es nicht hin das das Applet sich aktualisiert. Ich möchte das das Label jede Sekunde geändert wird. Zuletzt hab ich es mit threads versucht.
Hier mal der Factory code.
Als beispiel soll hier einfach nur eine zahl im label stehen. Fängt bei 0 an und wird pro sekunde um 1 erhöht.

Code: Alles auswählen

def factory(applet, iid):
	class count(threading.Thread):
		def __init__(self):
			threading.Thread.__init__(self)
		def run(self):
			zahl = 0
			while 1:		
				label = gtk.Label(str(zahl))				
				applet.add(label)
				applet.show_all()
				time.sleep(1)
				zahl+=1
	thread=count()
	thread.start()
	return True
aber das führt nur dazu das das Label 0 zeigt und nicht höher geht. Wie krieg ich nun das Label dazu sich zu aktualisieren?
thx.

Re: Label im applet aktualisieren?

Verfasst: Montag 13. Juni 2011, 22:01
von deets
GUI & threads == schlechte idee.

Fuer sowas nimmt man einen Timer. Du kannst auch Threads nehmen, aber dann musst du einen vom Toolkit abhaengigen Weg finden, wie du GUI-updates aus anderen Threads antriggerst. Das kannst du in der Doku nachlesen (ich benutze kein GTK)

Re: Label im applet aktualisieren?

Verfasst: Montag 13. Juni 2011, 22:04
von Arp
Threaads waren von mir jetzt nur so angedacht. Ich hab eh nicht sonderlich viel Erfahrung mit Threads.
Zuerst wollte ich ja in der Factory einfach die while 1: schleife laufen lassen aber dann hängt das halbe system und es passiert gar nichts :)

ich glaube, das warten, bzw. wie man das anstellt ist sogar noch das sekundäre problem hierbei. Primär seh ich noch keine möglichkeit wie das einmal gezeichnete Label überschrieben werden soll.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 07:28
von Yaso
Schau mal hier nach:
http://unpythonic.blogspot.com/2007/08/ ... pygtk.html
Das hat mir mit Threads geholfen und dein Vorhaben sollte funktionieren.
Wobei GUI und Threads wirklich am besten zu vermeiden sind. Aber manchmal kommt man nicht drum herum:

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 08:13
von BlackJack
In diesem Falle sollte man aber darum herum kommen mit `gobject.timeout_add()`.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 08:15
von lunar
@Arp: Du brauchst keine Threads. Es reicht ein Timer, der einmal in der Sekunde eine Funktion zur Aktualisierung des Labels ausführt.

Und wieso erzeugst Du jedes Mal ein neues Label, statt einfach nur mit ".set_label()" den Text des existierenden Labels anzupassen?!

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 16:26
von Arp
Hi,

Das mit dem set_label klappt auch nicht.

Ich hab den code jetzt stark vereinfacht, nur um es hinzukriegen das das existierende Label von 0 auf 1 springt.

Code: Alles auswählen

def factory(applet, iid):
	label = gtk.Label(0)			
	applet.add(label)
	time.sleep(1)	
	label = gtk.Label(1)			
	applet.set_label(label)
	applet.show_all()
	return True
Seht ihr da einen offensichtlichen Fehler?

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 17:59
von deets
Ja. Das du nicht tust, was man dir sagt: benutze Timer!

Eine GUI wird in nur *EINEM* thread aufgebaut & dargestellt. Wenn du also ein Label erzeugst, und dann einfach ne Sekunde wartest - dann passiert halt ne Sekunde nix. Und dann setzt du das um auf den neuen Wert, und *danach*, wenn der GUI-thread wieder die Kontrolle hat, weil die factory-fukntion beendet wurde, *dann* werden die Sachen dargestellt.

Darum "frieren" Programme ein, wenn man laengere Berechnungen macht, ohne zwischendurch die Kontrolle wieder an den GUI-thread zurueckzugeben - wenigstens fuer kurze Zeit, um eben updates der GUI darzustellen.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 18:02
von Arp
Achso. Dann muss ich den Timer, bzw. das warten außerhalb der def factory machen und immer wieder def factory aufrufen? Wie gesagt, das primäre Problem ist, das das Label überhaupt erstmal sich aktualisiert. Wie man nun darauf wartet sollte ja nebensächlich sein.
deets hat geschrieben:... *dann* werden die Sachen dargestellt.
Das ist übrigens in diesem Fall nicht richtig. Denn das würde bedeuten das im obigen Beispiel erstmal nichts passieren würde, und dann im Label die 1 steht. Aber es steht immer die 0 da.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 18:10
von deets
Jein. Du setzt den Timer, und der bekommt nen Callback. Darin updatest du das Label. Aber die Factory wird vermute ich mal ja nur *einmal* aufgerufen.

In pseudo-code (weil, wie gesagt, kein GTK-Kenner) etwa so:

Code: Alles auswählen


counter = 0
label = None

def timer_callback(timer):
      global counter, label
      counter += 1
      label.set_text(str(counter))

def factory(...):
      ...
      label = Label(...)
      add_timer(timer_callback, 1.0)
      ...

add_timer musst du natuerlich ersetzen durch das, was du da wirklich in GTK benoetigst, das wurde ja glaube ich schon gepostet.

Und der globale Zustand ist jetzt auch nicht sooo dolle, aber erstmal fuer den Anfang. Normalerweise wuerde man da wohl eher ein komplettes Objekt erzeugen in der Factory, welches dann eine Methode hat, die als callback dient. Aber das kann dann ja noch kommen.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 18:32
von Arp
hmmm....

Code: Alles auswählen

zahl = 0
label = None

def timer_callback(timer):
	global zahl,label
	zahl+=1

def factory(applet, iid):
	Label = gtk.Label(label)			
	applet.add(Label)
	applet.show_all()
	gobject.timeout_add(1000,timer_callback)	
	return True
führt jetzt dazu das kurz was aufblinkt und gar nichts angezeigt wird.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 19:17
von deets
Das sieht alles etwas wurstig aus.

Dein timer-callback macht ja nix. Er zaehlt hoch, na fein. Aber er setzt den Text nicht.

Und das globale label muss ein gtk.Label-objekt sein, nicht ein Text oder sowas. Das weisst du dem ja aber gar nicht zu. Ich hatte in der factory da aber auch das global vergessen.

Code: Alles auswählen


def factory(..):

     global label
     label = Label(str(counter))


Und was passiert, wenn

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 19:29
von Arp
Sorry, das eine label hatte ich beim schreiben vergessen. Das macht aber auch nichts.

Code: Alles auswählen

zahl = 0
label = gtk.Label(str(zahl))

def timer_callback(timer):
	global zahl,label
	zahl+=1
	label.set_text(str(zahl))

def factory(applet, iid):
	global label		
	applet.add(label)
	applet.show_all()
	gobject.timeout_add(1000,timer_callback)	
	return True
zeigt mir nur die 0 im label an und es tut sich nichts. An der 1000 liegts nicht, da, soweit ich weiss man das da in ms statt s angeben muss.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 19:34
von deets
Aber das Label steht schon da? Gibt's noch ne Art redraw-Befehl?

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 19:35
von deets
Ah, und ausserdem ist der callback falsch. Ich hab' den nur prophylaktisch mit nem timer-argument versehen, weil ich das von anderen toolkits so kenne. Aber laut Doku bekommt der keinen. Nimm also mal das Argument timer weg.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 20:03
von Barabbas
Die Callback-Funktion muss "True" zurück geben, damit sie erneut ausgelöst wird. Außerdem kann man timeout_add() weitere Parameter übergeben, die dann auch an die Callback-Funktion durchgereicht werden. So spart man sich bspw. die globale label-Variable.

Besten Gruß,

brb

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 20:31
von Arp
Danke, aber das bringts auch nicht.... scheinbar bedarf es hier wirklich einer redraw befehl da ansonsten der einmal geschriebene Text auf teufel komm raus sich nicht ändert.

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 20:53
von BlackJack
@Arp: Also ich brauche hier keinen redraw-Befehl. Es wäre vielleicht hilfreich wenn Du mal ein funktionierendes Minimalbeispiel zeigen würdest.

Code: Alles auswählen

from itertools import count
import gobject
import gtk


def main():
    def destroy(window):
        window.hide()
        gtk.main_quit()
    
    window = gtk.Window()
    window.connect('destroy', destroy)
    
    label = gtk.Label()
    label.set_text('-')
    window.add(label)
    
    def set_label_counter(counter):
        label.set_text(str(counter.next()))
        return True
        
    gobject.timeout_add_seconds(1, set_label_counter, count())
    
    window.show_all()
    gtk.main()


if __name__ == '__main__':
    main()

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 21:47
von Arp
@Blackjack

Ich glaube es macht wohl einen unterschied ob man ein gnome applet schreibt oder ein "richtiges" programm.

Das ist das letzte was ich probiert habe, und es führt nur dazu das im gnome panel eine 0 steht, und sich dann nichts tut.

Code: Alles auswählen

zahl = 0
label = gtk.Label(str(zahl))

def timer_callback():
	global zahl,label
	zahl+=1
	label.set_text(str(zahl))
	return True

def factory(applet, iid):
	global label,zahl		
	label = gtk.Label(str(zahl))
	applet.add(label)
	applet.show_all()
	gobject.timeout_add(1,timer_callback,applet)	
	return True


if __name__ == '__main__':
	print "Starting factory"	
	gnomeapplet.bonobo_factory("OAFIID:Gnome_Panel_Example_Factory", gnomeapplet.Applet.__gtype__, "Simple gnome applet example", "1.0", factory)

Re: Label im applet aktualisieren?

Verfasst: Dienstag 14. Juni 2011, 22:00
von Barabbas
Deinen Code kann man ja mit 2, 3 Änderungen so abändern, dass er ein normales Fenster erzeugt. Und dann funktioniert er immer noch nicht, was deine These in Frage stellt.

Stellen wir uns also die Frage, warum dein Code nicht funktioniert. Und da fällt die Funktion "timer_callback" ins Auge. Du über gibst "gobject.timeout_add" den Zusatz-Parameter "applet". Die Callback-Funktion kennt aber keine Parameter und schmeißt daher den Fehler

Code: Alles auswählen

TypeError: timer_callback() takes no arguments (1 given)
^CTraceback (most recent call last):
  File "tst.py", line 23, in <module>
    gtk.main()
KeyboardInterrupt
Wenn du den Fehler behebst, geht auch dein Code.

Gruß,

brb