我怎样才能等到 Qt 的 keyevents 中的每个进程完成?
Posted
技术标签:
【中文标题】我怎样才能等到 Qt 的 keyevents 中的每个进程完成?【英文标题】:How can i wait until the every process finished in keyevents in Qt? 【发布时间】:2017-08-28 06:57:20 【问题描述】:我创建了一个按键事件,如果我按下按键“A”,它将执行功能 A()。A() 的过程将持续 2 秒。如果我像 4 次/2 秒那样快速按下键,我想等到每个过程完成。我测试发现,如果我在 4 次/2 秒内按键,它会首先在以后的按键事件中执行该过程。我如何才能等到每个过程在 keyevents 中完成?我必须尝试使用线程和互斥锁。但是有些不对劲。第一次用mutex,不知道怎么解决。
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();
【问题讨论】:
你的线程应该做什么?我不明白你为什么需要一个线程。只需维护已启动进程的计数器。进程完成时使用QProcess::finished
信号通知。当您收到此类信号时减少计数器。当计数器达到 0 时,您将知道所有进程都已完成。虽然我不明白这一切有什么意义。如果您稍微解释一下您的程序,将会很有帮助。
我已经更新了代码。例如我想在A()中2s处理后更新g的值。但是,如果我这么快按下键,它就没有更新 g 并接收新的键事件并再次从第一行执行 A()。所以我想设置一个互斥锁来防止新事件的发生,并确保它可以通过 A() 并更新 g。但是代码不工作
为什么要在启动进程两秒后更新g
?为什么不能立即更新?您应该更详细地解释您要达到的目标,因为现在它没有任何意义。如果您想在进程运行时阻止某个键事件,只需在您的键事件中添加check the state of the process。
因为我已经设置了一个计时器,在更新之前使用 g 进行 2 秒的处理。所以我想把所有的keyevents保存在队列中,每2s一个一个地执行(等到进程完成再做下一步)
【参考方案1】:
如果我理解正确,您可以使用希望操作 A() 在按下按钮 A 时执行。但是,您在单独的线程中执行操作 A(),因为您不想阻塞 GUI 线程并冻结您的 UI。
如果您不想“跳过”按钮按下,解决方法很简单:
-
创建一些名为
context
的虚拟QObject
。 QObject* context = new QObject;
启动并运行名为thread
的QThread
。 QThread* thread = new QThread this ; thread->start(); ...
然后将context
移动到thread
object->moveToThread(thread)
。
在MainWindow
类中创建信号,例如runA()
。
将此信号与A()
操作连接:connect(this, &MainWindow::runA, context, [] () A(); );
每次按下按钮“A”时都会发出这个信号:emit runA();
每次发出信号时,都会将要执行的操作A(
) 的事件发布到`threads 事件循环。所有事件将按它们发布的顺序处理。
#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
;
无论您多快按下按钮“A”。 “正在执行行动。”将以精确的 2 秒间隔和精确的按钮按下次数打印。
【讨论】:
感谢您的回答。但在我的情况下,我想将所有键事件保存在队列中,并每 2 秒一个一个地执行(等到进程完成再做下一步)。例如,我按键 2 次/秒,一个进程将持续 2 秒。所以在 2 秒内我按了 4 次键。我想将这4个事件保存在队列中,每2s一个一个执行。 用 A() 动作连接这个信号:connect(this, &MainWindow::runA, context, [] () A(); );无法工作 @MotoJack,好的,我知道第一部分不适合您。但是为什么“用A()
动作连接这个信号”不起作用呢?
我给了[] () A();
只是作为一个占位符。请参阅我的测试工作示例。【参考方案2】:
一个快速的解决方案是在只有一个线程的线程池上使用QtConcurrent::run
。这使您不必管理线程的生命周期,这是一种昂贵的资源 - 例如。它会在一段时间未使用后被丢弃以释放资源。
// https://github.com/KubaO/***n/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 = ) : QPlainTextEditparent
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 appargc, argv;
LogWindow w;
w.show();
return app.exec();
#include "main.moc"
【讨论】:
【参考方案3】:不清楚需要什么:
如果您想为每个按下的键启动一个线程,请使用QtConcurrent::run(A);
,而A()
内没有任何互斥锁
如果您想为每个按下的键执行A()
,但不是同时使用QtConcurrent::run(A);
和A()
内的互斥锁(就像您所做的那样)
【讨论】:
我已经更新了代码。例如我想在A()中经过2s处理后更新g的值。但是,如果我这么快按下键,它就没有更新 g 并接收新的键事件并再次从第一行执行 A()。所以我想设置一个互斥锁来防止新事件的到来,并确保它可以通过 A() 并更新 g。但是代码不起作用 这并没有提供问题的答案。您可以search for similar questions,或参考页面右侧的相关和链接问题找到答案。如果您有一个相关但不同的问题,ask a new question,并包含指向此问题的链接以帮助提供上下文。见:Ask questions, get answers, no distractions以上是关于我怎样才能等到 Qt 的 keyevents 中的每个进程完成?的主要内容,如果未能解决你的问题,请参考以下文章