QTimer的跨线程启动问题

记录一个跨线程启动QTimer的问题。问题是个小问题,但是不注意的话就不是知道为啥咱的计时器它咋就坏了呢。

先看个示例代码:(为简洁 部分省略[手动狗头])

//*.h

//主窗口类
class Dialog : public QDialog
{
    Q_OBJECT

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

    void startTimer();

public slots:
    void slotTimeout();

private:
    Ui::Dialog *ui;
    QTimer timer;
};

//工作线程
class WorkThread : public QThread
{
    Q_OBJECT
public:
    WorkThread(QObject* parent);
protected:
    virtual void run() override;
};


///
//*.cpp

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    qDebug() << "Main:" << QThread::currentThreadId();

    timer.setSingleShot(true);
    connect(&timer, &QTimer::timeout,this, &Dialog::slotTimeout);

    startTimer();

    WorkThread* th = new WorkThread(this);
    th->start();
}

void Dialog::startTimer()
{
    qDebug() << __FUNCTION__ << QThread::currentThreadId();
    timer.start(1000);
}

void Dialog::slotTimeout()
{
    qDebug() << __FUNCTION__;
}

WorkThread::WorkThread(QObject *parent):QThread(parent)
{}

void WorkThread::run()
{
    qDebug() << "Thread id:" << QThread::currentThreadId();
    QThread::sleep(3);
    qobject_cast<Dialog*>(parent())->startTimer();

    QThread::exec();
}

这一小段干了什么呢?计时器设置成单发,主窗口类Dialog启动了一次计时器;接着启动了一个线程,线程也启动了一次计时器,只不过让线程休息3秒后才启动。看结果:

 从结果上看,线程启动的QTimer似乎失败了 Qt直接给了错误消息,告诉我们不能从另一个线程中启动计时器。赶紧看看文档

 上面巴拉巴拉的就不看了,直接看重点,我们必须要在他所在线程中启动停止。人家都说这么明白了,改吧。

//第一 startTimer改成槽函数
public slots:
    void startTimer(); 
    void slotTimeout();

//第二 调用用invokeMethod
//qobject_cast<Dialog*>(parent())->startTimer();
QMetaObject::invokeMethod(parent(),"startTimer",Qt::QueuedConnection);

用invokeMethod就省去了再定义信号,关联信息这两步,非常方便。

再看结果,没毛病了。从线程中调用的startTimer 线程id也成了主线程id。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt中进行线程更新UI,需要使用Qt的信号槽机制配合Qt线程机制来实现。具体来说,需要在UI主线程中创建一个QObject对象,并将其移动到其他线程中。然后,在该对象中定义槽函数,用于接收其他线程发送的信号并更新UI。最后,在其他线程中使用QMetaObject::invokeMethod()或QTimer::singleShot()等方法来触发该对象的槽函数。 示例代码如下: ``` cpp class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = nullptr) : QObject(parent) {} signals: void signalUpdateUI(QString text); public slots: void slotDoWork() { // 进行耗时操作 QString result = doSomething(); // 发送信号更新UI emit signalUpdateUI(result); } private: QString doSomething() { // ... } }; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {} public slots: void slotUpdateUI(QString text) { ui->label->setText(text); } private: Ui::MainWindow *ui; Worker *m_worker; QThread *m_workerThread; private slots: void on_pushButton_clicked() { m_worker = new Worker; m_workerThread = new QThread(this); // 将Worker对象移动到工作线程中 m_worker->moveToThread(m_workerThread); // 连接信号槽 connect(m_workerThread, &QThread::started, m_worker, &Worker::slotDoWork); connect(m_worker, &Worker::signalUpdateUI, this, &MainWindow::slotUpdateUI); connect(m_worker, &Worker::destroyed, m_workerThread, &QThread::quit); // 启动线程 m_workerThread->start(); } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值