How can I delay the process in Qt

时间:2016-04-04 18:02:16

标签: c++ qt qthread timedelay qtimer

I'm trying to make a visualization of searching for the max value of the array. The idea of it is to show the pointer position in each iteration. There's a grid layout built in the following way: first line includes ten labels showing the index of each element of the array, in the second line there are ten line edits with array values, and in the third there come ten labels which can have text " " (no pointer) or "^" (pointer on this value). It looks like

0 1 2 3 4 5 6 7 8 9 - the row of indexes

12 23 34 54 78 1 32 26 55 26 - the elements

_ _ _ ^ _ _ _ _ _ _ - the row of pointers

When searching for the maximum the pointer must move to the next element after each iteration. And for comfortable perception it is needed to wait a sec during each iteration if the cycle. The code of the slot is:

void Widget::slotFindMax()
{
    int max = a[0];
    pointer[0]->setText("^");
    maxValue->setText(QString::number(max));
    for (int i = 1; i < 10; i++)
    {
        pointer[i - 1]->setText(" ");
        QThread::sleep(1);
        pointer[i]->setText("^");
        if (a[i] > max)
        {
            max = a[i];
            maxValue->setText(QString::number(max));
        }
    }
    pointer[9]->setText(" ");
}

I see that QThread::sleep() doesn't work correctly here. As far as I understood QTimer::singleShot also isn't suitable, cause I need a delay not before processing the slot but during it. Could anyone who faced such a problem give an example of correct using of the functions I mentioned or give an equivalent example which could work in this case?

3 个答案:

答案 0 :(得分:1)

阻止和图形用户界面不能混合。以异步方式编写,利用C ++ 11:

class Widget : ... {
  // use QVector, std::vector or std::array for pointer and a!
  QTimer m_animationTimer { this };
  ...
};

void Widget::slotFindMax()
{
  m_animationTimer.start(1000);
  int i = 0;
  int max = std::numeric_limits<int>::min();
  auto loop = [this, i, max]() mutable {
    if (i > 0) pointer[i-1]->setText(" ");
    if (i == pointer.size()) {
      m_animationTimer.disconnect();
      return m_animationTimer.stop();
    }
    pointer[i]->setText("^");
    if (a[i] > max) {
       max = a[i];
       maxValue->setText(QString::number(max));
    }
    i ++;
  });
  loop(); // run the first iteration
  connect(&m_animationTimer, &QTimer::timeout, loop);
}

loop仿函数按值捕获imax的可变值,并立即运行一次,然后每秒运行一次,直到整个pointer数组被迭代过度。然后它停止计时器。函数从基础QObject::event的{​​{1}}方法调用,调用从事件循环处理QObject。由于您的代码不会阻止事件循环,因此它仍然具有响应性。

在C ++ 98 / Qt 4中,您必须将仿函数放入QTimerEvent派生类等的插槽中。它更详细,但逻辑最终会是一样的。

答案 1 :(得分:0)

To summarize if I understood correctly your question:

  • Save initial time
  • Run the calculation
  • If calculation took more than 1s, just go to the next iteration
  • If time elapsed is smaller than 1s, wait up to 1s

I just suggest you to wait remaining time after the calculation is done.

// Get initial time
auto t1 = QDateTime::currentMSecsSinceEpoch();

// Make a complex operation
if (a[i] > max)
{
    max = a[i];
    maxValue->setText(QString::number(max));
}

// Get final time
auto t2 = QDateTime::currentMSecsSinceEpoch();

// Wait until the end of the 1s if required, or directly continue
if (t2-t1 < 1000) QThread::msleep(1000-(t2-t1));

// Update the pointer
if (i>0) pointer[i - 1]->setText(" ");
pointer[i]->setText("^");

答案 2 :(得分:0)

  

据我所知,QTimer :: singleShot也不合适,因为我   在处理插槽之前需要延迟,但在此期间需要延迟。

如果您使用延迟调用(使用计时器)而不是您的for循环,那么

sort_column可以适用于将索引作为参数并包含循环体的函数。然后,该函数可以使用递增的索引递归调用if。