2017-08-28 1 views
0

Je crée un keyevent qui si j'appuie sur la touche "A" fera la fonction A(). Le processus de A() durera 2s. Je veux attendre jusqu'à ce que chaque processus fini si j'appuie sur la touche si rapidement juste comme 4times/2s. J'ai testé et trouvé que si j'appuie sur la touche dans 4times/2s, il fera d'abord le processus dans les événements de pression plus tard. Comment puis-je attendre jusqu'à ce que tous les processus finis dans keyevents? Je dois essayer d'utiliser le fil et le mutex. Mais quelque chose ne va pas. C'est la première fois que j'utilise mutex. Je ne sais pas comment résoudre ce problème.Comment puis-je attendre jusqu'à ce que chaque processus terminé dans keyevents dans Qt?

int g = 0; 
void MainWindow::keyPressEvent(QKeyEvent *event) 
{ 
int keyCode = event->key(); 
if(keyCode == Qt::Key_A) { 
    qDebug() << "da"; 
    a->start(); 
} 
} 


void MyThread::run()// i try to block the second time process while press the key so quickly 
{ 

    mutex->lock(); 
    ...//process:last for 2s 
    g++; 
    mutex->unlock(); 
} 
+1

Quel est votre fil de fer supposé faire?Je ne vois pas pourquoi auriez-vous besoin d'un fil pour cela. Maintenez simplement un compteur de processus démarrés. Utilisez le signal ['QProcess :: finished'] (http://doc.qt.io/qt-5/qprocess.html#finished) pour être informé lorsqu'un processus est terminé. Décrémenter le compteur lorsque vous recevez un tel signal. Lorsque le compteur atteint 0, vous saurez que tous les processus sont terminés. Bien que je ne vois pas quel est le point dans tout cela. Il serait utile que vous expliquiez un peu votre programme. – thuga

+0

J'ai mis à jour le code. Par exemple, je veux mettre à jour la valeur de g après 2s processus dans A(). Cependant, si j'appuie sur la touche si rapidement, il ne mettra pas à jour le g et ne recevra pas le nouvel événement clé et exécutera à nouveau l'exécution de A() à partir de la première ligne. Donc je veux définir un mutex pour empêcher un nouvel événement de venir et s'assurer qu'il peut passer par le A() et mettre à jour g.Mais le code ne fonctionne pas –

+0

Pourquoi voulez-vous mettre à jour 'g' deux secondes après avoir démarré un processus? Pourquoi ne peut-il pas être mis à jour immédiatement? Vous devriez expliquer plus en détail ce que vous essayez d'accomplir, parce que, pour le moment, cela n'a aucun sens. Si vous voulez bloquer un keyevent pendant qu'un processus est en cours d'exécution, vérifiez simplement l'état du processus (http://doc.qt.io/qt-5/qprocess.html#state) dans votre keyevent. – thuga

Répondre

0

Si j'ai bien compris, vous utilisez l'action A() à exécuter sur le bouton A enfoncé. Cependant, vous faites l'action A() dans un thread séparé, car vous ne voulez pas bloquer le thread graphique et geler votre interface utilisateur.

Si vous ne voulez pas "sauter" bouton pousse la solution est simple:

  1. Créer une QObject factice appelé context.
    QObject* context = new QObject;
  2. Appelez QThread appelé thread et opérationnel.
    QThread* thread = new QThread{ this }; thread->start(); ...
  3. Avancez ensuite le context au thread avec object->moveToThread(thread).
  4. Créez un signal dans votre classe MainWindow, par exemple runA().
  5. Connectez ce signal avec avec A() l'action:
    connect(this, &MainWindow::runA, context, []() { A(); });
  6. Chaque fois que le bouton "A" est pressé juste émettre ce signal: emit runA();

