Seite 1 von 2

Sehr komplizierte ProgressBar

Verfasst: Dienstag 13. Januar 2009, 15:58
von gugugs
Guten Tag, und zwar habe ich folgendes Problem, ich habe einen Prozess, den ich mit subprocess.Popen öffne, der schickt mir dann immer wieder etwas in meine Konsole. Diese Ausgabe in der Konsole speichere ich in eine Datei, in dieser Datei steht immer eine Zahl drinen, wie die lautet ist vorerst unwichtig, wie ich die bekomme auch, das ist auch kein Problem, das Problem ist jetzt das diese Zahl, mein Progressbar beeinflusst. Das heist, das ganze müsste ungefähr so funktionieren:

- subprocess wird in einem Thread gestartet...
- die Datei die durch den subprocess gestartet wurde, wird geöffnet, ausgelesen, und der Progressbar wird darauf eingestellt.

Wie ich einen Thread starte, einen subprocess starte, eine Datei durchsuche und mir die Zahl finde und den Progressbar auf die Zahl programmiere, kann ich alles, ist auch alles kein Problem.

Bis jetzt hört sich ja alles einfach an, so nun kommt aber mein Problem. Ich muss aus der Datei diese Zahl so lang heraus holen, bis die Zahl z.B.: 100 ist, dann soll sozusagen die "gigantische Schleife aufhören"

Das heist während der subprocess im neuen Thread läuft, und immer wieder eine neue Info in die datei "xy" schreibt, muss ich in meinem Hauptprogramm, die neue Zahl auslesen, und den Progressbar erweitern, und zwar solange und so oft, bis diese Zahl 100 lautet.

Wenn ich das nun mit einer while schleife mache, also:

Code: Alles auswählen

zahl=0
while meine_zahl!=100:
	f=open("datei", "r")
	line=f.readline
	zahl=line[3:7]
	progressbar.set_fraction (zahl)
	f.close()
so entsteht im Prinzip eine "gigantische und unendliche Schleife" die mein ganzes Programm aus der Bahn wirft, besonders da es ein GUI ist und der dann völlig abschmiert. Eig. eine total dumme Idee, und was auch gar nicht geht ist, einfach noch mal einen neuen Prozess zu starten.

So wie löse ich nun mein Problem und bekomme meine Progressbar????
Im Prinzip muss ein Teil sich um den subprocess kümmern (kein Problem mit Threads) und der andere um das "so und so viel mal" auslesen der Datei (großes Problem)

Wenn ich total auf dem Holzpfad bin, und jemand eine ganz andere (bessere) Idee hat, dann bin ich total glücklich für jede Hilfe. Muss das unbedingt hin bekommen egal wie.

Danke schon mal

P.s.: Wer Linux benutzt, kann dieses ganze Prinzip super mit dem Prozess ping benutzen, denn mit dieser Ausgabe:

64 bytes from ug-in-f104.google.com (66.249.93.104): icmp_seq=6 ttl=243 time=670 ms

kann man super das icmp_seq=6 benutzen, das sich nach jeder neuen Zeile um eins erweitert. mit dem Befehl ping www.google.de | tee meinedatei.txt bekommt man jede neue Zeilenausgabe in die Datei meinedatei.txt

Verfasst: Dienstag 13. Januar 2009, 16:26
von BlackJack
Der Umweg über eine Datei mutet etwas umständlich an…

Wie man Code "nebenher" laufen lässt, der die GUI beeinflussen soll, hängt ganz stark vom GUI-Toolkit ab.

Verfasst: Dienstag 13. Januar 2009, 16:28
von gugugs
Ich benutze GTK. Ich wollte es eig. auch erst nicht über eine Datei machen, aber ich wüsste nicht wie es anders gehen könnte.

Re: Sehr komplizierte ProgressBar

Verfasst: Dienstag 13. Januar 2009, 16:31
von helduel
Moin,
gugugs hat geschrieben:

Code: Alles auswählen

zahl=0
while meine_zahl!=100:
	f=open("datei", "r")
	line=f.readline
	zahl=line[3:7]
	progressbar.set_fraction (zahl)
	f.close()
