首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QThread和QTimer

QThread和QTimer
EN

Stack Overflow用户
提问于 2013-04-05 13:30:17
回答 4查看 11.3K关注 0票数 3

我正在开发一个QT4.6开发的应用程序。

我想要创建一个自定义计时器,在一个单独的线程中计数。但是,我希望这个计时器能够向主线程发送信号。

我对QThread进行了子类化,但它似乎行不通。

这是Timer.h:

代码语言:javascript
复制
#ifndef TIMER_H
#define TIMER_H

#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QTimer>

class Timer : public QThread
{
    Q_OBJECT
public:
    explicit Timer(QObject *parent = 0);
    ~Timer();

    // true if the timer is active
    bool isCounting();

    // start the timer with a number of seconds
    void startCounting(int value = 300);
    void stopCounting();

    // the number of seconds to reach
    int maximum();

    // the current value of the timer
    int value();

    // elapsed time since the timer has started
    int elapsedTime();

signals:
    // sent when the timer finishes to count
    void timeout();
    // an event is emited at each second when the timer is active
    void top(int remainingSeconds);

protected:
    // launch the thread
    //virtual void run();

private slots:
    // decrements the remaining time at each second and emits top()
    void timerEvent();

private:
    QTimer* _timer;
    // remaining time
    int _left;
    // number of seconds at timer startup
    int _maximum;
};

#endif // TIMER_H

和Timer.cpp:

代码语言:javascript
复制
#include "Timer.h"

Timer::Timer(QObject *parent) :
    QThread(parent)
{
    _timer = new QTimer(this);
    _maximum = 0;
    _left = 0;
    connect(_timer, SIGNAL(timeout()), this, SLOT(timerEvent()));
}

Timer::~Timer()
{
    delete _timer;
}

bool Timer::isCounting()
{
    // test if timer still active
    return _timer->isActive();
}

void Timer::startCounting(int value)
{
    qDebug() << QString("Start timer for %1 secs").arg(QString::number(value));
    if(_left != 0 || _timer->isActive())
    {
         _timer->stop();
    }

    _maximum = value;
    _left = value;

    // emit the first top
    emit top(_left);

    // start the timer: 1000 msecs
    _timer->start(1000);

    // start the thread
    start();
}

void Timer::stopCounting()
{
    qDebug() << QString("Stopping timer at %1 secs => %2 secs remaining.").arg(QString::number(elapsedTime()), QString::number(_left));
    // stop timer
    _timer->stop();
    _left = 0;
    _maximum = 0;
    // kill thread
    terminate();
}

int Timer::maximum()
{
    return _maximum;
}

int Timer::value()
{
    return _left;
}

void Timer::timerEvent()
{
    qDebug() << "Timer event";
    if(--_left == 0)
    {
        // stop timer
        _timer->stop();
        // emit end of timer
        emit timeout();
        // stop thread
        terminate();
    }
    else
    {
        // emit a signal at each second
        emit top(_left);
    }
}

int Timer::elapsedTime()
{
    return (_maximum - _left);
}

编辑

我意识到我试图移动到另一个线程的对象实际上是一个单例。它可能导致一个问题(请看这里)。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-04-05 13:51:50

在这种特殊情况下,不需要对QThread进行子类分类。通常,除非您确信QThread是您所需要的,否则不要对它进行子类化。

下面是一个快速示例,如何在线程中设置工作人员和计时器并启动它:

工人阶级:

代码语言:javascript
复制
class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = 0) : QObject(parent) {}

signals:
    void doSomething();

public slots:
    void trigger() {
        emit doSomething();
    }
};

main.cpp

代码语言:javascript
复制
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MainThreadObject o;

    QThread *thread = new QThread;
    Worker w;
    QTimer timer;
    timer.setInterval(1000);

    timer.moveToThread(thread);
    w.moveToThread(thread);

    QObject::connect(thread, SIGNAL(started()), &timer, SLOT(start()));
    QObject::connect(&w, SIGNAL(doSomething()), &o, SLOT(doSomething()));
    QObject::connect(&timer, SIGNAL(timeout()), &w, SLOT(trigger()));

    thread->start();

    return a.exec();
}

因此,我们有一个MainThreadObject,它表示在主线程中派生的QObject。我们创建了计时器和Worker对象,它只是用来包装一个信号和插槽,以避免子类QThread的需要。定时器被设置并移动到新线程,线程started()信号连接到定时器start()插槽,工作doSomething()信号连接到主线程对象doSomething()插槽,最后定时器timeout()信号连接到工人trigger()插槽。然后启动线程,在事件循环中启动整个链。

因此,每秒钟调用一次MainThreadObject::doSomething(),从辅助线程发出信号。

票数 13
EN

Stack Overflow用户

发布于 2015-09-17 06:31:17

试一试

代码语言:javascript
复制
QMetaObject::invokeMethod(&timer, "start", Qt::QueuedConnection); //timer->start()

如果您想立即启动计时器

代码语言:javascript
复制
QMetaObject::invokeMethod(&timer, "start", Qt::QueuedConnection , Q_ARG(int, 1000 )); //timer->start(200)

如果您想在1000秒后启动计时器

在非GUI线程中(QThread或P线程回调)

票数 1
EN

Stack Overflow用户

发布于 2013-04-05 13:39:23

首先,如果您来自QThread的子类,您必须实现run()方法,如果没有,就没有必要这样做,您可以从QObject继承。

其次,您的QTimer必须驻留在运行事件循环的线程中。如果没有事件循环,就不能传输Qt排队信号。您可以通过在线程的run方法中调用exec()来启动事件循环:

代码语言:javascript
复制
void Timer::run() {
    exec();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15835267

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档