2013-09-30 11 views
5

Ich habe eine einfache GUI für meine Anwendung = Ich muss einige Eingabeparameter für meine mathematische Funktion, klicken Sie dann auf "Berechnen" -Taste, und die Funktion startet. Mathematische Funktionen sind in reinem C geschrieben, also gibt es keine Objekte, nur Funktionen.Qt GUI Mathe-Anwendung hängt GUI während der Berechnung

Es sieht wie folgt aus:

#include "mymath.h" 

class myMath : public QMainWindow 
{ 
    Q_OBJECT 

    // ... 
    void compute(); 
}; 

void myMath::compute() 
{ 
    //get parameters from gui 
    call_C_fun(); 
    // save results to GUI 
} 

Das Hauptproblem mit diesem Code ist, dass wenn ich auf ‚Compute‘ (es sooo viel Rechen tut, dauert es bis zu 5 Minuten oder so) es hängt heraus meine GUI, so kann ich nichts anderes tun (ich sehe nicht einmal meine GUI, das Fenster ist für die Zeit eingefroren, in der die Berechnung läuft. Nachdem die Funktion beendet ist, druckt sie die Ergebnisse auf QLabels, und die GUI ist wieder da "lebendig". Wie kann ich das lösen? Ich will nicht meine GUI "eingefroren" werden, wenn die Berechnung Zeit braucht. Irgendwelche Ideen? Ich dachte über QThread - aber ich bin irgendwie neu in Threads-Ding, also bitte, geben Einfach-leicht zu verstehende Antworten für Neuling :)

+1

einen Blick auf [diese] Nehmen Sie (https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly- use-qthreads-the-full-Erklärung /). Dann mach deine Berechnung im Thread-Objekt und sende ein Signal, sobald es fertig ist. Verbinden Sie das Signal mit einem Steckplatz in Ihrer Klasse und tun Sie alles, was Sie mit dem Ergebnis tun möchten. –

+0

Und es gibt zwei ':' Semikolons nach 'class myMath' weil ...? – Shoe

Antwort

2

In Ihrem Fall wäre Threading eine Lösung. Ihre Berechnung würde in einem separaten Thread laufen, der dann Ihrer GUI erlauben würde, zu reagieren, während sie berechnet, was Sie brauchen.

Das ist etwas ziemlich allgemein über GUI in meiner Erfahrung. GUI hat eigene Threads und Ihre Logik verwendet eigene Threads.

Sie dann sehr einfache Muster verwenden, kann dies zu handhaben, mit dem Signal von der GUI, die Arbeiter beginnt, und Signale, die von den Arbeitern, die Aktualisierungen in der GUI auslöst.

Sie müssen vorsichtig sein über die üblichen Thread-Sicherheitsbedenken. Ich schlage vor, dass Sie etwas über Threading im Allgemeinen lernen, um besser zu verstehen, was Sie tun. Es kann Ihnen auch helfen, seltsame Verhaltensweisen zu verstehen, die bei der Verwendung von Thread-Code auftreten können (was für Leute, die nicht daran gewöhnt sind, nicht immer trivial ist).

Ich empfehle auch, lesen Sie QThread documentation, die ziemlich gut erklärt, wie Thread-Code in Qt implementiert wird (bevorzugen Sie jedoch den separaten Arbeiter zu der Unterklasse von Qthread). Werfen Sie einen Blick auch auf QMutex und QMutexLocker, können Sie sie benötigen.

+0

Für jetzt, hat es 'QThread' und' QMutex' Unterklassenbildung - funktioniert brilliant, Prost! Morgen werde ich andere Lösungen aus diesem Thema ausprobieren. Und übrigens - warum Subclassing 'QThread' ist als schlechte Idee bekannt? – yak

+0

Re. Unterklasse 'QThread': lesen [diesen Blog-Beitrag] (http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/). – andref

+0

@yak Andref verlinkte einen relevanten Artikel. Es ist nicht immer schlecht, aber generell sollten Sie den Worker-Ansatz bevorzugen. Dann ist dieser Link auch relevant für [Warum es nicht immer schlecht ist, QThread abzuleiten] (http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html). Wirklich kurze Antwort: Wenn Sie keine Ereignisschleife, Unterklasse, benötigen, wenn Sie eine Ereignisschleife (Signale, Slots, usw.) benötigen, dann Unterklasse nicht. – JBL

1

Als Alternative zu einer vollständigen QThread-Lösung können Sie auch QEventLoop verwenden, um eine separate Ereignisschleife zu erstellen, um die Berechnung der Hauptereignisschleife (die die UI hostet) freizugeben. Es ist nicht so flexibel wie QThread, aber sie sind unglaublich schnell zu implementieren.

+0

Sie stellen auch eine ganze große Menge von Problemen dar, da plötzlich die Gesamtheit Ihres GUI-Codes wieder in das Programm gelangt ist. –

+0

Ich dachte, dass der GUI-Code nur dann reentrant werden würde, wenn Sie die Berechnungsklassen in die GUI mischen und sie nicht trennen und über das Signal/Slots-System aufrufen würden? Ich könnte mich irren, es ist lange her, seit ich darüber nachgedacht habe. –

+0

Wo immer Sie 'exec()' in Ihrem eigenen Code sehen, ist eine Stelle, an der eine der 'QObject :: event()' Methoden erneut eingegeben werden kann. Das ist alles was es braucht.Natürlich, technisch, wenn Sie nur eine Ereignisschleife zum Spaß erstellen und dann zerstören, ohne es über 'exec()', Sie sind in Ordnung, aber das ist sicherlich nicht, was Sie gemeint :) –

