c++ - Qt 多个异步 While 循环和 qApp->processEvents();

标签 c++ qt while-loop qtimer

我正在尝试做一个项目,使用 Qt GUI C++ 5.6.2 在窗口上创建一些图形。 我有两个名为“createVerticalSpeedIndicator”和“createAirSpeedIndicator”的方法。这些方法需要使用 while(1) 循环创建一些图形并使用 qApp->processEvents();在窗口上,当其中一个正在工作而另一个处于非事件状态时,他们做得很完美。但我需要同时且始终运行它们。

我该怎么做才能同时且始终运行它们。

非常感谢

最佳答案

解决方案是反转控制流。 while() { ... processEvents() ... } 是异步代码中的反模式,因为它假设您拥有控制点,而实际上您没有。您很幸运,没有耗尽堆栈,因为 processEvents 可能会重新进入 createXxx 方法。

这是一个完整的转换示例:

// Input
void Class::createVerticalSpeedIndicator() {
  for (int i = 0; i < 100; i ++) {
    doStep(i);
    QCoreApplication::processEvents();
  }
}
// Step 1 - factor out state
void Class::createVerticalSpeedIndicator() {
  int i = 0;
  while (i < 100) {
    doStep(i);  
    QCoreApplication::processEvents();
    i++;
  }
};
// Step 2 - convert to continuation form
void Class::createVerticalSpeedIndicator() {
  int i = 0;
  auto continuation = [=]() mutable {
    if (!(i < 100))
      return false;
    doStep(i);  
    QCoreApplication::processEvents();
    i++;
    return true;
  };
  while (continuation());
};
// Step 3 - execute the continuation asynchronously   
auto Class::createVerticalSpeedIndicator() {
  int i = 0;
  return async(this, [=]() mutable {
    if (!(i < 100))
      return false;
    doStep(i);
    i++; // note the removal of processEvents here
    return true;
  });
};

template <typename F> void async(QObject * parent, F && continuation) {
  auto timer = new QTimer(parent);
  timer->start(0);
  connect(timer, &QTimer::timeout, [timer, c = std::move(continuation)]{
    if (!c())
      timer->deleteLater();
  });
}

此时,您可以将相同的转换应用于 createAirSpeedIndicator 并在类的构造函数中启动它们:

Class::Class(QWidget * parent) : QWidget(parent) {
  ...
  createVerticalSpeedIndicator();
  createAirSpeedIndicator();
}

两个任务都将在主线程中异步且伪并发地运行,即每个任务将交替执行一个步骤。

假设我们想要链接任务,即只有在前一个任务完成后才开始任务。用户代码中的修改可以很简单:

Class::Class(QWidget * parent) : QWidget(parent) {
  ...
  createVerticalSpeedIndicator()
  >> createAirSpeedIndicator()
  >> someOtherTask();
}

async 函数现在必须返回一个允许建立此类连接的类:

struct TaskTimer {
  QTimer * timer;
  TaskTimer & operator>>(const TaskTimer & next) {
    next.timer->stop();
    connect(timer, &QObject::destroyed, next.timer, [timer = next.timer]{
      timer->start(0);
    });
    timer = next.timer;
    return *this;
  }
};

template <typename F> TaskTimer async(QObject * parent, F && continuation) {
  TaskTimer task{new QTimer(parent)};
  task.timer->start(0);
  connect(task.timer, &QTimer::timeout, 
          [timer = task.timer, c = std::move(continuation)]{
            if (!c())
              timer->deleteLater();
  });
  return task;
}

关于c++ - Qt 多个异步 While 循环和 qApp->processEvents();,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44319577/

相关文章:

c++ - 单例场景,重载不同参数的getInstance?

c++ - 带有两个(或更多)特定包(特化/重载)的可变参数函数模板

c++ - "::' 变量'"指的是什么?

c - fgets 不通过 while 循环 C 进行第二次扫描

c++ - 是否可以#include 命名空间类到另一个命名空间

c++ - 如何使用 Qt 在队列中创建多个线程?

python - 使用 python file_dialog() 从 Scientific Linux 访问 Windows 共享上的网络文件夹

linux - native KDE 寻找 Qt 5 应用程序

php - 使用 while() 生成随机文件名?

java - 如何解决这个无限 while 循环?