Hallo zusammen! Ich möchte in meinem QT Projekt ein QLabel verwenden. Dazu ist zu sagen, dass ich über ein Modul digitale Ein- und Ausgänge schalte, bzw. einlese. Wenn ich meinen pushButton drücke, läuft ein Stück Programm ab, in dem mehrmals die digitalen Eingänge eingelesen werden. Die Bitmaske der 8 digitalen Eingänge muss ich zwischendurch einlesen, da ich somit den Schaltungszustand eines Relais abfrage. Nun habe ich das QLabel soweit konfiguriert, jedoch aktualisiert er das Label nicht nach jedem Step (mehrere Steps im pushButton, wo jedes mal die Bitmaske abgefragt wird), sondern erst wenn das Programm des pushButtons einmal durchgelaufen ist. Das Programm aktualisiert nur am Ende das QLabel und zeigt auch nur nur den letzten abgefragten Wert an. Frage ist also, wie ich den Wert der in das QLabel geschrieben wird kontinuierlich aktualisiere? Im Voraus schonmal vielen dank!!
Du hast nur einen Thread und solange der mit Programmlogik beschäftigt ist, kann er nicht gleichzeitig das Label neu malen. Du musst entweder zwischendurch zur Event Loop zurückkehren und das zweite Einlesen der Eingänge später machen (z.B. mit einem Timer) oder einen zweiten Thread starten, der mit der Hardware redet.
Ich verstehe nicht ganz, wie dein Programm abläuft. Wozu musst du alle Zwischenwerte ansehen können? Das dürfte sich doch so schnell ändern, dass man die eh nicht erkennen kann. Oder hast du irgendwo eine Warteschleife oder sowas, das dein Programm verzögert? Dann auf eine Timer-Steuerung umstellen. Notfalls wie Sven schon geschrieben hat, in einen separaten Thread stecken. Der GUI-Thread darf nicht durch lang andauernde Dinge blockiert werden.
Auszug aus dem Sourcecode der mainwindow.cpp: Alle STEPs sind ähnlich aufgebaut wie STEP17: void MainWindow::STEP17() { mycard.get_RELAIS_NO(); showRelais(); Sleep(1700); //vorher 1800 elfkiloHz(); //return; } void MainWindow::on_WEITER_clicked() { STEP3(); STEP4(); STEP5(); STEP6(); STEP7(); STEP8(); STEP9(); STEP10(); STEP11(); STEP12(); STEP13(); STEP14(); STEP15(); STEP16(); STEP17(); STEP18(); STEP19(); return; } void MainWindow::showRelais() { ui->relaisLabel->setText(tr("Relaiszustand:%1") .arg(QString::number(digitIN))); } Der mycard.get_RELAIS_NO(); holt sich aus dem Sourcecode des Moduls die Bitmaske der digitalen Eingänge, hier: digitIN (mögliche Werte die vom Modul gegeben werden sind 0-255). Und in jedem Step hole ich mir den "aktuellen" Wert digitIN und möchte den in meinem QLabel relaisLabel anzeigen, um so ständig den Zustand des Relais anzeigen zu lassen.
Sehe grade, dass ich nen Tippfehler im Betreff habe, muss natürlich aktualisieren heißen ;-)
David S. schrieb: > Sleep(1700); Tödlich für ein GUI-Programm. Mache es raus und implementiere die ganze Geschichte mit einer Statemachine.
David S. schrieb: > Alle STEPs sind ähnlich aufgebaut wie STEP17: > > void MainWindow::STEP17() > { > mycard.get_RELAIS_NO(); > showRelais(); > Sleep(1700); //vorher 1800 Und da haben wir ja den Übeltäter. Genau dieses Sleep() muss weg! Es blockiert dir jedesmal die komplette GUI. Sowas darf nicht in einem Thread stehen, der eine Eventloop ausführt. Das ist ähnlich wie bei den ISRs auf einem µC. Nimm einen Timer (In diesem Fall die Klasse QTimer) und steuere dein Timing damit. > elfkiloHz(); > //return; > }
Mathias O. schrieb: > processEvents(); Kann manchmal sinnvoll sein. Hier ist aber die Vermeidung von blockierenden Wartefunktionen besser.
Rolf M. schrieb: > Mathias O. schrieb: >> processEvents(); > > Kann manchmal sinnvoll sein. Hier ist aber die Vermeidung von > blockierenden Wartefunktionen besser. Wenn processEvents() eintrittsinvariant ist (was es vermutlich ist) dann kann man mit dieser Methode oftmals einen ganzen Haufen Code und unübersichtliche Statemachines sparen, das erhöht meist die Leserlichkeit. Allerdings muss man genau wissen was man tut wenn man sich in der x-ten Ebene geschachtelter processEvents()-Auifrufe befindet und wie man da unter allen Umständen sauber wieder rauskommt ohne sich dabei aufzuhängen. Ich mach das gerne in Lazarus (LCL), dort heißt das Application.ProcessMessages() und hat mir schon so manchen Timer, so manche häßliche unhandliche Statemachine und auch schon so manchen Thread erspart. Wenn man weiß was das für Implikationen hat ist es im Sinne der Lesbarkeit oftmals die zu empfehlende Vorgehensweise.
:
Bearbeitet durch User
Bernd K. schrieb: > Rolf M. schrieb: >> Mathias O. schrieb: >>> processEvents(); >> >> Kann manchmal sinnvoll sein. Hier ist aber die Vermeidung von >> blockierenden Wartefunktionen besser. > > Wenn processEvents() eintrittsinvariant ist (was es vermutlich ist) dann > kann man mit dieser Methode oftmals einen ganzen Haufen Code und > unübersichtliche Statemachines sparen, das erhöht meist die > Leserlichkeit. Hier geht es um ein Programm, dass im obigen Beispiel X mal hintereinander komplett schlafen gelegt wird, in der beispielhaft gezeigen Funktion für 1,7 Sekunden. Was ist dein Vorschlag? Alle 1,7 Sekunden mal processEvents() aufrufen? Oder aus dem einen Aufruf eine Schleife machen und 100 kurze Sleeps mit jeweils einem processEvents()? Das ist doch Murks. Viel Statemachine braucht man ja auch nicht, wenn einfach eine Reihe von Aktionen nacheinander ausgeführt werden soll - immer in gleicher Anzahl und Reihenfolge.
Rolf M. schrieb: > Hier geht es um ein Programm, dass im obigen Beispiel X mal > hintereinander komplett schlafen gelegt wird, in der beispielhaft > gezeigen Funktion für 1,7 Sekunden. Was ist dein Vorschlag? Alle 1,7 > Sekunden mal processEvents() aufrufen? Oder aus dem einen Aufruf eine > Schleife machen und 100 kurze Sleeps mit jeweils einem processEvents()? > Das ist doch Murks. QEventLoop benutzen. Ist aber trotzdem Murks.
Bernd K. schrieb: > Rolf M. schrieb: >> Das ist doch Murks. > > Definiere Murks. Schrieb ich doch schon: Sleep-Funktionen haben in einem Thread, der eine GUI-Eventloop enthält, nichts verloren. Das macht das Programm nur unnötig träge. processEvents() ist da nur eine Krücke, die das etwas abmildert. Das grundlegende Problem bleibt aber bestehen. Murks eben...
Es gibt für Qt "empfohlene" Emulationen von u/m/sleep. Entweder indirekt über QThread:
1 | class Sleeper : public QThread |
2 | { |
3 | public: |
4 | static void usleep(unsigned long usecs){QThread::usleep(usecs);} |
5 | static void msleep(unsigned long msecs){QThread::msleep(msecs);} |
6 | static void sleep(unsigned long secs){QThread::sleep(secs);} |
7 | }; |
8 | ... |
9 | Sleeper::sleep(5); |
10 | ... |
Oder von Hand mit Mutex:
1 | QWaitCondition sleep; |
2 | QMutex mtx; |
3 | mtx.lock(); |
4 | sleep.wait(&mtx,milisecs); |
Nur vorsicht: Unter Windows nur(!) mit Qt4.8.6 scheint trotzdem die Eventloop zumindest teilsweise nicht ausgeführt zu werden (mit beiden Methoden). Da hängen Programme, die DDE-Anfragen an alle anderen broadcasten genau für die Dauer des sleeps.
Murks hoch 2 ist es :-) Wie ich solche "Probleme" löse: 1. Die STEP1-19 ( auch Murks ) Funktionen müssen vom separetem Thread aufgerufen werden. Also: Meinen Thread von QThread ableiten und die STEP aufrufe in seine run() Methode Packen. Dort kann man auch problemloss sleep() benutyen, die GUI wird nicht geblockt... 2. IN dem Thread Objekt Metoden und Variablen deklarieren und definieren, die den Zustand von dem, was der Thread macht abfragen. MUtex ist nicht notwending, da wir nur lesen. Also diese Mothoden sind const Methoden... 3. Im GUI THread einen QTimer benutzen, durch den der Zustand des Threads regelmässig abgefragt wird, ZB. alle 100ms.... 4. Den Thread starten und Tee Trinken... ;-)
Georg A. schrieb: > Es gibt für Qt "empfohlene" Emulationen von u/m/sleep. Entweder indirekt > über QThread: Diese Antwort ist m.E. komplett wirr. Zum einen macht die Helper-Klasse keinerlei Sinn, du kannst auch direkt QThread::sleep() schreiben statt Sleeper::sleep() (???). Zum anderen ist ein sleep eben ein sleep, das macht i.d.R. einen Syscall der dem Betriebssystem sagt, dass jetzt ein anderer Thread geschedult werden soll und dieser hier nach n µs wieder aufgeweckt. Events werden während einem Sleep nie prozessiert und das hat auch mit der Qt-Version nichts zu tun.
Sven B. schrieb: > Diese Antwort ist m.E. komplett wirr. Zum einen macht die Helper-Klasse > keinerlei Sinn, du kannst auch direkt QThread::sleep() schreiben statt > Sleeper::sleep() (???). Das geht wohl erst in neueren Qt-Versionen, da früher aus unverständlichen Gründen diese Funktionen protected waren und somit nur direkt aus abgeleiteten Klassen heraus und nicht von überalls aus aufrufbar waren. > Events werden während einem Sleep nie prozessiert und das > hat auch mit der Qt-Version nichts zu tun. Der Grund für die Existenz dieser Funktionen dürfte auch nicht sein, dass da auf irgendeine Weise Events bearbeitet würden, sondern einfach damit man auf betriebssystemspezifische sleep-Funktionen verzichten kann.
Rolf M. schrieb: > Sven B. schrieb: >> Diese Antwort ist m.E. komplett wirr. Zum einen macht die Helper-Klasse >> keinerlei Sinn, du kannst auch direkt QThread::sleep() schreiben statt >> Sleeper::sleep() (???). > > Das geht wohl erst in neueren Qt-Versionen, da früher aus > unverständlichen Gründen diese Funktionen protected waren und somit nur > direkt aus abgeleiteten Klassen heraus und nicht von überalls aus > aufrufbar waren. Ok, das war mir nicht bewusst.
Sven B. schrieb: > Diese Antwort ist m.E. komplett wirr. Tja, jedem seine Erfahrungen. > Zum einen macht die Helper-Klasse > keinerlei Sinn, du kannst auch direkt QThread::sleep() schreiben statt > Sleeper::sleep() (???). Die Antwort hast du ja schon bekommen... Und es ist nicht so super-hipp, das neueste Qt zu benutzen, wenn man "alte" Qt4-Anwendungen hat und der Kunde keine Lust hat, die Zeit für die Portierung zu bezahlen, auch wenn das an sich nicht so schlimm ist. Aber man muss das Zeug ja auch testen... > Zum anderen ist ein sleep eben ein sleep, das > macht i.d.R. einen Syscall der dem Betriebssystem sagt, dass jetzt ein > anderer Thread geschedult werden soll und dieser hier nach n µs wieder > aufgeweckt. Events werden während einem Sleep nie prozessiert und das > hat auch mit der Qt-Version nichts zu tun. Es gibt durchaus sinnvolle Beispiele, wo ein (non-GUI)Thread in seinem Ablauf einfach mal eine kurze(!) Zeit warten soll und das mit einer Art von sleep am schnellsten zu machen ist, statt den Ablauf mit Timer-Events komplett zu zerstückeln. Und das geht auch super ohne Nebenwirkungen. Ausser eben bei genau 4.8.6 (nicht bei 4.8.5 oder 5*) mit dem Windows-Kram. Fällt sonst überhaupt nicht auf, ausser jemand macht noch DDE-Broadcasts. In meinem Fall war das eine andere Nicht-Standard-Anwendung, die jedesmal beim Öffnen des Fileselektors kurz blockiert hat.
Georg A. schrieb: > Die Antwort hast du ja schon bekommen... Und es ist nicht so super-hipp, > das neueste Qt zu benutzen, wenn man "alte" Qt4-Anwendungen hat und der > Kunde keine Lust hat, die Zeit für die Portierung zu bezahlen, auch wenn > das an sich nicht so schlimm ist. Aber man muss das Zeug ja auch > testen... Naja, Dezember 2012 ist jetzt nicht gerade gestern. Aber ja. > Es gibt durchaus sinnvolle Beispiele, wo ein (non-GUI)Thread in seinem > Ablauf einfach mal eine kurze(!) Zeit warten soll und das mit einer Art > von sleep am schnellsten zu machen ist, statt den Ablauf mit > Timer-Events komplett zu zerstückeln. Und das geht auch super ohne > Nebenwirkungen. Außer dass eben der Thread seine Event-Loop nicht durchläuft. Und genau darum ging es ja in diesem Thema hier ...
Sven B. schrieb: tt zu zerstückeln. Und das geht auch super ohne >> Nebenwirkungen. > Außer dass eben der Thread seine Event-Loop nicht durchläuft. Und genau > darum ging es ja in diesem Thema hier ... Ein nicht GUI Thread braucht normalerweise gar keinen Event Loop.... Enzige frage ist ob die Funktionen die in dem anderen Thrad laufen blocken oder nicht. Falls nicht ist sleep notwendig, sonst sind wir bei 100% COU Last....
Heir mein Ansatz nochmal zum Mitschreiben: #include <QWidget> #include <QTimer> #include <QLabel> #include <QThread> class MyThread: public QThread { Q_OBJECT public: MyThread(QObject *parent=0): QThread(parent) : someStatus(0) { } int getStatus() const { return someStatus; } protected: void run() { while(1) { someStatus = CallStepOrWhatever(); //Sleep if CallStepOrWhatever() does not block or whatever msleep(1000); } } private: int someStatus; } class MyWidget: public QWidget { Q_OBJECT public: MyWidget(QWidget *parent=0): QWidget(parent) { mylabel=new QLabel(this); timer=new QTimer(); connect(timer, SIGNAL(timeout()), this, SLOT(guiRefreshTimerSlot())); timer->start(100); theThread=new QThread(this); thread->start(); } private slots: void guiRefreshTimerSlot() { mylabel->setText( QString::number(theThread->getStatus())); } private: QThread *theThread; QTimer *timer; QLabel *mylabel; };
BobbyX schrieb: > Sven B. schrieb: > tt zu zerstückeln. Und das geht auch super ohne >>> Nebenwirkungen. >> Außer dass eben der Thread seine Event-Loop nicht durchläuft. Und genau >> darum ging es ja in diesem Thema hier ... > > Ein nicht GUI Thread braucht normalerweise gar keinen Event Loop.... In Qt kommuniziert man normalerweise mit Signals & Slots mit Threads, und dann brauchen die eine Event Loop. Das macht auch Sinn.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.