PyQT ProgressBar/ProgressDialog

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

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
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

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
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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.
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.
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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

Du kannst ja den Prozess nichtblockierend starten, etwa mithilfe des Moduls `subprocess`.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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

Ins [wiki=Neue Features#Subprocess]Wiki[/wiki] geschaut?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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.
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.
sigro
User
Beiträge: 8
Registriert: Montag 4. Februar 2008, 14:27

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.
Antworten