【问题标题】:Qt Multiple Async While Loops and qApp->processEvents();Qt 多个异步 While 循环和 qApp->processEvents();
【发布时间】:2017-11-03 07:30:51
【问题描述】:

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

我可以做些什么来同时和始终运行它们。

非常感谢

【问题讨论】:

  • 您当前是尝试在同一个 while 循环中呈现两个指标,还是两个?您使用的是 OpenGL 小部件还是内置小部件?您是否为它们使用单​​独的线程?一些示例伪代码会很好。鉴于此描述,有太多可能出错的地方。
  • 我使用了线程,但我看到了一些我正在创建图形的卡顿,所以我想如果在同一个循环中显示,我可能会失去平滑。因为我会将这 15 个图形相乘。我正在使用内置小部件
  • 你经历过什么样的“卡顿”?您使用的是哪个内置小部件? 15 究竟是什么?请发布您的一些代码和您的图形图片。

标签: c++ qt while-loop qtimer


【解决方案1】:

解决方案是反转控制流。 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 2016-01-28
    • 1970-01-01
    • 2011-08-09
    • 2015-04-04
    • 1970-01-01
    相关资源
    最近更新 更多