Seite 1 von 2
QProgressBar und QThread
Verfasst: 25. Januar 2008 17:05
von D_ron
Hallo allerseits!
Ich habe eine ProgressBar die ich in der StatusBar meines Fensters unterbringe:
Code: Alles auswählen
mProgressBar = new ProgressBar();
mProgressThread = new ProgressThread();
this->statusBar()->addPermanentWidget(mProgressBar);
Die ProgressBar soll parallel zu den StatusEvents laufen.
Innerhalb meiner Execute()-Methode rufe ich dann zunächst:
QObject::connect(this->mProgressThread, SIGNAL(CurrentProgress(int)), mProgressBar, SLOT(UpdateCurrentProgress(int)), Qt::QueuedConnection);
this->mProgressThread->start(QThread::NormalPriority);
auf und starte den Thread welcher über die run()-Funktion ein Signal an die ProgressBar triggert um den entsprechenden Wert zu setzen:
Code: Alles auswählen
void ProgressThread::run()
{
int iCount = 10;
while(this->isRunning()){
if(iCount > 100){
emit CurrentProgress(100);
}//if
emit CurrentProgress(iCount);
iCount += 10;
}//while
}//run()
Die SIGNAL() / SLOT() Verbindungen funktionieren alle einwandfrei.
Das Problem ist das die ProgressBar nicht parallel zu den StatusMeldungen der Statusbar laufen.
Weiter habe ich festgestellt das sich der Thread nur über ein terminate() killen lässt. Das quit() / exit() tut nicht, die Anwendung friert hierbei ein.
In der *.pro Datei ist
CONFIG += thread gesetzt. Allerdings führt dies zu keiner Verbesserung.
Ziel ist schlichtweg das ordnungsgemäße Beenden des Threads sowie die das synchrone Laufen der ProgressBar zum StatusOutput.
Danke im Vorraus für die Hilfe!

