Сигнал Qt получен, но пользовательский интерфейс его не показывает

Я новичок в qt и хочу создать поток, который отправляет целочисленный сигнал, и у меня есть главное окно, которое получает сигнал, и я уверен, что сигнал доставлен, поскольку я использовал cout, чтобы увидеть его, но когда я хочу отправить полученный номер в spinbox (или ярлык), размещенный в пользовательском интерфейсе, основной поток застрял и ничего не показывает.

вот мой класс потока:

#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);

    }
}

главное окно.ч:

#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. Что не так?


person Seyed Hojat Mirtajadini    schedule 05.12.2016    source источник


Ответы (1)


Вам нужно запустить поток, вызвав его метод start(), а не метод run(). Ваша реализация потока неправильно делает run() общедоступным методом: это позволило вам совершить эту ошибку - иначе это было бы невозможно по конструкции. run() должно быть protected, а не public.

Вероятно, вы также захотите прервать цикл, когда запрашивается прерывание потока (см. 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 и использование универсального безопасного потока для его размещения - этот процесс подробно описан в этом ответе< /а>.

Третье преобразование может включать использование модуля Qt Concurrent для распараллеливания вычислений между несколькими потоками, если это возможно.

person Kuba hasn't forgotten Monica    schedule 05.12.2016