Seite 1 von 1

PyQT ProgressBar/ProgressDialog

Verfasst: Montag 4. Februar 2008, 14:43
von sigro
Hallo,
ich habe folgendes Problem:
ich möchte ein externes Programm ausführen und während dieses Programm läuft dem Benutzer durch einen Fortschrittsbalken ( nur "Lauflicht") zeigen das das Programm läuft.
Leider steht der Balken immer an einer Position.

Code: Alles auswählen

pd = QtGui.QProgressDialog("Programmiere...","Abbrechen", 0, 0, ui)
pd.show()

ausgabe = os.popen(cmd,"r")
for zeile in ausgabe:
    text = zeile.strip()
    status = 0
    if re.search("Error",text)>0:
         ui.textEdit.setTextColor(QtGui.QColor("red"))
    else:
         ui.textEdit.setTextColor(QtGui.QColor("black"))
    ui.textEdit.append(text)
pd.hide()
Herzlichen Dank

Re: PyQT ProgressBar/ProgressDialog

Verfasst: Montag 4. Februar 2008, 22:52
von Gnushi
Hi!
sigro hat geschrieben: Leider steht der Balken immer an einer Position.
Probiere mal (ungetestet):

Code: Alles auswählen

avalue = 1
pd = QtGui.QProgressDialog("Programmiere...","Abbrechen", 0, 100, ui)
pd.show()
# während Du was machst, also ne Schleife oder so
pd.setValue(avalue)
avalue += 1
GnuShi

Verfasst: Montag 11. Februar 2008, 08:50
von sigro
Hallo Gnushi,
danke, aber da ich nur einen Prozess habe der ausgeführt wird, habe ich min- und max- value auf 0 gesetzt. So sollte der Busy Balken auftauchen(Lauflicht like KITT nur in eine Richtung).
der Prozess ist ein Komandozeilen Befehl der relativ lange braucht und dessen Ausgabe ich weiter verarbeiten muß.
MfG Sigro

Verfasst: Dienstag 12. Februar 2008, 17:25
von Gnushi
Hi Sigro!
sigro hat geschrieben:So sollte der Busy Balken auftauchen(Lauflicht like KITT nur in eine Richtung).
Tut er doch auch:

Code: Alles auswählen

#!/usr/bin/python
import sys
from PyQt4 import QtGui, QtCore

class Dialog(QtGui.QProgressDialog):
    def __init__(self):
        QtGui.QProgressDialog.__init__(self, "Label", "Ende", 0, 0)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    d = Dialog()
    d.show()
    d.exec_()


GnuShi

Verfasst: Mittwoch 13. Februar 2008, 08:34
von sigro
leider läuft der Balken nicht während mein Prozess "ausgabe = os.popen(cmd)" läuft. Scheinbar lastet dieser Prozess die Python zugewiesenen Ressourcen voll aus.
Insgesamt werden nur wenige Prozent (laut Task Manager) verwendet.

Verfasst: Mittwoch 13. Februar 2008, 09:47
von BlackJack
Der Aufruf von `popen()` blockiert, d.h. der kehrt erst zurück, wenn das externe Programm abgelaufen ist. Damit dürfte auch die Qt-Eventloop nicht mehr laufen, weil die darauf wartet, dass Deine Funktion/Methode zurückkehrt.

Verfasst: Donnerstag 14. Februar 2008, 08:58
von sigro
Hallo BlackJack,
BlackJack hat geschrieben:Der Aufruf von `popen()` blockiert, d.h. der kehrt erst zurück, wenn das externe Programm abgelaufen ist. Damit dürfte auch die Qt-Eventloop nicht mehr laufen, weil die darauf wartet, dass Deine Funktion/Methode zurückkehrt.
Gibt es denn eine Möglichkeit meinen Kommandozeilenbefehl auszuführen ohne das er den Qt-Eventloop unterbricht?
Ich habe leider nicht viel Ahnung von Threading.
Sigro

Verfasst: Donnerstag 14. Februar 2008, 13:09
von Leonidas
Du kannst ja den Prozess nichtblockierend starten, etwa mithilfe des Moduls `subprocess`.

Verfasst: Donnerstag 14. Februar 2008, 15:36
von sigro
Hallo Leonidas,
Leonidas hat geschrieben:Du kannst ja den Prozess nichtblockierend starten, etwa mithilfe des Moduls `subprocess`.
kannst Du mir das bitte etwas genauer erklären.
Wie habe ich die Klasse subprocess.Popen() aufzurufen so daß nach Beendigung dieses Prozesses erst das Programm weiter läuft?

Code: Alles auswählen

pd = QtGui.QProgressDialog("Programmiere...","Abbrechen", 0, 0, ui)
pd.show()

#ausgabe = subprocess.Popen(cmd,"r")
#funktioniert so nicht

