为什么我的QThreads持续崩溃使Maya崩溃?

问题描述 投票:0回答:1

我有一个要在Maya内部使用线程化的UI。这样做的原因是,这样我可以在不使用进度条等更新UI的情况下运行Maya.cmds而不挂起/冻结UI。

我已经从StackOverflow阅读了一些示例,但是我的代码每运行一次就会崩溃。我遵循的示例是herehere

import maya.cmds as cmds
from PySide2 import QtWidgets, QtCore, QtGui, QtUiTools
import mainWindow #Main window just grabs the Maya main window and returns the object to use as parent.

class Tool(QtWidgets.QMainWindow):
    def __init__(self, parent=mainWindow.getMayaMainWindow()):
        super(Tool, self).__init__(parent)

        UI = "pathToUI/UI.ui"
        loader = QtUiTools.QUiLoader()
        ui_file = QtCore.QFile(UI)
        ui_file.open(QtCore.QFile.ReadOnly)
        self.ui = loader.load(ui_file, self)

        #Scans all window objects and if one is open with the same name as this tool then close it so we don't have two open.
        mainWindow.closeUI("Tool")      

        ###HERE'S WHERE THE THREADING STARTS###
        #Create a thread
        thread = QtCore.QThread()
        #Create worker object
        self.worker = Worker()
        #Move worker object into thread (This creates an automatic queue if multiples of the same worker are called)
        self.worker.moveToThread(thread)

        #Connect buttons in the UI to trigger a method inside the worker which should run in a thread
        self.ui.first_btn.clicked.connect(self.worker.do_something)
        self.ui.second_btn.clicked.connect(self.worker.do_something_else)
        self.ui.third_btn.clicked.connect(self.worker.and_so_fourth)

        #Start the thread
        thread.start()

        #Show UI
        self.ui.show()

class Worker(QtCore.QObject):
    def __init__(self):
        super(Worker, self).__init__() #This will immediately crash Maya on tool launch
        #super(Worker).__init__() #This works to open the window but still gets an error '# TypeError: super() takes at least 1 argument (0 given)'

    def do_something(self):
        #Start long code here and update progress bar as needed in a still active UI.
        myTool.ui.progressBar.setValue(0)
        print "doing something!"
        myTool.ui.progressBar.setValue(100)

    def do_something_else(self):
        #Start long code here and update progress bar as needed in a still active UI.
        myTool.ui.progressBar.setValue(0)
        print "doing something else!"
        myTool.ui.progressBar.setValue(100)

    def and_so_fourth(self):
        #Start long code here and update progress bar as needed in a still active UI.
        myTool.ui.progressBar.setValue(0)
        print "and so fourth, all in the new thread in a queue of which method was called first!"
        myTool.ui.progressBar.setValue(100)

#A Button inside Maya will import this code and run the 'launch' function to setup the tool
def launch():
    global myTool
    myTool = Tool()

我期望UI保持活动状态(未锁定),并且线程在运行Maya cmds时不会在更新UI进度条时完全崩溃Maya。

任何对此的见识都将是惊人的!

python python-2.7 maya qthread pyside2
1个回答
0
投票

据我所见,它具有以下错误:

  • thread是一个局部变量,当构造函数完成执行时会删除该变量,导致在主线程中执行不希望执行的操作,解决方案是延长生命周期,为此,有几个解决方案:1)设置类属性,2)将父级传递到它们由父级管理的生命周期中。在这种情况下,请使用第二种解决方案。

  • 您不应该从另一个线程修改GUI,如果您已经从另一个线程修改了progressBar,则在Qt中,您必须使用信号。

  • 您必须在另一个线程中执行的方法中使用@Slot装饰器。

  • 您表示要修改myTool,但尚未声明,因此,通过将global myTool设置为要删除的局部变量,myTool将不起作用。解决方法是声明myToolmyTool = None考虑到上述情况,解决方案是:

import maya.cmds as cmds
from PySide2 import QtWidgets, QtCore, QtGui, QtUiTools
import mainWindow  # Main window just grabs the Maya main window and returns the object to use as parent.


class Tool(QtWidgets.QMainWindow):
    def __init__(self, parent=mainWindow.getMayaMainWindow()):
        super(Tool, self).__init__(parent)

        UI = "pathToUI/UI.ui"
        loader = QtUiTools.QUiLoader()
        ui_file = QtCore.QFile(UI)
        ui_file.open(QtCore.QFile.ReadOnly)
        self.ui = loader.load(ui_file, self)

        # Scans all window objects and if one is open with the same name as this tool then close it so we don't have two open.
        mainWindow.closeUI("Tool")

        # Create a thread
        thread = QtCore.QThread(self)
        # Create worker object
        self.worker = Worker()
        # Move worker object into thread (This creates an automatic queue if multiples of the same worker are called)
        self.worker.moveToThread(thread)

        # Connect buttons in the UI to trigger a method inside the worker which should run in a thread
        self.ui.first_btn.clicked.connect(self.worker.do_something)
        self.ui.second_btn.clicked.connect(self.worker.do_something_else)
        self.ui.third_btn.clicked.connect(self.worker.and_so_fourth)

        self.worker.valueChanged.connect(self.ui.progressBar.setValue)

        # Start the thread
        thread.start()

        # Show UI
        self.ui.show()


class Worker(QtCore.QObject):
    valueChanged = QtCore.Signal(int)

    @QtCore.Slot()
    def do_something(self):
        # Start long code here and update progress bar as needed in a still active UI.
        self.valueChanged.emit(0)
        print "doing something!"
        self.valueChanged.emit(100)

    @QtCore.Slot()
    def do_something_else(self):
        # Start long code here and update progress bar as needed in a still active UI.
        self.valueChanged.emit(0)
        print "doing something else!"
        self.valueChanged.emit(100)

    @QtCore.Slot()
    def and_so_fourth(self):
        # Start long code here and update progress bar as needed in a still active UI.
        self.valueChanged.emit(0)
        print "and so fourth, all in the new thread in a queue of which method was called first!"
        self.valueChanged.emit(100)

myTool = None

def launch():
    global myTool
    myTool = Tool()
© www.soinside.com 2019 - 2024. All rights reserved.