5

Factor aus der Berechnung auf einen anderen Thread, wie folgt aus: -

// This is the object that will run the computation on a different thread 
class Computation : public QObject 
{ 
signals: 
    void Finished(); 
public slots: 
    void Compute(); 
}; 

dann den anderen Thread in Ihrem Hauptfenster-Klasse erstellen und starten Sie es ausgeführt wird: -

class MyMath : public QMainWindow 
{ 
    public: 
     void StartComputation(); 
}; 


MyMath::StartComputation() 
{ 
    QThread* pThread = new QThread; 
    Computation* pComputation = new Computation; 

    // move computation to the new thread 
    pCompuation->moveToThread(pThread); 

    // Note Qt5 connection style  

    // ensure the computation starts when the thread starts 
    connect(pThread, &QThread::started, pComputation, &Computation::Compute); 
    // when computation is finished, quit the thread 
    connect(pComputation, &Compute::Finished, pThread, &QThread::quit); 
    // have the thread tidy up when finished 
    connect(pThread, &QThread::finished, pThread, &QThread::deleteLater); 
    // start it! 
    pThread->start(); 
} 
+0

Es sollte beachtet werden, dass die 'connect' Syntax in Qt 5. –

+1

neu ist, weshalb ich es Qt 5. – TheDarkKnight

3

Statt Ihre Walz eigene threading Sachen, versuchen die eingebaute inQtConcurrent Namespace. Es ist einfacher, optimiert und weniger fehleranfällig. Es gibt keinen Grund zur Sorge über Sachen zu anderen Threads zu bewegen und explizite Synchronisation durchführen mit mutexes.

QtConcurrent::run verwendet einen internen Thread-Pool Ihre Aufgaben auszuführen und gibt einen QFuture, mit denen Sie interagieren können QFutureWatcher und Signale & Slots verwenden.Die Namen mag kompliziert klingen, aber der Code ist sehr einfach:

class MyMath : public QObject 
{ 
    Q_OBJECT 
public: 

    explicit MyMath(QObject* parent) : QObject(parent) { 
     this->watcher = new QFutureWatcher(this); 
     connect(this->watcher, SIGNAL(finished()), 
       this, SLOT(computationFinished())); 
    } 

public slots: 

    void compute() { 

     // This one is called by the user. Retrieve 
     // the computation arguments (whatever they 
     // may be), start the computation using 
     // QtConcurrent::run and prepare to receive 
     // the results. 
     // 
     // Maybe update the UI to tell the user that 
     // the computationis being performed? 

     Args args = getSomeArgs(); 
     QFuture<Result> res = QtConcurrent::run(this, &MyMath::internalCompute, args); 
     this->watcher->setFuture(res); 
    } 

    void computationFinished() { 
     // The computation is done. Update the GUI 
     // to display the results. Done. 
    } 

private: 

    QFutureWatcher<Result>* watcher; 

    Args getSomeArgs() const { 
     // return arguments needed by compute. 
    } 

    Result internalCompute(Args args) const { 
     // perform very expensive math. 
    } 
}; 

aktualisieren. Nach dem Kommentar von Merlin069 denke ich, dass es nicht ratsam ist, die komplexeren Operationen von QtConcurrent zu empfehlen.

+1

kommentiert Obwohl, wenn Sie QtConcurrent verwenden, dann sollten Sie wahrscheinlich diesen Thread gelesen: http: // Kommentare. gmane.org/gmane.comp.lib.qt.devel/7942 – TheDarkKnight

2

Qt GUI Mathematik Anwendung hängt GUI heraus, während

Berechnung Ich habe eine einfache GUI für meine Anwendung ... ..

Das Hauptproblem mit diesem Code das ist, wenn ich auf 'compute' (es macht so viel Berechnung, es dauert etwa 5 Minuten) es hängt meine GUI aus, so dass ich nichts anderes tun kann (ich kann nicht einmal meine GUI sehen, das Fenster ist für die Zeit "eingefroren") Diese Berechnung läuft. Nachdem die Funktion beendet ist, druckt sie die Ergebnisse auf QLabels, und die GUI ist wieder "am Leben". Wie kann ich das lösen? Ich möchte, dass meine GUI "eingefroren" wird, wenn die Berechnung Zeit braucht. Irgendwelche Ideen? Ich dachte über QThread - aber ich bin irgendwie neu in Threads-Sache, also bitte, geben Sie einfach-leicht verständliche Antworten für Anfänger :)

Es scheint, dass Ihr Programm (GUI) nie hängen. Es geht weiter mit der 'call_C_fun()' von 'compute()' Funktion. Aber die GUI ist nicht Responsive. Siehe die Referenznummer . Halten Sie das GUI Responsive um http://doc.qt.digia.com/qq/qq27-responsive-guis.html. Das wiederkehrende Problem der Einfrieren von GUIs während langer Operationen kann mit vielen Methoden umgehen. Aber der einfachste Weg ist manuelle Ereignisverarbeitung.

Um mit Manueller Ereignisverarbeitung seine, ein QCoreApplication :: process() regelmäßig innerhalb der Schleife verlangen.

Das folgende Beispiel zeigt, wie man arbeitet:

call_C_fun(){ 
.... 
while(Your_loop_condition) { 
    .... 
    QCoreApplication::processEvents(); 
    if (!your_compute_button->isChecked()) { 
     //"Aborted" 
     return; 
    } 
} 
.... 
}