PyQt QThread: как запустить функцию для рабочего объекта в том же потоке?

Я просто не могу понять, как правильно использовать QThreads. У меня есть рабочий объект и графический интерфейс с двумя полями со списком: когда пользователь выбирает элемент в comboWorkspace, элементы в comboModel будут загружаться. Что происходит, так это то, что всякий раз, когда я выбираю из comboWorkspace, он снова запускает функцию get_workspaces из работника. Вероятно, это потому, что я снова и снова вызываю функцию «старт» QThread. Мне очень жаль, если здесь много чего не так. Если кто-то может просто дать мне представление о том, как правильно подойти к этому. Большое спасибо!

* полный код с функцией setupUi находится здесь: pastebin.com/Y7dGbRLu

from PyQt5 import QtCore, QtGui, QtWidgets
import os
import time
from functools import partial
import copy

class anaplanWorker(QtCore.QObject):

    signal_workspacenames = QtCore.pyqtSignal(str)
    signal_modelnames = QtCore.pyqtSignal(str)
    finish_progressbar = QtCore.pyqtSignal()
    start_progressbar = QtCore.pyqtSignal()
    finish_workspace_thread = QtCore.pyqtSignal()
    finish_model_thread = QtCore.pyqtSignal()
    count_run = 0

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


    def get_workspaces(self):
        ws_names = ['Name One', 'Name Two', 'Name Three']

        self.start_progressbar.emit()
        for ws_name in ws_names:
            self.signal_workspacenames.emit(ws_name)

        self.finish_workspace_thread.emit()


    def get_models(self,workspaceindex):

        self.start_progressbar.emit()

        models = ['Model One', 'Model Two', 'Model Three']

        for model_name in models:
            self.signal_modelnames.emit(model_name)

        self.finish_model_thread.emit()


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        """ui setup for combo combo boxes: comboWorkspace and comboModel"""

    def progress_start(self):
        print("start")

    def progress_finish(self):
        print("finish")

#workspace functions
    def add_workspace(self, workspace_name):
        self.comboWorkspace.addItem(workspace_name)

    def start_workspace(self):

        self.comboWorkspace.clear()
        self.workspace_thread = self.anaplan_thread
        self.anaplan_worker.moveToThread(self.workspace_thread)
        self.workspace_thread.started.connect(self.anaplan_worker.get_workspaces)        
        self.workspace_thread.start()

#model functions
    def add_model(self, model_name):
        self.comboModel.addItem(model_name)

    def start_model(self):
        #clear combomodel
        self.comboModel.clear()
        workspaceIndex = self.comboWorkspace.currentIndex()

        self.model_thread = self.anaplan_thread
        self.anaplan_worker.moveToThread(self.model_thread)

        self.model_thread.started.connect(partial(self.anaplan_worker.get_models, workspaceIndex))

        self.model_thread.start()

#quit threads
    def quit_model_thread(self):
        self.model_thread.quit()
        print("quit model thread")

    def quit_workspace_thread(self):
        self.workspace_thread.quit()
        print("quit workspace thread")


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Tool"))
        self.labelWorkspace.setText(_translate("MainWindow", "Workspace"))
        self.labelModel.setText(_translate("MainWindow", "Model"))

        self.anaplan_worker = anaplanWorker()
        self.anaplan_thread = QtCore.QThread()

        self.anaplan_worker.signal_workspacenames.connect(self.add_workspace)

        self.anaplan_worker.signal_modelnames.connect(self.add_model)

        self.anaplan_worker.finish_workspace_thread.connect(self.quit_workspace_thread)

        self.anaplan_worker.finish_model_thread.connect(self.quit_model_thread)

        self.comboWorkspace.activated[str].connect(self.start_model)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    ui.start_workspace()
    sys.exit(app.exec_())
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
1 516
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы должны разделить свой код больше. Это решило бы многие ваши проблемы.

У вас есть две основные проблемы: вы снова устанавливаете соединения сигналов/слотов каждый раз, когда меняете индекс (одно соединение означает один вызов). Вы используете один и тот же поток для двух разных задач.

Вы должны создать новый класс MainWindow и перенести в него свою бизнес-логику. Ваш класс Ui_MainWindow должен обрабатывать только часть пользовательского интерфейса (виджеты, макеты и т. д.).

У вашего anaplanWorker куча проблем: он наследуется от QObject, но вызывает QThread.__init__, и вы используете его для создания потока и объекта рабочий. Было бы понятнее использовать напрямую QThread.

Класс также следует разделить на две разные части: одну для рабочей области и одну для модели:

class ModelWorker(QtCore.QObject):

    signal_modelnames = QtCore.pyqtSignal(str)
    finish_progressbar = QtCore.pyqtSignal()
    start_progressbar = QtCore.pyqtSignal()
    finish_model_thread = QtCore.pyqtSignal()

    def __init__(self, parent=None):
         super().__init__(parent) 

    def get_models(self,workspaceindex):
        print("Get models with", workspaceindex)
        self.start_progressbar.emit()

        models = ['Model One', 'Model Two', 'Model Three']

        for model_name in models:
            self.signal_modelnames.emit(model_name)

        self.finish_model_thread.emit()

class WorkspaceWorker(QtCore.QObject):
    signal_workspacenames = QtCore.pyqtSignal(str)
    finish_progressbar = QtCore.pyqtSignal()
    start_progressbar = QtCore.pyqtSignal()
    finish_workspace_thread = QtCore.pyqtSignal()
    finish_model_thread = QtCore.pyqtSignal()

    def __init__(self, parent=None):
         super().__init__(parent)


    def get_workspaces(self):
        ws_names = ['Name One', 'Name Two', 'Name Three']

        self.start_progressbar.emit()
        for ws_name in ws_names:
            self.signal_workspacenames.emit(ws_name)

        self.finish_workspace_thread.emit()

Затем в классе MainWindow создайте и настройте потоки и соединения. Вы просто должны начать поток, когда это необходимо.

class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setupUi(self)

        self.workspaceWorker = WorkspaceWorker()
        self.modelWorker = ModelWorker()

        self.workspaceWorker_thread = QThread(self)
        self.modelWorker_thread = QThread(self)

        self.workspaceWorker.moveToThread(self.workspaceWorker_thread)
        self.modelWorker.moveToThread(self.modelWorker_thread)

        self.workspaceWorker.signal_workspacenames.connect(self.add_workspace)
        self.workspaceWorker.finish_workspace_thread.connect(self.quit_workspace_thread)

        self.modelWorker.signal_modelnames.connect(self.add_model)
        self.modelWorker.finish_model_thread.connect(self.quit_model_thread)

        self.comboWorkspace.activated[str].connect(self.start_model)

        self.modelWorker_thread.started.connect(lambda: self.modelWorker.get_models(self.comboWorkspace.currentIndex()))
        self.workspaceWorker_thread.started.connect(self.workspaceWorker.get_workspaces)

        self.start_workspace()


    def add_workspace(self, workspace_name):
        self.comboWorkspace.addItem(workspace_name)

    def start_workspace(self):

        self.comboWorkspace.clear()
        self.workspaceWorker_thread.start()

#model functions
    def add_model(self, model_name):
        self.comboModel.addItem(model_name)

    def start_model(self):
        #clear combomodel
        self.comboModel.clear()
        self.modelWorker_thread.start()

#quit threads
    def quit_model_thread(self):
        self.modelWorker_thread.quit()
        print("quit model thread")

    def quit_workspace_thread(self):
        self.workspaceWorker_thread.quit()
        print("quit workspace thread")

Другие вопросы по теме