收到Qt信号,但ui没有显示

时间:2016-12-05 16:36:05

标签: multithreading qt qthread

我是qt的新手,想要创建一个发送整数信号的线程,我有一个接收信号的主窗口,我确信信号是在我用cout看到的时候发送的,但是当我想发送收到的信息时放置在ui中的旋转框(或标签)的数字主线程被卡住并且没有显示任何内容。

这是我的主题类:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QtCore>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);
    void run();
    bool Stop;

signals:
    void NumberChanged(int);

public slots:

};

#endif // MYTHREAD_H

线程的cpp文件:

#include "mythread.h"
#include <QtCore>

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

void MyThread::run()
{

    for(int i=0;i<2000000;i++){

        QMutex m;
        emit NumberChanged(i);
        QThread::msleep(100);

    }
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "mythread.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::MainWindow *ui;

private slots:
    void on_pushButton_clicked();

public slots:
    void onNumberChanged(int num);
};

#endif // MAINWINDOW_H

最后是mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>

using namespace std;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    mthread = new MyThread(this);
    connect(mthread,SIGNAL(NumberChanged(int)),this,SLOT(onNumberChanged(int)));

    mthread->property(Q)

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onNumberChanged(int num)
{
    cout << num << endl;
    ui->spinBox->setValue(num);
}

void MainWindow::on_pushButton_clicked()
{
    mthread->run();
}

当我运行它时,整数值由cout显示但旋转框或标签根本没有变化,直到数字达到2000000.什么错了?

1 个答案:

答案 0 :(得分:2)

您需要通过调用其start()方法而不是run()方法来启动该线程。你的线程实现错误地使run()成为一种公共方法:这使你犯了这个错误 - 否则它就不可能通过构造来实现。 run()应该是protected,而不是public

您可能还希望在请求线程中断时中断循环(c.f。QThread::requestInterruption()QThread::isInterruptionRequested())。你还需要随时使线程可以破坏,这样当你退出应用程序时,线程就会干净利落。

最后,您想要将线程与用户界面分离:窗口不需要知道线程,反之亦然。它们应该通过兼容的接口连接,例如,通过信号和插槽。

因此,我首先将您的代码转换为:

#include <QtWidgets>

class MyThread : public QThread
{
   Q_OBJECT
public:
   using QThread::QThread;
   ~MyThread() { requestInterruption(); wait(); }
   void run() override {
      for(int i=0; i<2000000 && !isInterruptionRequested(); i++) {
         emit numberChanged(i);
         QThread::msleep(100);
      }
   }
   Q_SIGNAL void numberChanged(int);
};

class Window : public QWidget
{
   Q_OBJECT
   QVBoxLayout m_layout{this};
   QPushButton m_start{"Start"};
   QPushButton m_stop{"Stop"};
   QSpinBox m_box;
public:
   Window() {
      m_layout.addWidget(&m_start);
      m_layout.addWidget(&m_stop);
      m_layout.addWidget(&m_box);
      connect(&m_start, &QPushButton::clicked, this, &Window::reqStart);
      connect(&m_stop, &QPushButton::clicked, this, &Window::reqStop);
   }
   Q_SIGNAL void reqStart();
   Q_SIGNAL void reqStop();
   Q_SLOT void setNumber(int n) {
      m_box.setValue(n);
   }
};

int main(int argc, char **argv) {
   QApplication app{argc, argv};
   MyThread t;
   Window w;
   QObject::connect(&w, &Window::reqStart, &t, [&t]{ t.start(); });
   QObject::connect(&t, &MyThread::numberChanged, &w, &Window::setNumber);
   QObject::connect(&w, &Window::reqStop, &t, &MyThread::requestInterruption);
   w.show();
   return app.exec();
}

#include "main.moc"

第二个转换涉及将循环移动到QObject,并使用通用安全线程来托管它 - 该过程在this answer中详细说明。

第三个转换可能涉及使用Qt Concurrent模块在可能的情况下跨多个线程并行化计算。