Verfasst: 25. Januar 2008 17:43
von upsala
Definiere eine Variable innerhalb des Threads die du mit while(var) abfragst und setzte diese von außerhalb des Threads zum beenden des Threads auf false.
Verfasst: 25. Januar 2008 19:11
von D_ron
Verfasst: 25. Januar 2008 19:13
von D_ron
D_ron hat geschrieben:Hallo!
Ich habe versucht was du mir empfohlen hast allerdings hat das leider nicht geholfen.
Anbei der Code meiner run()-Funktion:
Code: Alles auswählen
void ProgressThread::run()
{
int iCount = 10;
while(false == running){
if(iCount > 100){
emit CurrentProgress(100);
QThread::quit();
}//if
/*this->wait(1000); --> run() wird verlassen... wait is von sleep ein override*/
emit CurrentProgress(iCount);
iCount += 10;
}//while
QThread::quit();
}//run()
Es gibt 2 Abbruchkriterien:
Beim Aufruf von quit() friert mir die Anwendung ein. Das terminate() geht wird aber laut Doku wie gesagt nicht empfohlen.
Einmal wenn 100% erreicht wurden und einmal wenn running == true.
Die ProgressBar läuft noch immer nicht parallel zur StatusBar...
Folgende Frage noch:
Vor dem emit CurrentProgress(iCount); möchte ich noch eine zeitliche Verzögerung einbauen. Mit QThread::sleep() lege ich den Thread nur schlafen aber die Methode run() wird dann auch verlassen, ist so also nicht praktikabel. Was kann man da tun?!
Verfasst: 25. Januar 2008 19:27
von upsala
Eigentlich schon mal die Doku zu QThread::quit() durchgelesen?
Verfasst: 25. Januar 2008 19:41
von D_ron
ok... exit() is korrekt.
die synchro stimmt aber immer nocht nicht. der status ändert sich aber nicht die ProgressBar obwohl ich den Thread parallel dazu laufen lassen. any ideas?
Verfasst: 26. Januar 2008 11:36
von solarix
der status ändert sich aber nicht die ProgressBar
was tust du in ProgressBar::UpdateCurrentProgress(int)? Wird diese Methode korrekt aufgerufen (qDebug())? Im Übrigen läuft der Thread maximal ein paar ms.. da siehst du nur das Endergebnis..
Mit QThread::sleep() lege ich den Thread nur schlafen aber die Methode run() wird dann auch verlassen, ist so also nicht praktikabel.
Der Thread belegt momentan 100% eines CPU-Cores... da ist sleep() (oder msleep()) ganz genau richtig... wenn das für dich "nicht praktikabel" ist, musst du uns erklären warum..
Verfasst: 26. Januar 2008 14:36
von D_ron
Hallo,
in dieser Funktion mache ich folgendes:
Code: Alles auswählen
void ProgressBar::UpdateCurrentProgress(int iCount){
this->setValue(iCount);
}//UpdateProgressBar()
Ich setze praktisch den Progress auf iCount, mehr nicht.
Wieso läuft der Thread nur einige ms? Hier is doch wo mein Fehler, kannst du mir bitte erklären was ich hier falsch mache?
Danke vielmals!
Verfasst: 26. Januar 2008 14:39
von D_ron
D_ron hat geschrieben:Hallo,
in dieser Funktion mache ich folgendes:
Code: Alles auswählen
void ProgressBar::UpdateCurrentProgress(int iCount){
this->setValue(iCount);
}//UpdateProgressBar()
Ich setze praktisch den Progress auf iCount, mehr nicht.
Diese Funktion wird auch angesprungen, der pointer auf die ProgressBar ist ebenfalls korrekt.
Wieso läuft der Thread nur einige ms? Hier is doch wo mein Fehler, kannst du mir bitte erklären was ich hier falsch mache?
Danke vielmals!
Ergänzende Anmerkung:
Ich habe beim Start des Threads einen Breackpoint gesetzt und beim stoppen auch.
Code: Alles auswählen
QObject::connect(this->mProgressThread, SIGNAL(CurrentProgress(int)), mProgressBar, SLOT(UpdateCurrentProgress(int)), Qt::QueuedConnection);
this->mProgressThread->start(QThread::NormalPriority);
Das interessante ist das run() erst nach stopThread() angesprungen wird.
Ich kann mir nicht erklären wieso das so ist.
Verfasst: 26. Januar 2008 15:56
von solarix
Wieso läuft der Thread nur einige ms?
reduzier den Loop mal auf das Wesentliche:
Code: Alles auswählen
int iCount = 10;
while(false == running){
if(iCount > 100)
QThread::quit();
iCount += 10;
}
Schätz mal, wie lange dein Rechner hat um 10 Additionen durchzuführen.. ganz egal ob er 33 oder 3000MHz hat, du wird das mit der Armbanduhr nicht messen können....
übrigens den quit() brauchst du nirgends, denn wenn du die Run-Methode verlässt, läuft der Thread auch nicht mehr..
Das interessante ist das run() erst nach stopThread() angesprungen wird.
Ein Thread zu erstellen ist für das Betriebsystem recht aufwendig.. das dauert! Wenn du dem System keine Zeit dafür gibst (start und stop kurz nacheinander), kann der Thread nicht mal anlaufen..
Aus diesem Grund gibt es das Signal QThread::started()... erst wenn du dieses erhälst, läuft die run-Methode.
was gibt's da noch.. ach ja (sollte zwar kein Einfluss auf die Funktion haben):
Code: Alles auswählen
void ProgressBar::UpdateCurrentProgress(int iCount){
this->setValue(iCount);
}
Dann kannst du ja auch gleich mit dem Slot QProgressBar::setValue() connecten.. deine "ProgressBar" scheint ja von "QProgressBar" zu erben..
Verfasst: 26. Januar 2008 16:14
von ObeliX
D_ron hat geschrieben:Hallo,
in dieser Funktion mache ich folgendes:
Code: Alles auswählen
void ProgressBar::UpdateCurrentProgress(int iCount){
this->setValue(iCount);
}//UpdateProgressBar()
Ich setze praktisch den Progress auf iCount, mehr nicht.
Wieso läuft der Thread nur einige ms? Hier is doch wo mein Fehler, kannst du mir bitte erklären was ich hier falsch mache?
Danke vielmals!
dein thread addiert jeweils 10 zu iCount und emittiert CurrentProgress(int) bis iCount größer 100 ist. was denkst du wie lange dein gigaherz-dual/quad-core-rechner braucht um im wesentlichen zehn integer-additionen durchzuführen ?
QThread::quit(); beendet die event-loop der thread instanz, nicht die thread-loop (run()-methode). um die thread-loop zu beenden, mußt du einfach nur die run()-methode verlassen.
MfG Obel
uups ... hat bei mir mit dem absenden meiner antwort etwas gedauert, hatte solarix post noch nicht gesehen.
Verfasst: 26. Januar 2008 16:20
von D_ron
Danke für deine Antwort! Zw. Start() und Stop() des Threads passiert eine Menge im Debugger sehe ich auch das der Thread läuft.
Ich starte den Thread mit
mProgressThread ist ein Objekt das von QThread abgeleitet ist.
Die run() methode habe ich nahezu so übernommen wir du mir zunächst mal empfolen hast, das emit() habe ich noch mit rein damit die ProgressBar sichaktualisiert.
Ich verwende Qt\4.3.3. Hier ist start() innerhalt der QThread Klasse als SLOT definiert. Sobald ich start aufrufe wird dann auch die run() getriggert. Soweit tut eigentlich alles, nur wie gesagt hast du ja geschrieben das der Thread nur einige ms läuft. das ist korrekt. Wie schaffe ich es jedoch das der Thread etwas langsamer läuft?
Ich habe die sleep() methode überschrieben:
Code: Alles auswählen
void wait(unsigned long msecs){
QThread::msleep(msecs);
}//wait()
wenn diese innerhalb von run() aufrufe:
Code: Alles auswählen
void ProgressThread::run()
{
int iCount = 10;
while(false == running){
this->wait(100);
emit CurrentProgress(iCount);
if(iCount > 100){
QThread::quit();
}
iCount += 10;
}//while
}//run()
hüpft er aber aus run() raus, der Thread läuft dann zwar langsamer aber noch immer nicht synchron... Irgendwie bin ich grad total auf Glatteis, für den "tritt in die richtige richtung" wär ich sogar schon dankbar

