Дизайнер Qt Creator-a и многопоточность, как их подружить

222
29 июня 2018, 03:30

В общем столкнулся с проблемой, если внешний вид программы сделал в дизайнере qt creator-a, то не получаться сделать несколько потоков и взаимодействовать с GUI интерфейсом. Если внешний вид программы написать "руками" в виде кода, без использования дизайнера qt creator-a то получаеться сделать несколько потоков и взаимодействовать с GUI интерфейсом ))). Но так как у меня проделана большая работа в в дизайнере qt creator-a, то я бы не хотел бы перерисовать все с нуля.

По этому я сделал простейший пример, как я делаю. Хотелось бы услышать конструктивную критику и реальный код как надо делать.

Простейшая программа которая выводит на QspinBox постоянно число из бесконечного цикла.

SimpleGUItwoflow.pro

QT       += core gui serialbus widgets concurrent
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = SimpleGUItwoflow
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
        main.cpp \
        mainwindow.cpp
HEADERS += \
        mainwindow.h
FORMS += \
        mainwindow.ui

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QThread>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
signals:
    void update_m(int);
public slots:
    void RepaintReceivedMessage(int i);  
    void Receiving_a_Message();  
private:
    Ui::MainWindow *ui;
};

main.cpp

#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // поток приёма данных
    QThread *thread = new QThread(); // инициализ класс потока
    MyThread_priem *mythread_priem = new MyThread_priem(); // инициализируем второй класс
    connect(thread, SIGNAL(started()), this, SLOT(Receiving_a_Message())); // наследуем thread  а не от MyMainWindows-a
    connect(this,SIGNAL(update_m(int)),this,SLOT(RepaintReceivedMessage(int))); // соединение источника данных с приемником
    this->moveToThread(thread); // отправляем в поток
    thread->start(); // цикл обработки сообщения в потоке0
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::Receiving_a_Message()
{
    qDebug() << "Receiving_a_Message()";
    while (true) {
        for (int i =0; i<1000000;i++){
            qDebug() << "i: " << i;
            emit update_m(i);
        }
    }
}
void MainWindow::RepaintReceivedMessage(int i)
{
    ////
     qDebug() << "RepaintReceivedMessage()";
     ui->spinBox->setValue(i);
}

mainwindow.ui

А вот и результат :

Программа работает но GUI не отвечает. При этом программа не падает.

Исправил код .h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QThread>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
signals:
public slots:
     void RepaintReceivedMessage(int);   
private:
    Ui::MainWindow *ui;
};
class MyThread_priem: public QObject{
Q_OBJECT
public:
    void Clear_Struct();
private:
signals:
 void update_m(int);
public slots:
    void Receiving_a_Message();  
};
#endif // MAINWINDOW_H

.срр #include "mainwindow.h" #include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // поток приёма данных
    QThread *thread = new QThread(); 
    MyThread_priem *mythread_priem = new MyThread_priem(); 
    connect(thread, SIGNAL(started()), mythread_priem, SLOT(Receiving_a_Message())); 
    connect(mythread_priem, SIGNAL(update_m()), this, SLOT(RepaintReceivedMessage())); 
    mythread_priem->moveToThread(thread); 
    thread->start(); 
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MyThread_priem::Receiving_a_Message()
{
    qDebug() << "Receiving_a_Message()";
    while (true) {
        for (int i =0; i<1000000;i++){
            qDebug() << "i: " << i;
            emit update_m(i);
        }
    }
}

void MainWindow::RepaintReceivedMessage(int i)
{
    ////
     qDebug() << "RepaintReceivedMessage()";
     ui->spinBox->setValue(i);
}

Отправил в отдельный поток, но всё равно он не меняет значения spinBox-а

Answer 1

У Вас не код, а кошмар. Начнём с того, что вот это this->moveToThread(thread); является рассадником проблем, поэтому this не надо никогда перемещать в другой поток. Читайте статьи по правильному использованию QThread, начать можно с You’re doing it wrong….

Ну а конкретная проблема в Вашем коде в том, что у Вас MainWindow живёт вне UI потока (Вы его сами переместили), и в коде этого окна вызывается ui->spinBox->setValue(i);, что запрещено делать вне потока UI.

Answer 2

Вот код, всё работает.

.pro не менялся

.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QThread>

namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
signals:
public slots:
    void RepaintReceivedMessage(int);
private:
    Ui::MainWindow *ui;
};
class MyThread_priem: public QObject{
    Q_OBJECT
public:
    void Clear_Struct();
private:
signals:
    void update_m(int);
public slots:
    void Receiving_a_Message();
};
#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCheckBox>
#include <QHBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QThread *thread = new QThread(); 
    MyThread_priem *mythread_priem = new MyThread_priem();
    connect(thread, SIGNAL(started()), mythread_priem, SLOT(Receiving_a_Message())); 
    connect(mythread_priem, SIGNAL(update_m(int)), this, SLOT(RepaintReceivedMessage(int))); 
    mythread_priem->moveToThread(thread); // отправляем в поток
    thread->start(); 
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MyThread_priem::Receiving_a_Message()
{
    qDebug() << "Receiving_a_Message()";
    while (true) {
        for (int i =0; i<100000;i++){
            qDebug() << "i: " << i;
            emit update_m(i);
        }
    }
}
void MainWindow::RepaintReceivedMessage(int i)
{
     qDebug() << "RepaintReceivedMessage()";
     ui->spinBox->setValue(i);
}

.ui не менялся

main.cpp не менялся

READ ALSO
Как сделать сортировку по ФИО [дубликат]

Как сделать сортировку по ФИО [дубликат]

На данный вопрос уже ответили:

238
Дан массив. Найти строку, сумма элементов которой минимальна?

Дан массив. Найти строку, сумма элементов которой минимальна?

Нужна помощь с реализацией задачи на С++, как пишется она на паскале я понял, а вот перевести ее на С++ затрудняюсь, суть программыДан массив...

242
iconv всегда EILSEQ

iconv всегда EILSEQ

iconv всегда выдает ошибку EILSEQ с указанием на последний символ, что не так?

211