的解決方案是反轉控制流。 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;
}
您目前正在努力使這兩個指標在同while循環,還是兩個?您是使用OpenGL小部件還是內置小部件?你使用單獨的線程嗎?一些僞代碼的例子會很好。鑑於此描述,有太多可能會出錯的事情。 – rationalcoder
我使用了線程,但是我看到了一些粘連,我正在創建圖形,所以我想如果在同一個循環中顯示,我可能會失去smotth。因爲我會將這15張圖片分開。我正在使用內置小工具 –
您遇到過什麼樣的「粘連」?您正在使用哪個內置小工具? 15究竟是什麼?請發佈一些您的代碼和圖片。 – rationalcoder