Qt:有什么方法可以调用具有特定时间间隔的一系列插槽?
Qt: is there any way to call a sequence of slots with certain time interval?
我现在的工作方式是将 QTimer
连接到第一个插槽,在第一个插槽内它将触发另一个单发 QTimer
,这将触发第二个插槽...等等。
如果我一次更新所有小部件,GUI 会卡住一秒钟。但这是显而易见的。所以我想避免这种情况。
但是这个代码很难写。您必须在所有地方添加 QTimer
。有没有更好的解决方案?
编辑:这就是我更新小部件的方式,也许有更好的方法?
void UAVInfoView::updateDisplay()
{
if (!visibleRegion().isEmpty()){
info = _dataSrc->getUAVInfo(_id-1);
if (info)
{
//if new package received try to do updating.
if (_pakchk != info->_pakcnt){
//only update the text if there is communication
if (info->_communication != COMMSTATUS::WAIT4CONNECTION && info->_communication != COMMSTATUS::LOST)
{
ui->plainTextEdit->setPlainText(tr("x: %1\ny: %2\nz: %3").arg(info->_pos[0]).arg(info->_pos[1]).arg(info->_pos[2]));
}
//only update the status indicator only if status changed.
if (_status != info->_communication)
{
switch (info->_communication){
case COMMSTATUS::CONNECTED:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:green;}");
ui->label_2->setText("On Line");
break;
case COMMSTATUS::LOST:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:red;}");
ui->label_2->setText("Lost");
break;
case COMMSTATUS::WAIT4CONNECTION:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:grey;}");
ui->label_2->setText("Off Line");
}
}
}
//update the status and package counter to serve the state machine.
_status = info->_communication;
_pakchk = info->_pakcnt;
}
}
}
如你所见,它只是一堆默认的 =, !如果还有其他事情...
我不太清楚你想达到什么目的,但是如果你想用定时器触发一组特定的函数的执行,你可能需要引入一些带有单个的控制实例 QTimer
,您可以随意使用。
既然你说你不想一直更新所有的 GUI 小部件,我猜你正在使用 QWidgets
,你也可以使用 setUpdatesEnabled(bool)
方法来禁用所有update()
或 repaint()
调用的效果。
如果这对您没有帮助,也许您可以更详细地解释您的问题?
如果更新方法比较复杂,您应该尝试QtConcurrent::map()到运行在另一个线程中更新。然后你不需要延迟,因为当更新完成时你会收到 map() 的通知。
虽然我认为问题出在其他地方,但我会给您一个可能的解决方案。你可以使用状态机。只有一个由计时器触发的插槽,您可以在其中根据当前状态调用一些其他函数。
...
connect(&timer, SIGNAL(timeout()), this, SLOT(myStateSlot()));
timer.start(1000);
...
void MyClass::myStateSlot()
{
switch(state)
{
case State_Start:
operation1();
// you can change the state here.. or somewhere else.. up to your design
break;
case State_Two:
operation2();
break;
case State_End:
timer.stop();
break;
}
}
您可以在连接到计时器的插槽中以一定间隔调用它们。您连接到计时器的插槽可能像:
void myClass::onTriggered()
{
switch(turn){
case 0:
slot1();
break;
case 1:
slot2();
break;
...
}
turn++;
if(turn>=numberOfSlots)
turn = 0;
}
这样每次调用一个slot,然后依次调用。
您的问题可能源于 QPlainTextEdit
的相对缓慢。请改用 QLabel
。否则,代码看起来不错。确保如果有多个对 updateDisplay
的后续调用,它们都应该在没有控制 return 调用之间的事件循环的情况下发生。
以下是错误的,因为每个 processEvents
都会强制重新绘制小部件。
w.updateDisplay();
QCoreApplication::processEvents();
w.updateDisplay();
QCoreApplication::processEvents();
您可能在没有意识到的情况下调用了 processEvents()
。每当您从 QObject::event()
和 return 事件队列当时为空时,它都会被有效地调用。另请注意,QObject::event()
是排队插槽调用的调用方。因此,如果您有一个到插槽的排队连接,控件 returns 将在插槽 returns 之后立即进入事件循环。
我现在的工作方式是将 QTimer
连接到第一个插槽,在第一个插槽内它将触发另一个单发 QTimer
,这将触发第二个插槽...等等。
如果我一次更新所有小部件,GUI 会卡住一秒钟。但这是显而易见的。所以我想避免这种情况。
但是这个代码很难写。您必须在所有地方添加 QTimer
。有没有更好的解决方案?
编辑:这就是我更新小部件的方式,也许有更好的方法?
void UAVInfoView::updateDisplay()
{
if (!visibleRegion().isEmpty()){
info = _dataSrc->getUAVInfo(_id-1);
if (info)
{
//if new package received try to do updating.
if (_pakchk != info->_pakcnt){
//only update the text if there is communication
if (info->_communication != COMMSTATUS::WAIT4CONNECTION && info->_communication != COMMSTATUS::LOST)
{
ui->plainTextEdit->setPlainText(tr("x: %1\ny: %2\nz: %3").arg(info->_pos[0]).arg(info->_pos[1]).arg(info->_pos[2]));
}
//only update the status indicator only if status changed.
if (_status != info->_communication)
{
switch (info->_communication){
case COMMSTATUS::CONNECTED:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:green;}");
ui->label_2->setText("On Line");
break;
case COMMSTATUS::LOST:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:red;}");
ui->label_2->setText("Lost");
break;
case COMMSTATUS::WAIT4CONNECTION:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:grey;}");
ui->label_2->setText("Off Line");
}
}
}
//update the status and package counter to serve the state machine.
_status = info->_communication;
_pakchk = info->_pakcnt;
}
}
}
如你所见,它只是一堆默认的 =, !如果还有其他事情...
我不太清楚你想达到什么目的,但是如果你想用定时器触发一组特定的函数的执行,你可能需要引入一些带有单个的控制实例 QTimer
,您可以随意使用。
既然你说你不想一直更新所有的 GUI 小部件,我猜你正在使用 QWidgets
,你也可以使用 setUpdatesEnabled(bool)
方法来禁用所有update()
或 repaint()
调用的效果。
如果这对您没有帮助,也许您可以更详细地解释您的问题?
如果更新方法比较复杂,您应该尝试QtConcurrent::map()到运行在另一个线程中更新。然后你不需要延迟,因为当更新完成时你会收到 map() 的通知。
虽然我认为问题出在其他地方,但我会给您一个可能的解决方案。你可以使用状态机。只有一个由计时器触发的插槽,您可以在其中根据当前状态调用一些其他函数。
...
connect(&timer, SIGNAL(timeout()), this, SLOT(myStateSlot()));
timer.start(1000);
...
void MyClass::myStateSlot()
{
switch(state)
{
case State_Start:
operation1();
// you can change the state here.. or somewhere else.. up to your design
break;
case State_Two:
operation2();
break;
case State_End:
timer.stop();
break;
}
}
您可以在连接到计时器的插槽中以一定间隔调用它们。您连接到计时器的插槽可能像:
void myClass::onTriggered()
{
switch(turn){
case 0:
slot1();
break;
case 1:
slot2();
break;
...
}
turn++;
if(turn>=numberOfSlots)
turn = 0;
}
这样每次调用一个slot,然后依次调用。
您的问题可能源于 QPlainTextEdit
的相对缓慢。请改用 QLabel
。否则,代码看起来不错。确保如果有多个对 updateDisplay
的后续调用,它们都应该在没有控制 return 调用之间的事件循环的情况下发生。
以下是错误的,因为每个 processEvents
都会强制重新绘制小部件。
w.updateDisplay();
QCoreApplication::processEvents();
w.updateDisplay();
QCoreApplication::processEvents();
您可能在没有意识到的情况下调用了 processEvents()
。每当您从 QObject::event()
和 return 事件队列当时为空时,它都会被有效地调用。另请注意,QObject::event()
是排队插槽调用的调用方。因此,如果您有一个到插槽的排队连接,控件 returns 将在插槽 returns 之后立即进入事件循环。