Verfasst: 26. Januar 2008 17:31
von ObeliX
D_ron hat geschrieben:hüpft er aber aus run() raus, der Thread läuft dann zwar langsamer aber noch immer nicht synchron... Irgendwie bin ich grad total auf Glatteis, für den "tritt in die richtige richtung" wär ich sogar schon dankbar
also ich wüßte nicht warum die sleep()-funktionen dazu führen sollten, daß run() verlassen wird. wie kommst du zu dieser aussage ?
zumal, wenn run() verlassen würde, dann dürfte garnichts mehr passieren. aber du schreibst doch, daß es dann langsamer läuft. *verwirrtsein*
und das es nicht synchron läuft dürfte auch logisch sein :
D_ron hat geschrieben:Code: Alles auswählen
QObject::connect(this->mProgressThread, SIGNAL(CurrentProgress(int)), mProgressBar, SLOT(UpdateCurrentProgress(int)), Qt::QueuedConnection);
da ist das schlüsselwort Qt::
QueuedConnection
gruß Obel
Verfasst: 26. Januar 2008 18:40
von D_ron
Hallo Obelix!
Das mit dem wait() war Schwachsinn meinerseits, sorry dafür.
Folgendes:
Qt::QueuedConnection:
When emitted, the signal is queued until the event loop is able to deliver it to the slot.
Mit
Qt::DirectConnection fliegt eine Assertion in der paintingendinge_rater.cpp, Zeile 4462:
ASSERT: !rp->clipRect().isEmpty().
Der EventLoop schickt das Signal wohl erst zu spät, nämlich vermutlich nachdem die StatusEvents in der StatusBar abgeschickt wurden. Zumindest nehme ich das visuell so wahr.
Die StatusEvents kommen, nachdem diese alle fertig sind fängt erst die ProgressBar an zu laufen.
Die Frage ist wie ich es hinbekomme das die Events nahezu gleichzeitig kommen. Hier hat man ja nur die Möglichkeit die Flags beim QObject::connect() anders zu wählen oder?
Wenn ich Qt::AutoConnection verwende ist das Verhalten ggü. Qt::QueuedConnection gleich. Aus meiner Sicht sollte es mit
Qt::DirectConnection möglich sein, da das Signal dann SOFORT anden Slot weitergegeben wird. Hier erhalte ich aber wie gesagt diese Assertion...

Verfasst: 26. Januar 2008 19:09
von ObeliX
ich denke, daß threads nur mit den queued connections erlaubt sind.
versuch doch anstelle des signal/slot-mechanismus deine aufgabe mit events zu lösen (QCoreApplication::postEvent(receiver,event)).
konkrete aussagen zu der asynchronität sind ohne code nicht möglich.
D_ron hat geschrieben:Die StatusEvents kommen, nachdem diese alle fertig sind fängt erst die ProgressBar an zu laufen.
was sind das für für status-meldungen, wer verschickt die, wann und wohin und wie hängt das alles mit dem thread und dem progressbar zusammen ...?
bye Obel