Der Code funzt so nicht: meine_zahl ist nirgens definiert (du meinst wohl zahl), f.readline gibt dir die Referenz auf die Methode readline (du musst die Methode aufrufen), line[3:7] gibt dir einen String zurück (dein Vergleich erwartet aber eine Zahl -> deine Bedingung wird nie eintreffen). Außerdem solltest du noch ein time.sleep einbauen, damit auch andere Prozesse zum Zuge kommen.

Deine Bedingung sollte auch auf >= 100 lauten: Es kann gut sein, dass dein Subprozess schon die 100 überschritten hat (sofern das möglich ist) und du das dann gar nicht mitbekommst.

Warum wird die Zahl eigentlich in einer Datei abgelegt? Ist das so zwingend vorgegeben, oder kann dein Subprozess auch auf stdout schreiben? Vielleicht solltest du dir mal das Modul subprocess anschauen?

Gruß,
Manuel

Verfasst: Dienstag 13. Januar 2009, 16:35
von gugugs
Dieser Code sollte nur ein primitives Beispiel sein, und kein Anfangscode.... Das weiß ich auch alles, es geht um das parallele laufen lassen, bei den prozessen....

Probiere das mit dem Beispiel Code einmal aus, du wirst sofort merken, dass das Programm sofort einfriert, weil die Schleife, als Endlos gillt, und viel zu lang dauert, denn diese while Schleife, würde ja in meinem Fall mindestens 20 Minuten aktiv sein müssen, das die Zahl um von 0 auf 100 zu kommen knapp 20 minuten brauch, und wenn die while Schleife, in diesen 20 Minuten ungefähr die Datei 100 mal in der Sekunde öffnet und wieder schliest, und diese kein Ende findet, kann das nichts werden. Und es ist logisch dass dann mein GUI einfriert, da der ja durch die while Schleife 20 minuten lang gestoppt wird... Ich denke, wenn man mein Vorhaben genau durchliest, wird man wissen, das ich das mit einer while Schleife nicht machen kann.

edit: selbst wenn ich es nicht von einer Datei mache. Brauch ich trotzdem diese Prinzip:

Lese so lange eine Zahl aus (egal ob aus Datei oder nicht) und steigere den Progressbar um diese Zahl bis diese Zahl (von mir aus) 100 ist. Und irgendwie muss ich das schaffen, ohne diese while Schleife

Verfasst: Dienstag 13. Januar 2009, 16:40
von numerix
gugugs hat geschrieben:Dieser Code sollte nur ein primitives Beispiel sein, und kein Anfangscode....
Aber auch ein "primitives Beispiel" muss nicht fehlerhaft sein!

Verfasst: Dienstag 13. Januar 2009, 16:43
von gugugs
numerix hat geschrieben:
gugugs hat geschrieben:Dieser Code sollte nur ein primitives Beispiel sein, und kein Anfangscode....
Aber auch ein "primitives Beispiel" muss nicht fehlerhaft sein!
Ja entschuldigung^^

Code: Alles auswählen

zahl=0
while zahl<100:
    f=open("datei", "r")
    line=f.readline()
    zahl=line[3:7]
    zahl=int(zahl)
    progressbar.set_fraction (zahl)
    f.close()

Weis mir nun vllt trotzdem noch jemand bitte zu helfen? Immer noch egal wie

Verfasst: Dienstag 13. Januar 2009, 16:51
von helduel
time.sleep(x) gibt anderen Threads wieder etwas Luft zum atmen. Allerdings meine ich gelesen zu haben, dass Threads mit GTK so einige Haken haben soll.

Verfasst: Dienstag 13. Januar 2009, 16:53
von gugugs
Kann man eig. zwei Threads starten?
Oder gehts das nicht, das zwei Threads gleichzeitig laufen?

Verfasst: Dienstag 13. Januar 2009, 17:05
von helduel
gugugs hat geschrieben:Kann man eig. zwei Threads starten?
Oder gehts das nicht, das zwei Threads gleichzeitig laufen?
Das ist der Sinn von Threads. Du kannst viele Threads nebeneinander laufen lassen.

