Канонический способ использовать QTimer в отдельном потоке - PullRequest
0 голосов
/ 07 октября 2018

Я пытаюсь создать рабочий поток, который будет обновлять QTWidget с интервалами в 1 секунду (можно считать, что это цифровые часы или средство обновления индикатора выполнения, лучше подойдет для приложения).

Мое приложение предназначено для авионики, которая вычисляет информацию об отслеживании полета по маршруту полета и регулярно обновляет карту или какой-либо другой виджет QT во время полета с интервалом в 1 секунду (я полагаю, вы могли бы думать об этом как о каком-то индикаторе прогресса -где индикатор выполнения можно заменить на виджет карты или таблицы в моем случае).Потоку, вероятно, потребуется около 10-20 секунд для вычисления полных данных о полете - (однако первые результаты будут доступны почти сразу же) - эти результаты необходимо отправлять с интервалом в 1 секунду в графический интерфейс для обновления местоположения воздушного судна.на карте.

Существует много путаницы относительно правильного и неправильного способа включения таймера, который обновляет рабочий поток.Лучшим источником знаний, который я нашел, была беседа на QtCon, озаглавленная Многопоточность с Qt - Giuseppe D'Angelo - кажется, что предпочтительным методом является рабочий QObject, который не подкласс QThread итаймер работает в своем собственном обработчике событий - но при переносе рабочего потока в другой поток возникает большая путаница, которую я не очень хорошо понимаю, и я ищу несколько канонических советов о том, как сделать это правильно.Делать это в лямбде было бы идеально, так как я мог бы держать логику и потоки относительно изолированными, что было бы идеально.

Я смотрю, чтобы увидеть, не может ли кто-то указать мне в направлении аналогичного примера (особенно если этоиспользует современные лямбды).В настоящее время я использую QT 5.11.2.

Мой рабочий объект (который содержит QTimer выглядит следующим образом):

class SimulatedFlightWorker : public QObject
{
    Q_OBJECT
public:
    explicit  SimulatedFlightWorker()
        : mpMMRFlightData{}
    {}
public slots:
    // worker thread slot that computes the mpMMRFlightData
    void importSimulatedFlight(
        const QString& fileName,
        const int aPlaybackSpeed);
    void updateGUI(int secondsElapsed);
signals:
    // every second during the flight we need to send a new MMR
    // record to the GUI - to display on a spreadsheet or google map
    void updateFlightData(const MMRTimedRecord& rMMRRecord);

    // this is effectively when the worker thread is done
    void flightCompleted();
private:
    QTimer mTimer;
    // the 
    std::unique_ptr<MMRFlightData> mpMMRFlightData;
};

Это код, в котором я настраиваю сигналы и слоты(еще не работает)

// Experimental worker model adapted from YouTube tutorial
// by Giuseppe di Angelo https://www.youtube.com/watch?v=BgqT6SIeRn4
auto thread = new QThread;
auto worker = new SimulatedFlightWorker;


connect(thread, &QThread::started, worker, &SimulatedFlightWorker::importSimulatedFlight);
connect(worker, &SimulatedFlightWorker::flightCompleted, thread, &QThread::quit);
connect(thread, &QThread::finished, worker, &SimulatedFlightWorker::deleteLater);

worker->moveToThread(thread);
thread->start();

1 Ответ

0 голосов
/ 07 октября 2018

Это действительно просто:

  1. Ваши вычисления выполняются в классе, производном от QObject

  2. Обновления выдаются с помощью сигнала в этом объекте.

  3. Расчеты выполняются небольшими порциями, которые занимают 10-20 мс.

  4. Расчеты инициируются таймером с нулевой длительностью - это не таймер, а способ определения состояния простоя цикла событий в потоке.

  5. Обновления запускаются с 1-секундного таймера.

Этот класс может быть запущен в любом потоке - он даже будет работать в потоке GUI, но сделает его немного менее отзывчивым (но вовсе не отвечающим).

Обычно вы создаете экземпляр класса, запускаете вычисления и перемещаете его в отдельный поток.

...