Sehr komplizierte ProgressBar

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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
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.
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

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
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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
Zuletzt geändert von gugugs am Dienstag 13. Januar 2009, 16:40, insgesamt 1-mal geändert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

gugugs hat geschrieben:Dieser Code sollte nur ein primitives Beispiel sein, und kein Anfangscode....
Aber auch ein "primitives Beispiel" muss nicht fehlerhaft sein!
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

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.
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Kann man eig. zwei Threads starten?
Oder gehts das nicht, das zwei Threads gleichzeitig laufen?
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

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
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

Hm oke Danke
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

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
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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"))
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

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
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

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.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
gugugs
User
Beiträge: 113
Registriert: Dienstag 30. Dezember 2008, 12:38

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
Antworten