Bloß mit GTK ist das so eine Sache. Da kann es zu Problemen kommen, wenn Threads außerhalb von GTK an der GUI rumfroschen.

Gruß,
Manuel

Verfasst: Dienstag 13. Januar 2009, 17:06
von gugugs
Hm oke Danke

Verfasst: Dienstag 13. Januar 2009, 17:11
von jonas
Nochmal zur Datei:

Du könntest doch in den Abständen in denen
du die Datei öffnest/einliest usw. auch einfach die
Rückgabe vom subprocess parsen, dann sparst
du dir den Umweg.

MfG Jonas :D

Verfasst: Dienstag 13. Januar 2009, 17:18
von gugugs
Also ich hätte nun das ganze erst mal so versucht:

Code: Alles auswählen

import pygtk
pygtk.require("2.0")
import gtk
import gtk.glade
import gobject
import os.path
import sys
import threading
import subprocess
import time


class tr(threading.Thread):
	def __init__(self):
		threading.Thread.__init__(self)
	def run(self):
		subprocess.Popen("ping google.de | tee kein", shell=True)

class tr2(threading.Thread):
	def __init__(self):
		threading.Thread.__init__(self)
	def run(self):
		self.xml = gtk.glade.XML(os.path.join(os.path.dirname(sys.argv[0]), "nun.glade"))
		self.entry=self.xml.get_widget("entry1")
		zahl=0
		while zahl<5:
			f=open("kein", "r")
			for zeile in f:
				line=zeile[:-1]
			line=str(line[62:63])
			zahl=int(line)
			self.entry.set_text(line)
			f.close()
			time.sleep(2)


class programm:

	def on_button1_clicked(self, widget):
		thread=tr()
		thread.start()
		time.sleep(3)
		thread2=tr2()
		thread2.start()


	def __init__(self):
		self.xml = gtk.glade.XML(os.path.join(os.path.dirname(sys.argv[0]), "nun.glade"))
		self.window = self.xml.get_widget("window1")

		dic = {}
		for key in dir(self.__class__):
			dic[key] = getattr(self,key)
		self.xml.signal_autoconnect(dic)


		self.window.show()


def main():
	gtk.main()


if __name__=="__main__":
	programm()
	main()

Das funktioniert aber so nicht, warum wüsste ich jetzt nicht genau, vllt liegt es ja an dem GUI, das er das entry nicht ändern kann?

Bitte um weitere Hilfe....

P.s.: Das ist mit glade gemacht, also nicht über das

Code: Alles auswählen

self.xml = gtk.glade.XML(os.path.join(os.path.dirname(sys.argv[0]), "nun.glade"))

Verfasst: Dienstag 13. Januar 2009, 17:40
von numerix
Von gtk verstehe ich zwar nichts, aber in Tkinter gibt es für so etwas die after()-Methode und ich kann mir einfach nicht vorstellen, dass es Entsprechendes nicht auch für gtk gibt.

Ansonsten: Nimm doch einfach Tkinter ... :wink:

Verfasst: Dienstag 13. Januar 2009, 18:19
von Hyperion
Wir hatten das ja eigentlich schon einmal in einem anderen Thread von Dir thematisiert! (Nur mal so am Rande ;-) )
http://www.python-forum.de/topic-17347.html?highlight=

Aber ok, nun geht es ja um die GUI. Zum einen gibt es da das GTK-Forum hier im Board, wo der Thread ggf. besser aufgehoben wäre.

@numerix: Naja, evtl. hat er ja Vorgaben!

Ich kenne mich mit GTK nicht die Spur aus, aber es muss doch da auch Möglichkeiten geben, mit Threads zu arbeiten! (evtl. GTK.eigene Implementierungen?) Ich kann mir nicht vorstellen, dass das nicht möglich sein sollte. Kennt sich Leonidas nicht gut mit GTK aus?

