Russian Qt Forum
Сентябрь 30, 2024, 18:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QTimer, QThread  (Прочитано 6176 раз)
Bhted
Гость
« : Февраль 20, 2015, 13:14 »

Нужен таймер, который будет работать в отдельном потоке приложения и после определённого числа переполнений останавливаться. Почему таймер в отдельном потоке? У меня в приложении есть ещё события, и пока они отрабатывают сигналы от таймер выстраиваются в очередь и потом одной пачкой отрабатывают, что мне не подходит. А не подходит, потому что таймер при переполнении рисует разные положения стрелочного индикатора. Визуально стрелка из крайнего положения сразу дёргается в нуль, без плавного движения.
Вот нашёл в сети код, чтобы таймер работал в отдельном потоке. Тут как-то можно из потока сказать таймеру стоп?

worker.h
Код:

#include <QDebug>
#include <QThread>

class Worker : public QObject
{
    Q_OBJECT

public:

    Worker();
private slots:
    void onTimeout();

private:
    int counter;
};




worker.cpp
Код:
#include "worker.h"

Worker::Worker()
{
    counter = 0;
}

void Worker::onTimeout()
{
    qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
    counter++;
    //if (counter == 3)
    // stopTimer();
}



mainwindow.h
Код:
#include <QMainWindow>
#include <QDebug>
#include <QThread>
#include <QTimer>
#include "worker.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QThread t;
    QTimer timer;
    Worker worker;

private slots:
    void onInit();
    void onStart();
};



mainwindow.cpp
Код:
...
    connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(onStart()));
...
//------------------------------------------------------------------------------
void MainWindow::onStart()
{
    qDebug()<<"From main thread: "<<QThread::currentThreadId();

    QObject::connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
    timer.start(1000);

    worker.moveToThread(&t);

    t.start();
}
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #1 : Февраль 20, 2015, 15:06 »

что мешает запихнуть таймер в Worker и общаться посредством сигналов и слотов?
Записан
Bhted
Гость
« Ответ #2 : Февраль 20, 2015, 15:26 »

Я тогда получу "timers cannot be stopped from another thread"
Вот как я делал:
worker.h
Код:
class Worker : public QObject
{
    Q_OBJECT

public:

    Worker();
    void start();

private slots:
    void onTimeout();
    void stop();

signals:
     void stopTimer();

private:
    int counter;
    QTimer timer;
};

worker.cpp
Код:
Worker::Worker()
{
    counter = 0;
    QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
    QObject::connect(this, SIGNAL(stopTimer()), this, SLOT(stop()));
}

void Worker::start()
{
    timer.start(1000);
}

void Worker::stop()
{
    timer.stop();
}

void Worker::onTimeout()
{
    qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
    counter++;
    if (counter == 3)
    {
        emit stopTimer();
        //timer.stop();
    }
}

mainwindow.cpp
Код:
//------------------------------------------------------------------------------
void MainWindow::onStart()
{
    qDebug()<<"From main thread: "<<QThread::currentThreadId();

    worker.moveToThread(&t);
    worker.start();

    t.start();
}
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Февраль 20, 2015, 15:29 »

Работай через сигналы/слоты или инвокМетод, а не прямыми вызовами методов.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Bhted
Гость
« Ответ #4 : Февраль 20, 2015, 15:50 »

Работай через сигналы/слоты или инвокМетод, а не прямыми вызовами методов.
А конкретней можете сказать? Я вроде через сигналы/слоты работаю. Когда надо остановить таймер, посылаю сигнал emit stopTimer(), который связан со слотом stop() и вот тогда я и получаю "timers cannot be stopped from another thread".

Зато на прямой вызов worker.start(), который делает timer.start(1000), он почему-то не ругается, что стартовать не хочет.
« Последнее редактирование: Февраль 20, 2015, 15:52 от Bhted » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #5 : Февраль 20, 2015, 15:52 »

Код
C++ (Qt)
QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::QueuedConnection);
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Февраль 20, 2015, 15:58 »

Нужен таймер, который будет работать в отдельном потоке приложения и после определённого числа переполнений останавливаться. Почему таймер в отдельном потоке? У меня в приложении есть ещё события, и пока они отрабатывают сигналы от таймер выстраиваются в очередь и потом одной пачкой отрабатывают, что мне не подходит. А не подходит, потому что таймер при переполнении рисует разные положения стрелочного индикатора. Визуально стрелка из крайнего положения сразу дёргается в нуль, без плавного движения.
Насчет "пачки событий от таймера" это Вы загнули, там одно событие. Ну ладно, допустим вынесли как-то таймер в поток и тогда получаете от него события "по расписанию". А толку? Ведь рисовать "стрелочный индикатор" можно только в главной нитке которая забита др событиями. Поэтому лучше использовать вторичный цикл processEvents
Записан
Bhted
Гость
« Ответ #7 : Февраль 20, 2015, 16:15 »

