我怎样才能等到 Qt 中的 keyevents 中的每个进程都完成?
How can i wait until the every process finished in keyevents in Qt?
我创建了一个按键事件,如果我按下 "A" 键,它将执行函数 A()。A() 的过程将持续 2 秒。如果我像 4 次/2 秒那样快地按下键,我想等到每个过程都完成。我测试发现,如果我按 4 次/2 秒的键,它会在以后的按键事件中执行该过程 firstly.How 我可以等到每个过程在 keyevents 中完成吗?我必须尝试使用线程和互斥体。但是出了点问题。第一次用mutex.I不知道怎么解决这个问题
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();
}
不清楚需要什么:
- 如果您想为每个按下的键启动一个线程,请使用
QtConcurrent::run(A);
A()
中没有任何互斥锁
- 如果你想为每个按下的键执行
A()
但不是同时使用 QtConcurrent::run(A);
并在 A()
中使用互斥锁(就像你所做的那样)
如果我没理解错的话,您使用的是要在按下按钮 A 时执行的操作 A()。但是,您在单独的线程中执行操作 A(),因为您不想阻塞 GUI 线程并冻结您的 UI.
如果您不想 "skip" 按钮按下,解决方案很简单:
- 创建一些名为
context
的虚拟 QObject
。
QObject* context = new QObject;
- 叫
QThread
叫 thread
起来 运行。
QThread* thread = new QThread{ this }; thread->start(); ...
- 然后将
context
移动到 thread
object->moveToThread(thread)
.
- 在
MainWindow
class 中创建信号,比如 runA()
。
- 将此信号与
A()
操作连接:
connect(this, &MainWindow::runA, context, [] () { A(); });
- 每次按下按钮 "A" 都会发出这个信号:
emit runA();
每次发出信号时,都会将要执行的操作 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
}
};
无论您按下按钮的速度有多快"A"。 "Action is being executed." 将以恰好 2 秒的间隔打印,并且恰好按下按钮的次数。
一个快速的解决方案是在只有一个线程的线程池上使用 QtConcurrent::run
。这使您不必管理线程的生命周期,这是一种昂贵的资源 - 例如闲置一段时间后将被丢弃以释放资源。
// https://github.com/KubaO/Whosebugn/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"
我创建了一个按键事件,如果我按下 "A" 键,它将执行函数 A()。A() 的过程将持续 2 秒。如果我像 4 次/2 秒那样快地按下键,我想等到每个过程都完成。我测试发现,如果我按 4 次/2 秒的键,它会在以后的按键事件中执行该过程 firstly.How 我可以等到每个过程在 keyevents 中完成吗?我必须尝试使用线程和互斥体。但是出了点问题。第一次用mutex.I不知道怎么解决这个问题
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();
}
不清楚需要什么:
- 如果您想为每个按下的键启动一个线程,请使用
QtConcurrent::run(A);
A()
中没有任何互斥锁
- 如果你想为每个按下的键执行
A()
但不是同时使用QtConcurrent::run(A);
并在A()
中使用互斥锁(就像你所做的那样)
如果我没理解错的话,您使用的是要在按下按钮 A 时执行的操作 A()。但是,您在单独的线程中执行操作 A(),因为您不想阻塞 GUI 线程并冻结您的 UI.
如果您不想 "skip" 按钮按下,解决方案很简单:
- 创建一些名为
context
的虚拟QObject
。QObject* context = new QObject;
- 叫
QThread
叫thread
起来 运行。QThread* thread = new QThread{ this }; thread->start(); ...
- 然后将
context
移动到thread
object->moveToThread(thread)
. - 在
MainWindow
class 中创建信号,比如runA()
。 - 将此信号与
A()
操作连接:
connect(this, &MainWindow::runA, context, [] () { A(); });
- 每次按下按钮 "A" 都会发出这个信号:
emit runA();
每次发出信号时,都会将要执行的操作 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
}
};
无论您按下按钮的速度有多快"A"。 "Action is being executed." 将以恰好 2 秒的间隔打印,并且恰好按下按钮的次数。
一个快速的解决方案是在只有一个线程的线程池上使用 QtConcurrent::run
。这使您不必管理线程的生命周期,这是一种昂贵的资源 - 例如闲置一段时间后将被丢弃以释放资源。
// https://github.com/KubaO/Whosebugn/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"