Ansonsten meine ich, dass es bei wxWidgets in deren wiki extra dieses Thema behandelt wird! Evtl. wäre das also auch mal einen Blick wert, wenn man schon Alternativen dazu sucht.

Irgend wie werde ich das Gefühl nicht los, dass man zu dieser Thematik mal einen wiki-Artikel schreiben sollt :-)

Edit:
http://www.pardon-sleeuwaegen.be/antoon ... page0.html
Sieht ganz nett aus!

http://aruiz.typepad.com/siliconisland/ ... _pygt.html
Und das wohl auch.

Habe jetzt nur mal kurz gegoogelt und kann die Qualität nicht bewerten - das Konzept scheint aber identisch zu sein

Verfasst: Dienstag 13. Januar 2009, 18:33
von Trundle
Das ist kein GTK+-Problem, das gilt für alle GUI-Toolkits. Wie sollen auch zwei Threads gleichzeitig zeichnen? Und natürlich kann man auch mit PyGTK Threads verwenden. Man darf aber entweder nur auf mit einem Thread, nämlich dem Thread, in dem die GTK-Hauptschleife ausgeführt wird, zugreifen, was mit `gobject.idle_add()` recht gut geht (was in Tkinter das `after()` wäre) oder man muss mit Locks arbeiten (`gtk.gdk.threads_enter()` und `gtk.gdk.threads_leave()`). Auf jeden Fall muss beim Initialisieren `gobject.threads_init()` aufgerufen werden, greift man mit mehr als einem Thread auf die GUI zu noch `gtk.gdk.threads_init()`.

Aber die Forensuche müsste dazu eigentlich etwas finden.

Verfasst: Dienstag 13. Januar 2009, 18:34
von Leonidas
helduel hat geschrieben:time.sleep(x) gibt anderen Threads wieder etwas Luft zum atmen. Allerdings meine ich gelesen zu haben, dass Threads mit GTK so einige Haken haben soll.
Das ist mit jedem Toolkit so. Tkinter und wxPython sowie PyQt sind nicht besser und die Pseudo-Timer die GTK-bietet wenn man nicht über Threads gehen will können oft ausreichend sein um sich die komplette Thread-Lösung zu sparen.

Verfasst: Dienstag 13. Januar 2009, 19:02
von gugugs
Uff, das kling ja schon wirklich ziemlich kompliziert Trundle, ich werde mir da denke ich mal einiges was du geschrieben hast durchlesen, hoffe mal ich bekomme es hin, wenn jemandem sowieso langweilig ist, wäre ich echt Dankbar, wenn mir bei den Themen:

gobject.idle_add()
gtk.gdk.threads_enter()
gtk.gdk.threads_leave()
gobject.threads_init()
gtk.gdk.threads_init()

jemand ein bisschen helfen könnte, beziehungsweise ein paar "qualitativ gute" Tutorials oder How to's geben könnte. Kenne mich in dem Thema nämlich noch nicht so wirklich gut aus :roll:

Aber schon mal vielen Dank
Dieser Beitrag hat mir nun etwas mehr geholfen :wink:

Verfasst: Dienstag 13. Januar 2009, 19:19
von Leonidas
Ich persönlich würde ja einfach den Prozess mit ``subprocess.Popen`` starten und einen ``gobject.timeout_add`` machen, das ich an eine Prozedur binde, die die Ausgaben des Subprocesses aus der Pipe liest und die Progressbar aktualisiert. Das ist doch nicht so schwer.

Verfasst: Dienstag 13. Januar 2009, 19:26
von gugugs
Wie lese ich mit subprocess aus der Pipe?
Hab leider momentan nur so die Grundlagen von Python und GTK. Wenn du gerade Zeit hast, wäre es echt super, wenn du mal ein Beispiel mit dem Ping google machen könntest.
Aber schon mal Danke für den Tipp

Oder vllt ein kurtzes "Statement" zu gobject.timeout_add^^
Ich finde nämlich auch in google nicht sooo brauchbare Ergebnisse, die mir erklären könnten, wie ich gobject.timeout_add am besten bei mir verwende