for zeile in ausgabe:
    text = zeile.strip()
    if re.search("Error",text)>0:
        ui.textEdit.setTextColor(QtGui.QColor("red"))
    else:
        ui.textEdit.setTextColor(QtGui.QColor("black"))
    ui.textEdit.append(text)
pd.hide()
Herzlichen Dank sagt Sigro

Verfasst: Donnerstag 14. Februar 2008, 16:52
von Leonidas
sigro hat geschrieben:kannst Du mir das bitte etwas genauer erklären.
Wie habe ich die Klasse subprocess.Popen() aufzurufen so daß nach Beendigung dieses Prozesses erst das Programm weiter läuft?
Was willst du denn? Nichtblockierend ist es per Default, wenn du es blockierend haben willst musst du auf der Instanz ``wait()`` aufrufen, welches so lange blockiert bis der aufgerufene Prozess zu Ende ist.

Verfasst: Donnerstag 14. Februar 2008, 17:16
von sigro
Ich muß gestehen, daß es mir am liebsten wäre, wenn Du mir genau aufschreibst wie die Syntax des Befehls lautet, so daß ich die Ausgaben des Kommandos weiterverarbeiten kann.

Verfasst: Donnerstag 14. Februar 2008, 17:32
von Leonidas
Ins [wiki=Neue Features#Subprocess]Wiki[/wiki] geschaut?

Verfasst: Donnerstag 14. Februar 2008, 17:45
von sigro
Streue bitte Asche auf mein Haupt, leider habe ich nicht in die Wiki geschaut.


Ich habe jetzt folgendes ausprobiert:

Code: Alles auswählen

pd = QtGui.QProgressDialog("Programmiere...","Abbrechen", 0, 0, ui)
pd.show()

process = subprocess.Popen(['Stk500.exe', '-cUSB'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.wait()
ausgabe = process.stdout.readlines()

for zeile in ausgabe:
    text = zeile.strip()
    if re.search("Error",text)>0:
        ui.textEdit.setTextColor(QtGui.QColor("red"))
    else:
        ui.textEdit.setTextColor(QtGui.QColor("black"))
    ui.textEdit.append(text)
pd.hide() 

leider hängt wieder der QtGui.QProgressDialog Balken.

Verfasst: Freitag 15. Februar 2008, 14:12
von lunar
sigro hat geschrieben:leider hängt wieder der QtGui.QProgressDialog Balken.
Das wundert dich?

Du rufst den Prozess ja wieder blockierend auf, in dem du .wait() verwendest. Dadurch ist die Ereignisschleife wiederum blockiert, und nichts funktioniert.

Um Threading wirst du nicht herum kommen, wenn du die Module der Standardbibliothek verwenden willst.

Am besten wäre es allerdings, auch für die Prozesskontrolle auf die Qt Bibliotheken zurückzugreifen. Verwende doch am besten die Klasse QtCore.QProcess. Sie unterstützt nämlich das Signal-Slot-Konzept und integriert die Prozesskontrolle somit in die Qt-Ereignisschleife. Der Ablauf sieht dabei in etwa so aus (angenommen, der Prozess wird mit einen Button-Klick gestartet):

Im Slot des clicked-Signals des Buttons erzeugst du das QProcess Objekt, verbindest das "finished"-Signal mit einem Slot, startest den Prozess und zeigst den QProcessDialog an.

Im Slot des "finished"-Signals kannst du dann den QProcessDialog wieder schließen, und die Ausgabe des Prozesses über die Methode QProcess.readAllStandardOutput() auslesen und weiterverarbeiten.

Schon hat sich das Problem erledigt ;)

Nur ein genereller Tipp: Die Ereignisschleife von Qt läuft immer nur ab, wenn der Hauptthread keine blockierenden Aufrufe enthält. Deswegen müsst du dich vom normalen sequentiellen Programmablauf verabschieden, und dich auf das Signal-Slot-Konzept einlassen, dass ereignisbasierte Programmierung ermöglicht und so die Ereignisschleife berücksichtigt. Genau aus diesem Grund solltest du bei der Qt4 Programmierung auch dann auf Qt-Klassen zurückgreifen, wenn die benötigte Funktionalität eigentlich in schon in der Standardbibliothek oder in anderen Modulen verfügbar ist.
Ich kann nur für Qt sprechen, aber das ist bei anderen Toolkits möglicherweise ähnlich.

Verfasst: Montag 18. Februar 2008, 10:28
von sigro
lunar hat geschrieben: Das wundert dich?
um ehrlich zu sein, nein.

Ich wußte, bis ich Deine Antwort gelesen habe nur nicht so recht was ich machen sollte.
So wie Du es beschrieben hast Klappt es wunderbar.

An dieser stelle möchte ich mich noch einmal bei allen bedanken, ganz besonders natürlich bei lunar, für die freundliche Mitarbeit bei der Lösung meines Problems.