Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我怎样才能等到Qt中的keyevents中的每个进程都完成?_C++_Qt_Signals Slots - Fatal编程技术网

C++ 我怎样才能等到Qt中的keyevents中的每个进程都完成?

C++ 我怎样才能等到Qt中的keyevents中的每个进程都完成?,c++,qt,signals-slots,C++,Qt,Signals Slots,我创建了一个keyevent,如果我按下“a”键,它将执行函数a()。a()的过程将持续2秒。如果我像4次/2秒那样快速按键,我想等到每个过程完成。我测试发现,如果我在4次/2秒内按下该键,它将首先在以后的按键事件中执行该过程。我如何才能等到每个过程在keyevents中完成?我必须尝试使用线程和互斥。但有点不对劲。这是我第一次使用互斥。我不知道如何解决这个问题 int g = 0; void MainWindow::keyPressEvent(QKeyEvent *event) { int

我创建了一个keyevent,如果我按下“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();
}
intg=0;
void主窗口::按键事件(QKeyEvent*事件)
{
int keyCode=事件->键();
if(keyCode==Qt::Key_A){
qDebug()开始();
}
}
void MyThread::run()//我试图在如此快速地按键的同时阻止第二次进程
{
互斥->锁();
…//进程:持续2秒
g++;
互斥->解锁();
}

不清楚需要什么:

  • 如果要为每个按下的键启动线程,请使用
    QtConcurrent::run(a)内部没有任何互斥体
    A()
  • 如果要对每个按下的键执行
    A()
    ,但不能同时使用
    QtConcurrent::run(A)中有一个互斥体
    a()
    (就像你做的那样)

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

如果您不想按“跳过”按钮,解决方案很简单:

  • 创建一些名为
    context
    的虚拟
    QObject

    QObject*context=新的QObject
  • 获取调用的
    thread
    线程
    并运行
    QThread*thread=newqthread{this};线程->开始()
  • 然后将
    上下文
    移动到
    线程
    对象->移动到线程(线程)
  • main窗口中创建信号,比如
    runA()

  • A()连接此信号。
    操作:
    connect(这个,&MainWindow::runA,context,[](){A();})
  • 每次按下按钮“A”时,只需发出此信号:
    emit runA()
  • 每次发出信号时,将要执行的动作
    A(
    )的事件发布到“线程事件循环”。所有事件将按发布顺序进行处理


    #pragma一次
    #包括
    #包括
    #包括
    #包括
    类主窗口:公共QWidget
    {
    Q_对象
    私人:
    QThread*线程;
    QObject*上下文;
    公众:
    主窗口()
    :线程{new QThread},
    上下文{new QObject}
    {
    上下文->移动到线程(线程);
    连接(this,&MainWindow::doAction,context,[this](){
    动作();
    });
    线程->开始();
    }
    ~main window(){
    context->deleteLater();
    thread->deleteLater();
    }
    信号:
    无效动作();
    公众:
    无效按键事件(QKeyEvent*事件)
    {
    int keyCode=事件->键();
    if(keyCode==Qt::Key_A){
    发射doAction();
    }
    }
    无效行动(){
    qDebug()sleep(2);//模拟一些长时间的计算
    }
    };
    

    无论你按“A”键多快。“正在执行操作。”将以恰好2秒的间隔打印,并精确显示按钮被按下的次数。

    一个快速解决方案是在只有一个线程的线程池上使用
    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"
    
    //https://github.com/KubaO/stackoverflown/tree/master/questions/single-job-lambda-45913311
    #包括
    #包括
    类日志窗口:公共QPlainTextEdit{
    Q_对象
    QThreadPool m_pool;
    int g={};//只能从工作线程访问
    无效密钥释放事件(QKeyEvent*事件)覆盖{
    if(event->key()==Qt::key_A)
    QtConcurrent::run(&m_-pool,this,&LogWindow::method);
    QPlainTextEdit::keyReleaseEvent(事件);
    }
    ///此方法必须是线程安全的。它永远不会重新输入。
    void方法(){
    QThread::sleep(2);//阻塞两秒钟
    g++;
    发射完成(g);
    }
    Q_信号无效完成(int);
    公众:
    LogWindow(QWidget*parent={}):QPlainTextEdit{parent}{
    追加纯文本(“按下并释放“a”几次。\n”);
    m_pool.setMaxThreadCount(1);
    连接(this,&LogWindow::done,this,[this](int val){
    追加纯文本(QString::number(val));
    });
    }
    };
    int main(int argc,字符**argv){
    QApplication app{argc,argv};
    对数窗口w;
    w、 show();
    返回app.exec();
    }
    #包括“main.moc”
    
    你的线程应该做什么?我不明白你为什么需要一根线。只需维护已启动进程的计数器。使用流程完成时通知的信号。当你收到这样的信号时,减小计数器。当计数器达到0时,您将知道所有进程都已完成。虽然我不明白这一切有什么意义。如果你能稍微解释一下你的程序,那会很有帮助。我已经更新了代码。例如,我想更新a()中2s进程后g的值。但是,如果我这么快按下键,它就不会更新g并接收新的key事件,也不会从第一行再次执行execute A()。因此,我想设置一个互斥锁,以防止新事件发生,并确保它可以通过a()和更新g。但是代码不起作用。为什么要在启动进程两秒钟后更新
    g
    ?为什么不能立即更新?你应该更详细地解释你想要实现什么,因为现在它毫无意义。如果你想在进程运行时阻止一个keyevent,就在你的keyevent中。因为我已经设置了一个tim
    // 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"