Передача и возврат данных в класс Qthread PyQt5

Вопрос по передаче данных для расчетов и их возврате в класс QThread. В init данные передать не позволяет, вероятно, из-за наследования класса. Подскажите, пожалуйста, как это верно сделать.

Заранее спасибо!

from PyQt5 import QtCore, QtWidgets, QtSql, QtGui
from PyQt5.Qt import *

class MainWindow(QMainWindow):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.initUi()

    def initUi(self):
        self.btn2 = QPushButton()
        self.centralWidget = QWidget(self)
        self.VL = QVBoxLayout(self.centralWidget)                
        self.setCentralWidget(self.centralWidget)
        self.gifdialog = QtWidgets.QDialog()
        self.gifdialog.setFixedSize(252, 252)
        self.m_label = QLabel(self.gifdialog)
        self.movie = QMovie()
        self.movie.setFileName(os.getcwd() + r"\mgc.gif")
        self.m_label.setMovie(self.movie)
        self.gifdialog.setWindowFlag(QtCore.Qt.SplashScreen)
        self.thread = GifThread(self)

    def connectUi(self):
        self.btn2.clicked.connect(self.interpretation)
        self.thread.finish_signal.connect(self.stop_gif)

    def stop_gif(self):
        self.movie.stop()
        self.gifdialog.hide()

    def interpretation(self):

        #self.ai = AutoInterpretation(self.datas)  #<----долгие расчеты которые переносятся в GifThread
        #dots_with_data, self.support_times = self.ai.zips()
        #temp_dfs = self.ai.bias_and_splitting()

        self.movie.start()
        self.gifdialog.show()
        self.thread.start()

        dots_with_data, self.support_times, temp_dfs = self.thread.results()
        self.interpreted = True

class GifThread(QtCore.QThread):
    finish_signal = pyqtSignal()

    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)
        #self.data = data #<----- data которая нужна для расчетов, и которую надо передать в текущий класс

    def run(self):
        ai = AutoInterpretation(self.data)  #<----расчеты, теперь в другом потоке, как сюда передать данные?
        self.dwd, self.st = ai.zips()
        self.td = ai.bias_and_splitting()
        self.finish_signal.emit()

    def results(self):
        return self.dwd, self.st, self.td   #еще не уверен, но пока так я собираюсь вернуть данные назад в функцию interpretation для дальнейших действий

app = QApplication(sys.argv)
MW = MainWindow()
MW.show()
sys.exit(app.exec_())

Ответы (2 шт):

Автор решения: S. Nick

я подробно расписал вам как это делается

import sys
import os
from PyQt5 import QtCore, QtWidgets, QtSql, QtGui
from PyQt5.Qt import *


class GifThread(QtCore.QThread):
    finish_signal = pyqtSignal(object, object, object)                 # +++ (object, object, object)
                                                                       #     (  dwd,    st,     td  )
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)

        self.data = None # <-- data которая нужна для расчетов, и которую получим из основного потока

    def run(self):
        print(self.data) # <--  data которая нужна для расчетов !!!!!
        '''
        ai = AutoInterpretation(self.data)  #<----расчеты, теперь в другом потоке, как сюда передать данные?
        sdwd, st = ai.zips()        
        td = ai.bias_and_splitting()
        '''
        # имитирую процесс длительной задачи  !!!
        running = 1
        while running < 100:
            # довольно длительно выполняющаяся часть кода
            self.msleep(50)
            running += 1
        # в результате решения длительной задачи мы получили какие-то данные
        dwd, st =  [1, 2, 3], "Просто строка" 
        td = "Что-то еще"

        self.finish_signal.emit(dwd, st, td)   #  <--- передать данные в основной поток  !!!


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.initUi()

        self.dwd = None                                              # +++
        self.st  = None                                              # +++
        self.td  = None                                              # +++

    def initUi(self):

        self.centralWidget = QWidget()                     
        self.setCentralWidget(self.centralWidget)

        self.btn2 = QPushButton("Запустить задачу")
        self.btn2.clicked.connect(self.interpretation)

        self.VL = QVBoxLayout(self.centralWidget)                
        self.VL.addWidget(self.btn2)

        self.gifdialog = QtWidgets.QDialog()
        self.gifdialog.setFixedSize(252, 252)
        self.m_label = QLabel(self.gifdialog)
        self.movie = QMovie()
        self.movie.setFileName(os.getcwd() + "/img/Fo2BxBK.gif")        # \mgc.gif
        self.m_label.setMovie(self.movie)
        self.gifdialog.setWindowFlag(QtCore.Qt.SplashScreen)

        self.thread = GifThread(self)
        self.thread.finish_signal.connect(self.stop_gif)

    def stop_gif(self, dwd, st, td):                                   # +++ dwd, st, td
        self.movie.stop()
        self.gifdialog.hide()
        # используйте полученные данные где вам надо !!!
        self.dwd = dwd                                                 # +++
        self.st  = st                                                  # +++
        self.td  = td                                                  # +++        
        print(f'''
            Эти данные мы получили из дополнительного потока:
            dwd = {self.dwd};
            st  = {self.st};
            td  = {self.td}.
        ''')

    def interpretation(self):
      # педположим, что в поток надо передать какой-то список фойлов
      # vvvv <-- data которая нужна для расчетов, и которую надо передать в доп.поток !!!
        data, _ = QtWidgets.QFileDialog.getOpenFileNames(
            self, "CSV File", "", "*.csv"
        )
        if data:         # +++ Обратите внимание, что поток запускаем если есть данные для передачи
            self.thread.data = data               # <-- !!! передать данные в дополнительный поток
            self.movie.start()
            self.gifdialog.show()
            self.thread.start()                   # запустить дополнительный поток 


if __name__ == '__main__':
    app = QApplication(sys.argv)
    MW = MainWindow()
    MW.show()
    sys.exit(app.exec_())        

введите сюда описание изображения

→ Ссылка
Автор решения: ikocs

Передавать данные можно следующим образом:

class GifThread(QtCore.QThread):
    finish_signal = pyqtSignal()

    def __init__(self, parent=None, data):
        QtCore.QThread.__init__(self, parent)
        self.data = data

Затем в методе run() их без проблем использовать. Соответственно создание экземпляра у вас будет происходить вот так:

self.thread = GifThread(self, data)

Кроме этого, мне кажется у вас не совсем правильно реализована работа с потоками, но я могу быть не прав. Я реализую по вот этой статье.

Так такая логика:

# Создаем поток
self.thread_pool = QThreadPool()
....
# Создаем экземпляр QRunnable
class ThreadRun(QRunnable):
    def __init__(self, data):
        super(ThreadRun, self).__init__()
        self.data = data
    @pyqtSlot()
    def run(self):
        # Ваша логика
....
# Например, по нажатию кнопки запускаем метод
def analize_run(self):
    analize = ThreadRun(self.analize)
    self.thread_pool.start(analize)

Я кратко привел пример, в статье подробнее.

→ Ссылка