为啥我的 pyqt 信号错误会冻结 ui,直到调用另一个 python 函数
Posted
技术标签:
【中文标题】为啥我的 pyqt 信号错误会冻结 ui,直到调用另一个 python 函数【英文标题】:Why do my errors from pyqt signals freeze the ui until another python function gets called为什么我的 pyqt 信号错误会冻结 ui,直到调用另一个 python 函数 【发布时间】:2019-01-14 22:05:38 【问题描述】:在 Maya 2016 中一切正常。但是在 Maya 2017 中(在我完成所有 pyqt 转换之后),从 qt 信号调用的函数中发生的任何错误都不会立即显示。然后如果我在脚本编辑器中运行另一个代码,例如“print 0”,就会出现上一个函数的错误
要试一试,只需运行代码,然后单击“错误”按钮。
我在 Windows 和 Mac 上尝试过。还请朋友试穿 - 他也有同样的问题。同样,在 Maya 2016 上一切正常。该问题仅在 Maya 2017 中发生
from PySide2 import QtWidgets, QtGui, QtCore
from shiboken2 import wrapInstance
import maya.OpenMayaUI as mui
mainWin = None
def showUI():
global mainWin
if mainWin != None:
print "reloading UI..."
mainWin.close()
mainWin = myWindow()
mainWin.show()
def getMayaWindow():
ptr = mui.MQtUtil.mainWindow()
return wrapInstance(long(ptr), QtWidgets.QWidget)
class myWindow(QtWidgets.QDialog):
def __init__(self, parent=getMayaWindow()):
super(myWindow, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
def funcApply():
oooo # this should error!
self.layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.TopToBottom, self)
self.testButton = QtWidgets.QPushButton('error')
self.layout.addWidget(self.testButton)
self.testButton.clicked.connect(funcApply)
showUI()
【问题讨论】:
只是猜测;但可能是从 Qt 4 转移到 Qt 5 时引入的一个错误……您是否也在 2018 年看到它?刚在2018.5测试了一下,马上报错# NameError: global name 'oooo' is not defined
无法在 Linux 上的 Maya 2018 中复制该问题
我也相信这是从 Qt4 到 Qt5 的转变带来的一个错误 - 但让我感到困惑的是,我是唯一一个遇到这个问题的人。因为这个 UI 的代码比较简单。感谢您使用 maya2018 对其进行测试-也许我将不得不跳过 2017 年并转到 2018 年..
哇,2017 年在 Linux 上确认。如果我找到任何解决方案,我会报告。这是一个非常讨厌的错误,他们怎么能放过这个!这也是 Maya 2017 Update 2 的一个错误。
【参考方案1】:
就像我在 cmets 中所说,我可以在 2017 年和 2017 年更新 2 中复制您的错误,但在 2018 年工作得非常好。
幸运的是,有一个足够简单的解决方案,您只需将方法移出__init__
即可使其成为普通的实例方法。现在按预期执行此操作会出错。 (老实说,在__init__
中有一个嵌套函数有点奇怪,不管它是否有问题,我都会移动它)
有趣的是,静态方法也有同样的问题!如果你试图在课堂上给他们打电话,他们会挂掉。但是,如果你从类外部调用它,它可以正常工作,或者如果你用 try
except
包装它,它现在可以在从类内部调用时工作。
查看以下代码。我包括了3个案例,一个实例化的方法,一个静态的方法,一个用try
包裹的静态方法except
:
from PySide2 import QtWidgets, QtGui, QtCore
from shiboken2 import wrapInstance
import maya.OpenMayaUI as mui
mainWin = None
def showUI():
global mainWin
if mainWin != None:
print "reloading UI..."
mainWin.close()
mainWin = myWindow()
mainWin.show()
def getMayaWindow():
ptr = mui.MQtUtil.mainWindow()
return wrapInstance(long(ptr), QtWidgets.QWidget)
class myWindow(QtWidgets.QDialog):
def __init__(self, parent=getMayaWindow()):
super(myWindow, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
# Works.
self.testButton = QtWidgets.QPushButton('error')
self.testButton.clicked.connect(self.funcApply)
# Fails.
self.testButton2 = QtWidgets.QPushButton('error static method')
self.testButton2.clicked.connect(self.staticFuncApply)
# Works.
self.testButton3 = QtWidgets.QPushButton('error static method with try/except')
self.testButton3.clicked.connect(self.staticTryExceptFuncApply)
self.layout = QtWidgets.QBoxLayout(QtWidgets.QBoxLayout.TopToBottom, self)
self.layout.addWidget(self.testButton)
self.layout.addWidget(self.testButton2)
self.layout.addWidget(self.testButton3)
self.setLayout(self.layout) # Normally need to specify what layout this widget needs to use.
# Move this out and make it a normal instanced method.
# This will work as expected.
def funcApply(self):
oooo # this should error!
# Static methods still broken, but ok in Maya 2018.
@staticmethod
def staticFuncApply():
oooo
# Static methods wrapped with try except works.
@staticmethod
def staticTryExceptFuncApply():
try:
oooo
except Exception as e:
print e
showUI()
# myWindow.staticFuncApply() # Calling static method outside of class works ok.
所有这些都在 Maya 2018 中工作,但静态方法在 2017 年将失败。
希望您可以避免使用静态方法,因为将其全部包装在 try
except
中并不是一个实用的解决方案。您也可以尝试将您的 Maya 更新到 2017 更新 4 以查看它是否已修补。
希望这会有所帮助!
【讨论】:
是的,就是这样 - 感谢您发现它!转换我的所有代码会很棘手,因为在某些情况下,我会在 for 循环中按程序创建函数 - 但我相信我会找到一种方法。至于 try-except 语句,我也注意到他正确地捕捉到了它们。但是如果你在 except 语句中提出错误,你就会遇到同样的问题 也许对于简单的嵌套函数,您可以将它们替换为lambda
?嗯,很高兴你现在至少找到了一个出发点。或者说服你的雇主切换到 2018 年:P
不,lambda 也有同样的问题。但我会想办法的。只需要改变一些事情。
最终只是在按钮上创建了动态属性,然后创建了我自己的继承 QPushButton 的按钮类。并且,mouseReleaseEvent() 具有通常单击信号函数会执行的魔力。所以一切又好了。以上是关于为啥我的 pyqt 信号错误会冻结 ui,直到调用另一个 python 函数的主要内容,如果未能解决你的问题,请参考以下文章