2016-04-04 7 views
1

Я пытаюсь сделать визуализацию поиска максимального значения массива. Идея состоит в том, чтобы показать позицию указателя на каждой итерации. Существует сетка, построенная следующим образом: первая строка содержит десять ярлыков, показывающих индекс каждого элемента массива, во второй строке - десять строк с значениями массива, а в третьем - десять ярлыков, которые могут иметь текст "" (без указателя) или "^" (указатель на это значение). Похоже, чтоКак отложить процесс в Qt

0 1 2 3 4 5 6 7 8 9 - ряд индексов

12 23 34 54 78 1 32 26 55 26 - элементы

_ _ _ _^_ _ _ _ _ _ - строка указателей

При поиске максимального значения указатель должен перейти к следующему элементу после каждой итерации. И для комфортного восприятия необходимо ждать секунды во время каждой итерации, если цикл. Код щели:

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(" "); 
} 

Я вижу, что QThread :: сон() не работает здесь. Насколько я понял, QTimer :: singleShot тоже не подходит, потому что мне нужна задержка не до обработки слота, но во время его. Может ли любой, кто столкнулся с такой проблемой, привести пример правильного использования упомянутых мной функций или дать эквивалентный пример, который мог бы работать в этом случае?

+0

Ваша проблема заключается в блокировке gui. Пока ваш цикл работает, взаимодействие с пользователем невозможно, и экран не обновляется. Не блокируйте gui. –

ответ

0

Итак, если я правильно понял ваш вопрос:

  • Сохранить начальное время
  • Выполнить расчет
  • Если расчет потребовалось более 1 секунды, просто перейти к следующей итерации
  • Если время ожидания меньше 1 с, ждать до 1 с

Я просто предлагаю вам подождать оставшееся время после расчета.

// 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("^"); 
+0

Расчет времени очень короткий, я не думаю, что это проблема. Думаю, проблема, вероятно, в обновлении экрана. – Ilya

0

Насколько я понял QTimer :: SingleShot также не подходит, потому что нужна задержка не перед обработкой слот, но во время него.

QTimer::singleShot может быть подходящим, если вместо вашей for цикла, то есть задержанный вызов (с помощью таймера) сделать функцию с индексом в качестве параметра и содержащего тело цикла. Затем эта функция может быть вызвана рекурсивно с индексированным индексом.

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 функтор фиксирует изменяемые значения i и max значением, и выполняется один раз сразу, а затем один раз в секунду, пока весь pointer массив не было итерации , Затем он останавливает таймер.Функтор вызывается из метода QObject::event базы QObject, и вызов приходит как QTimerEvent обрабатывается из цикла событий. Поскольку ваш код не блокирует цикл событий, он остается отзывчивым.

В C++ 98/Qt 4 вам нужно было бы поместить функтор в слот в классе QObject и т. Д. Это было бы более подробным, но логика в конечном итоге была бы такой же.

+0

Он говорит: «Поле m_animationTimer имеет неполный тип». Должен ли он быть определен в заголовке? –

+0

@ ЮрийЛевитан Вы должны '#include ' в заголовке, где объявлен класс 'Widget'. Это требование C++, независимо от Qt. –