Код
C++ (Qt)
QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::QueuedConnection);
Ммм... если у меня сигналы и слоты от таймера внутри Worker будут помещаться/извлекаться в/из очереди, то как это повлияет на "timers cannot be stopped from another thread"?... Я Вас, видимо, не так понял.

Цитировать
Насчет "пачки событий от таймера" это Вы загнули, там одно событие. Ну ладно, допустим вынесли как-то таймер в поток и тогда получаете от него события "по расписанию". А толку? Ведь рисовать "стрелочный индикатор" можно только в главной нитке которая забита др событиями. Поэтому лучше использовать вторичный цикл processEvents
Ну, там таймер приконнекчен через Qt::QueuedConnection, поэтому я решил, что из-за этого там будет сразу несколько событий, также по индикатору это видно.

Цитировать
Поэтому лучше использовать вторичный цикл processEvents
Да вот когда я вызывал QApplication::processEvents(), там начинались проблемы... Сейчас ещё раз посмотрю, что там было.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Февраль 20, 2015, 16:18 »

Как я понял, у тебя идут "тяжелые" вычисления, во время которых ты хочешь крутить индикатор. Если так, то ты не то выносишь в поток - нужно выносить вычисления, а не таймер.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Февраль 20, 2015, 16:39 »

Да вот когда я вызывал QApplication::processEvents(), там начинались проблемы... Сейчас ещё раз посмотрю, что там было.
Насчет processEvents() это я погорячился Улыбающийся - если в очереди много событий, они и будут извлекаться. Ну а почему бы самому не отслеживать истекшее время и обновлять индикатор синхронно? Часто это выглядит примерно так (псевдокод)
Код
C++ (Qt)
// расчеты
for (int i = 0; i < data.size(); ++i) {
DoCalc(i);
if ((i % 100) == 0)    // обновляем каждые 100 итераций
  UpdateIndicator(i);
}
 
void UpdateIndicator( int val )
{
 static QTime theTime = QTime::currentTime();
 if (theTime.elapsed() < 300) return;
 theIndicator->setValue(val);
 theIndicator->repaint();
 theTime.restart();
}
 

Как я понял, у тебя идут "тяжелые" вычисления, во время которых ты хочешь крутить индикатор. Если так, то ты не то выносишь в поток - нужно выносить вычисления, а не таймер.
Qt рекомендует так делать потому что до этого делали по-старинке (как выше). Но это не значит что новый способ всегда лучше  Улыбающийся
Записан
Bhted
Гость
« Ответ #10 : Февраль 20, 2015, 17:08 »

У меня много частых событий (каждый 100 мс) от com-порта. С портом работаю через QtSerialPort. Читаю данные через сигнал от порта, сигналы выстраиваются в очередь с помощью Qt::QueuedConnection. Данные мы обрабатываем и строим график и рисуем стрелку. Логика работы стрелки такая: установили заданное значение и за n-секунд стрелка возвращается в исходное положение. Значения, устанавливаемые стрелке, меняются не слишком часто.
График строится отлично при такой интенсивности входных данных. А вот стрелка, повторюсь, мельком устанавливается в заданное положение и сразу в исходное возвращается.

Значит, попробую запихать чтение данных из порта и их обработку в отдельный поток.
Ну и также попробую "отслеживать истекшее время и обновлять индикатор синхронно". Только счётчик i цикла станет членом класс или статической переменной. В общем, попробую. Суть я уловил.
« Последнее редактирование: Февраль 20, 2015, 17:10 от Bhted » Записан
Alexu007
Гость
« Ответ #11 : Февраль 22, 2015, 09:57 »

Для отсчитывания промежутков времени в потоке необязательно прикручивать таймер, в потоке есть функция паузы. В поток можно передавать макс. значение стрелки, и он через фиксированные промежутки времени будет посылать сигналы, по которым можно возвращать стрелку в 0.

Код
C++ (Qt)
detki::detki(int x)
{
   postrelka = x;
}
 
 
void detki::run()
{
   // приоритет потока
   this->setPriority(QThread::IdlePriority);
 
       for (int i = postrelka; i > 0; i--)
       {
           //пауза в микросекундах
           this->msleep(500);                
 
           emit YourSignal(QString::number(i));
       }
 
   exec();
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.198 секунд. Запросов: 23.