我怎么能等到Qt中的关键事件中的每个进程都完成了?

时间:2017-08-28 06:57:21

标签: c++ qt signals-slots

我创建了一个keyevent,如果我按下键#34; A"它将执行函数A()。A()的过程将持续2秒。我想等到每个过程完成,如果我按下这么快就像4次/ 2秒。我测试并发现如果我按下4次/ 2秒的键,它将首先在稍后的按键事件中执行该过程。我怎么能等到每个进程在keyevents中完成?我必须尝试使用​​线程和互斥。但是有些不对劲。这是我第一次使用互斥锁。我不知道如何解决这个问题。

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();
}

3 个答案:

答案 0 :(得分:0)

如果我理解正确,你可以按下按钮A上的想要动作A()。但是,您在单独的线程中执行操作A(),因为您不想阻止GUI线程并冻结UI。

如果你不想&#34;跳过&#34;按钮推动解决方案很简单:

  1. 创建一个名为QObject的虚拟context
    QObject* context = new QObject;
  2. 启动并QThread调用thread
    QThread* thread = new QThread{ this }; thread->start(); ...
  3. 然后将context移至thread object->moveToThread(thread)
  4. MainWindow课程中创建信号,说runA()
  5. 将此信号与A()动作连接:
    connect(this, &MainWindow::runA, context, [] () { A(); });
  6. 每次按钮&#34; A&#34;按下只是发出此信号:emit runA();
  7. 每次发出信号时,要执行的动作事件A()都会被发送到“线程事件循环”。所有活动将按顺序处理

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

    无论您多快按下按钮&#34; A&#34;。 &#34;正在执行行动。&#34;将以2秒的间隔打印,并且按下按钮的次数。

答案 1 :(得分:0)

一个快速的解决方案是在线程池中使用QtConcurrent::run,其中只有一个线程。这使您无需管理线程的生命周期,这是一种昂贵的资源 - 例如它将在未使用一段时间后被处置以释放资源。

// 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"

答案 2 :(得分:-1)

目前尚不清楚需要什么:

  • 如果您想为每个按键使用QtConcurrent::run(A);启动一个主题,而A()
  • 内没有任何互斥锁
  • 如果您要为每个按键执行A()但不能同时使用QtConcurrent::run(A); A()内的互斥锁(就像您所做的那样)