Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Firefox от Июнь 26, 2013, 09:35



Название: QThread
Отправлено: Firefox от Июнь 26, 2013, 09:35
Здравствуйте подскажите по такому вопросу: создаю отдельный класс, пытаюсь его запустить в новом потоке. В методе run() стартую таймер. Но когда по сигналу из основного потока пытаюсь сменить интервал таймера, то выдает ошибку, что не возможно убить и стартовать объект из другого потока. как правильно обратиться к объекту таймера в потоке уже созданном, чтоб это было корректно?и правильно ли поток запускается, а то при старте тоже пишет ошибку?
//Класс потока
Код:
//.h
class CalkRastr: public QThread
{
    Q_OBJECT
public:
    CalkRastr();
    ~CalkRastr();
protected:
    void run();

private:
    QTimer *tPrepict;
    void Prepicture();
   
public slots:
  void NewScale(unsigned char scale); // изменение интервала таймера при изменении шкалы в СОРД

private slots:
   void SlotPrepic();

};
//.cpp
void CalkRastr::run()
{
    tPrepict=new QTimer(this);
    connect(tPrepict,SIGNAL(timeout()),SLOT(SlotPrepic()));
    tPrepict->start(135);
    exec();
}
void CalkRastr::SlotPrepic()
{
    Prepicture();
    emit SendDataToSord(&Mas_ind[0][0]);
}
void CalkRastr::NewScale(unsigned char scale)
{
    if(scale==0)
        tPrepict->setInterval(135);
    if(scale==1)
        tPrepict->setInterval(270);
    if(scale==2)
        tPrepict->setInterval(540);
    if(scale==3)
        this->tPrepict->setInterval(1080);
    if(scale==4)
        tPrepict->setInterval(1340);
    Scale=scale;
}
// основной поток
Код:
//.h
class MainWindow : public QMainWindow
                 
{
    Q_OBJECT
   
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QTimer *tmSord, *tmBor;
    void newScale(unsigned char Scale);
 
private:
    Ui::MainWindow *ui;
   
    CalkRastr *calcRst;

signals:
   
    void SigNewScale(unsigned char);
private slots:
   

};

//.cpp
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
 calcRst=new CalkRastr();
 connect(this,SIGNAL(SigNewScale(unsigned char)),calcRst,SLOT(NewScale(unsigned char)));
calcRst->start();

}
void MainWindow::newScale(unsigned char Scale)
 {
     if(oldScale!=Scale)
     {
         oldScale=Scale;
         emit SigNewScale(oldScale);
     }
 }


Ввыводе приложения в QtCreator пишет следующие ошибки(фиолетовым):
при старте процесса:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is CalkRastr(0xc5b0048), parent's thread is QThread(0xab27130), current thread is CalkRastr(0xc5b0048)
при смене интервала таймера:
QObject::killTimer: timers cannot be stopped from another thread
QObject::startTimer: timers cannot be started from another thread


Название: Re: QThread
Отправлено: Bepec от Июнь 26, 2013, 09:43
Или используй "moveToThread(this)" в конструкторе потока, или же кидай moveToThread при создании в самого себя.

Создавать и убивать в другом потоке нельзя. Зато можно вызвать слот и тогда он будет радостно исполняться в своём потоке (если конечно тип соединения - очередь).


Название: Re: QThread
Отправлено: Firefox от Июнь 26, 2013, 09:47
если я поставлю moveToThread(this) в конструкторе класса, то разве не создастся новый поток при вызове start()? И немного не понятно, я же вызываю слот из класса потока CalkRastr, почему это другой поток получается?


Название: Re: QThread
Отправлено: demaker от Июнь 26, 2013, 16:47
Вы создаете объект потока CalkRastr в основном потоке.
А QTimer вы создаете уже в другом по токе.

Попробуйте так
Выслать сигнал из основного потока и привязать его к слоту объекта потока CalkRastr.
А из слота объекта потока CalkRastr выслать сигнал для смены  интервала таймера(или наоборот, как хотите).
Должно помочь.

Потом

Код
C++ (Qt)
void CalkRastr::run()
{
tPrepict=new QTimer(this); //УБРАТЬ this!!!
...
}
 

иначе Ваш таймер будет дочерним от CalkRastr, а он создан в основном потоке.


Название: Re: QThread
Отправлено: Igors от Июнь 26, 2013, 17:13
если я поставлю moveToThread(this) в конструкторе класса, то разве не создастся новый поток при вызове start()?
Создастся и так и так. Осуждаемое moveToThread(this) просто говорит в каком потоке объект должен принимать сигналы/события (какой eventLoop)


Название: Re: QThread
Отправлено: Bepec от Июнь 26, 2013, 17:27
Уточняю свою реплику - при moveToThread(this) все объекты класса,наследованного от QThread будут созданы в его потоке. В ином случае все создаваемые объекты в иных методах, кроме как run будут созданы в потоке родителя вашего унаследованного класса.

Как то так.


Название: Re: QThread
Отправлено: Firefox от Июнь 27, 2013, 09:33
Спасибо большое всем за советы.все заработало и в голове немного прояснилось. :)