我有一个 UI,我想在 Maya 内部使用线程。这样做的原因是这样我可以运行 Maya.cmds,而无需挂起/冻结 UI,同时使用进度条等更新 UI。
我已经阅读了 StackOverflow 中的一些示例,但我的代码每次运行时都会崩溃。我遵循的例子是here https://stackoverflow.com/questions/56629553/proper-pyside-qthread-use-in-maya-to-avoid-hard-crash and here https://stackoverflow.com/questions/37687463/single-worker-thread-for-all-tasks-or-multiple-specific-workers/37688544#37688544
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 cmd,而在更新 UI 进度条时不会使 Maya 完全崩溃。
对此的任何见解都会令人惊奇!
据我所知,它有以下错误:
thread
是一个局部变量,当构造函数执行完成时被删除,导致执行的内容在主线程中完成,这是不希望的,解决方案是延长生命周期,为此有几种解决方案:1)制作类属性,2)将父级传递给由父级管理的生命周期。在这种情况下,请使用第二种解决方案。
您不应该从另一个线程修改 GUI,如果您已经修改了progressBar
从另一个线程,在 Qt 中你必须使用信号。
您必须在另一个线程中执行的方法中使用 @Slot 装饰器。
您表明您要修改myTool
但你还没有声明它,所以global myTool
不会通过使工作myTool
要删除的局部变量。解决方案是声明myTool
:myTool = 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()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)