Chaque fois que le signal est émis, un événement d'action A() à exécuter est affiché dans la boucle d'événement `threads. Tous les événements seront traités dans l'ordre ils sont affichés.


#pragma once 

#include <QThread> 
#include <QDebug> 
#include <QWidget> 
#include <QKeyEvent> 

class MainWindow : public QWidget 
{ 
    Q_OBJECT 
private: 
    QThread* thread; 
    QObject* context; 

public: 
    MainWindow() 
     : thread{ new QThread }, 
      context{ new QObject } 
    { 
     context->moveToThread(thread); 
     connect(this, &MainWindow::doAction, context, [this]() { 
      Action(); 
     }); 
     thread->start(); 
    } 
    ~MainWindow() { 
     context->deleteLater(); 
     thread->deleteLater(); 
    } 

signals: 
    void doAction(); 

public: 
    void keyPressEvent(QKeyEvent* event) 
    { 
     int keyCode = event->key(); 
     if(keyCode == Qt::Key_A) { 
      emit doAction(); 
     } 
    } 

    void Action() { 
     qDebug() << "Action is being executed."; 
     QThread::currentThread()->sleep(2); // imitate some long calculation 
    } 
}; 

Peu importe la rapidité avec laquelle vous appuyez sur le bouton "A". "L'action est en cours d'exécution." sera imprimé avec exactement 2 secondes d'intervalle et exactement le nombre de fois que le bouton a été pressé.

+0

Merci pour votre réponse. Mais dans mon cas, je veux sauvegarder tous les keyevents dans la file d'attente et les exécuter un par un toutes les 2 secondes (attendre que le processus soit terminé). Par exemple, j'appuie sur la touche 2 fois/s et un processus durera 2s. Donc en 2s j'ai appuyé sur la touche 4 fois. Et je veux enregistrer ces 4 événements dans la file d'attente, et les exécuter un par un toutes les 2s. –

+0

Connectez ce signal avec A() action: connect (this, & MainWindow :: runA, contexte, []() {A();}); ne peut pas travailler –

+0

@MotoJack, Ok, je vois que la première partie n'est pas une option pour vous. Mais pourquoi "connecter ce signal avec" A() 'action" ne peut pas fonctionner? – WindyFields

-1

Il est pas clair ce qui est nécessaire:

  • si vous voulez lancer un fil pour chaque clé d'utilisation pressée QtConcurrent::run(A); sans mutex à l'intérieur A()
  • si vous voulez exécuter A() pour chaque touche enfoncée mais pas en même temps utiliser QtConcurrent::run(A); avec un mutex à l'intérieur A() (comme vous l'avez fait)
+0

J'ai mis à jour le code.Par exemple, je veux mettre à jour la valeur de g après 2s processus dans A (). Cependant, si j'appuie sur la touche si rapidement, il ne mettra pas à jour le g et ne recevra pas le nouvel événement clé et exécutera à nouveau l'exécution de A() à partir de la première ligne. Donc, je veux définir un mutex pour empêcher un nouvel événement de venir et assurez-vous qu'il peut passer par le A() et mettre à jour g.Mais le code ne fonctionne pas –

+0

Cela ne fournit pas de réponse à la question. Vous pouvez [rechercher des questions similaires] (// stackoverflow.com/search), ou vous référer aux questions liées et liées sur le côté droit de la page pour trouver une réponse. Si vous avez une question connexe mais différente, [poser une nouvelle question] (// stackoverflow.com/questions/ask), et inclure un lien vers celui-ci pour aider à fournir le contexte. Voir: [Poser des questions, obtenir des réponses, pas de distractions] (// stackoverflow.com/tour) –

0

Une solution rapide consiste à utiliser QtConcurrent::run sur un pool de threads contenant un seul thread. Cela vous absout d'avoir à gérer la durée de vie du fil, une ressource coûteuse - par ex. il sera éliminé après avoir été inutilisé pendant un certain temps pour libérer des ressources.

// https://github.com/KubaO/stackoverflown/tree/master/questions/single-job-lambda-45913311 
#include <QtWidgets> 
#include <QtConcurrent> 

class LogWindow : public QPlainTextEdit { 
    Q_OBJECT 
    QThreadPool m_pool; 
    int g = {}; // can be accessed from the worker thread only 
    void keyReleaseEvent(QKeyEvent * event) override { 
     if (event->key() == Qt::Key_A) 
     QtConcurrent::run(&m_pool, this, &LogWindow::method); 
     QPlainTextEdit::keyReleaseEvent(event); 
    } 
    /// This method must be thread-safe. It is never reentered. 
    void method() { 
     QThread::sleep(2); // block for two seconds 
     g++; 
     emit done(g); 
    } 
    Q_SIGNAL void done(int); 
public: 
    LogWindow(QWidget * parent = {}) : QPlainTextEdit{parent} { 
     appendPlainText("Press and release 'a' a few times.\n"); 
     m_pool.setMaxThreadCount(1); 
     connect(this, &LogWindow::done, this, [this](int val){ 
     appendPlainText(QString::number(val)); 
     }); 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    LogWindow w; 
    w.show(); 
    return app.exec(); 
} 

#include "main.moc"