2013-09-30 24 views
5

Ho una semplice interfaccia grafica per la mia applicazione = Devo impostare alcuni parametri di input per la mia funzione matematica, quindi fare clic sul pulsante 'compute', e la funzione inizia. Le funzioni matematiche sono scritte in pura C quindi non ci sono oggetti, solo funzioni.Qt GUI applicazione matematica si blocca GUI durante il calcolo

Ecco come si presenta:

#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 
} 

Il problema principale di questo codice è che quando scatto 'calcolare' (lo fa talmente tanto di calcolo, ci vogliono fino a 5 minuti o giù di lì) si blocca il mio GUI quindi non posso fare nient'altro (non riesco nemmeno a vedere la mia GUI, la finestra è "congelata" per il tempo in cui il calcolo è in esecuzione. Dopo che la funzione è finita, stampa i risultati su QLabels, e la GUI è ancora una volta "Vivo" Come posso risolvere questo? Non voglio che la mia GUI sia "congelata" quando il calcolo richiede tempo. Qualche idea? Ho pensato a QThread - ma sono un po 'nuovo in thread-thing, quindi per favore, dai risposte semplici e facili da comprendere per i principianti :)

+1

Date un'occhiata a [questo] (https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly- use-qthreads-the-pieno-spiegazione /). Quindi esegui il calcolo nell'oggetto thread e invia un segnale una volta completato. Collega il segnale a uno slot della tua classe facendo qualsiasi cosa tu voglia fare con il risultato. –

+0

E ci sono due ':' punti e virgola dopo 'classe myMath' perché ...? – Shoe

risposta

2

Nel tuo caso, la filettatura sarebbe una soluzione. Il tuo calcolo sarebbe in esecuzione in un thread separato che quindi consentirebbe alla tua GUI di essere reattiva mentre calcola tutto ciò che ti serve.

Questa è una cosa abbastanza comune nella GUI nella mia esperienza. La GUI ha il proprio thread (s) e la tua logica usa il proprio thread (s).

È possibile utilizzare quindi schemi molto semplici per gestirli, con il segnale dalla GUI che avvia i lavoratori e i segnali dai lavoratori che attivano gli aggiornamenti nella GUI.

Avrete bisogno di stare attenti ai soliti problemi di sicurezza del thread. Ti suggerisco caldamente di imparare un po 'sul threading in generale per capire meglio cosa stai facendo. Può anche aiutarti a capire strani comportamenti che potresti osservare quando si utilizza il codice thread (che non è sempre banale per le persone non abituate).

Suggerisco anche di leggere QThread documentation che spiega abbastanza bene come implementare il codice filettato in Qt (preferire l'operatore separato alla sottoclasse di Qthread, però). Dai uno sguardo anche a QMutex e QMutexLocker, potresti averne bisogno.

+0

Per ora, ha creato una sottoclasse di 'QThread' e l'uso di' QMutex' - funziona brillante, evviva! Domani proverò altre anime da questo argomento. E btw - perché la sottoclasse di 'QThread' è nota come cattiva idea? – yak

+0

Re. sottoclasse 'QThread': leggi [questo post del blog] (http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/). – andref

+0

@yak Andref ha collegato un articolo pertinente. Non è sempre male, ma generalmente dovresti preferire l'approccio operaio. Quindi, questo collegamento è anche rilevante, riguardo [Perché non è sempre male sottoclasse QThread] (http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html). Risposta davvero breve: se non hai bisogno di un ciclo di eventi, sottoclasse, se hai bisogno di un ciclo di eventi (segnali, slot, ecc.), Allora non sottoclassi. – JBL

1

In alternativa a una soluzione completa QThread, è possibile utilizzare QEventLoop per creare un ciclo di eventi separato per l'esecuzione del calcolo per mantenere libero il loop di eventi principale (che ospita l'interfaccia utente). Non è così flessibile come lo standard QThread ma sono incredibilmente veloci da implementare.

+0

Espongono anche un sacco di problemi, dal momento che improvvisamente l'intero codice GUI è diventato rientrante. –

+0

Ho pensato che il codice della GUI sarebbe diventato un rientro solo se stavate mescolando le classi di calcolo nella GUI, e non separandole e chiamando attraverso il sistema di segnale/slot? Potrei sbagliarmi, è passato molto tempo da quando l'ho esaminato. –

+0

Ovunque vedi 'exec()' nel tuo codice è un posto dove è possibile reinserire uno qualsiasi dei metodi 'QObject :: event()'. Questo è tutto ciò che serve.Certo, tecnicamente se crei semplicemente un ciclo di eventi per divertimento e poi lo distruggi senza eseguirlo tramite 'exec()', sei a posto, ma sicuramente non è quello che volevi dire :) –

5

Factor fuori il calcolo a un altro thread, in questo modo: -

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

quindi creare l'altro thread nella classe finestra principale e rimetterlo in esecuzione di: -

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

Si noti che la sintassi 'connect' è nuova in Qt 5. –

+1

Questo è il motivo per cui l'ho commentata Qt 5. – TheDarkKnight

3

Invece di tirare il tuo possedere thread, provare lo spazio dei nomi integratoQtConcurrent. È più facile, ottimizzato e meno soggetto a errori. Non è necessario preoccuparsi di spostare roba su altri thread ed eseguire la sincronizzazione esplicita usando mutex.

QtConcurrent::run utilizza un pool di thread interna per eseguire i vostri compiti e restituisce una QFuture con il quale è possibile interagire utilizzando QFutureWatcher e segnali & slot.I nomi può sembrare complicato, ma il codice è molto semplice:

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. 
    } 
}; 

Update. Dopo il commento di Merlin069, penso che non sia saggio raccomandare l'uso delle operazioni più complesse fornite da QtConcurrent.

+1

Anche se si sta utilizzando QtConcurrent, probabilmente si dovrebbe leggere questa discussione: http: // comments. gmane.org/gmane.comp.lib.qt.devel/7942 – TheDarkKnight

2

GUI Qt applicazione matematica bazzica GUI mentre Computing

Ho una semplice interfaccia grafica per la mia domanda ... ..

Il problema principale di questo codice è che quando si fa clic 'compute' (ha troppi calcoli, impiega fino a 5 minuti o giù di lì) appende fuori la mia GUI quindi non posso fare nient'altro (non riesco nemmeno a vedere la mia GUI, la finestra è "congelata" per il tempo il calcolo è in esecuzione e una volta terminata la funzione, stampa i risultati su QLabels e la GUI è ancora una volta "viva" .Come posso risolvere questo? Voglio che la mia GUI sia "congelata" quando il calcolo richiede tempo. Qualche idea? Ho pensato a QThread - ma sono un po 'nuovo in thread-thing, quindi per favore, date risposte semplici e facili da capire per i principianti :)

Sembra che il tuo programma (GUI) non si blocchi mai. Continua a elaborare con la funzione 'call_C_fun()' della funzione 'compute()'. Ma la GUI non è reattiva. Vedere il riferimento di Conservazione della GUI Reattiva allo http://doc.qt.digia.com/qq/qq27-responsive-guis.html. Il problema ricorrente del congelamento delle GUI durante operazioni lunghe può essere affrontato con molti metodi. Ma il modo più semplice è Elaborazione evento manuale.

per stare con Manuale elaborazione di eventi, una persona deve chiamare QCoreApplication :: processEvents() periodicamente all'interno del vostro ciclo.

L'esempio seguente mostra come lavorare:

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