获取 wrapInstance 的父级会导致 window 中断
Getting parent of wrapInstance causes window to break
我一直在使用 this 代码的修改版本将 Qt window 包装在 Maya 自己的 workspaceControl
中。为了让小部件的外部级别查询几何、大小、移动等,我实际上需要做 self.parent().parent().parent().parent().parent()
,因为它包含在相当多的小部件中。
我一直在解决由此引起的一两个问题,但今天我遇到了一些更重要的问题,并决定找出确切的原因。
通过测试,我尽可能地缩小了代码范围,我发现它是在尝试获取 shiboken2.wrapInstance
的父级时使用的。之后尝试创建 window 时出现错误 RuntimeError: Internal C++ object (PySide2.QtWidgets.QWidget) already deleted.
.
import maya.OpenMayaUI as omUI
import pymel.core as pm
import shiboken2
from PySide2 import QtWidgets
win_id = 'test'
#Delete existing window
if pm.workspaceControl(win_id, exists=True):
pm.deleteUI(win_id)
#Create window and setup wrapper
pm.workspaceControl(win_id)
c_pointer = omUI.MQtUtil.findControl(win_id)
parent_wrap = shiboken2.wrapInstance(int(c_pointer), QtWidgets.QWidget)
print parent_wrap.parent()
#Create actual window
#This will error if parent_wrap.parent() was called
win = QtWidgets.QMainWindow(parent_object)
如何在不引起问题的情况下获取包装实例的父级?我认为这与过早地从内存中取消引用有关,但我不确定如何修复它。
我找到了一个修复程序,它有点脏,但到目前为止似乎工作可靠。
所以首先我发现如果您创建上述 parent_wrap
的两个实例,并在创建第二个实例之前获取父实例,则可以单独传递到 window 而不会导致问题。它一直工作到 window 为 docked/detached 为止,但是这会删除旧的父级并提供新的父级,因此旧指针不再有效。
似乎在初始化 window 之前提供这个父级允许我在不破坏代码的情况下用 self.parent().parent()....
重新生成它。
如果状态发生变化 (floating/docked),并且每当 RuntimeError
发生时,它都需要更新,但由于它不会对性能造成巨大影响,为简单起见,我'我只是在每次需要时重新生成它。
要覆盖一个函数,例如 move
,这就是如何使用它:
def move(self, x, y):
if self.dockable:
return self._parent_override().move(x, y)
return QtWidgets.QMainWindow.move(self, x, y)
这是解决问题的覆盖 class:
def _parent_override(self, create=True):
#Determine if it's a new window, we need to get the C++ pointer again
if not hasattr(self, '__temp_parent'):
base = qt_get_window(self.ID)
else:
base = self.parent()
#Get the correct parent level
if pm.workspaceControl(self.ID, query=True, floating=True):
parent = base.parent().parent().parent().parent()
else:
parent = base.parent().parent()
#Even though this attribute is never used,
#PySide2 is dumb and deletes the parent if it's not set
self.__temp_parent = parent
return parent
我一直在使用 this 代码的修改版本将 Qt window 包装在 Maya 自己的 workspaceControl
中。为了让小部件的外部级别查询几何、大小、移动等,我实际上需要做 self.parent().parent().parent().parent().parent()
,因为它包含在相当多的小部件中。
我一直在解决由此引起的一两个问题,但今天我遇到了一些更重要的问题,并决定找出确切的原因。
通过测试,我尽可能地缩小了代码范围,我发现它是在尝试获取 shiboken2.wrapInstance
的父级时使用的。之后尝试创建 window 时出现错误 RuntimeError: Internal C++ object (PySide2.QtWidgets.QWidget) already deleted.
.
import maya.OpenMayaUI as omUI
import pymel.core as pm
import shiboken2
from PySide2 import QtWidgets
win_id = 'test'
#Delete existing window
if pm.workspaceControl(win_id, exists=True):
pm.deleteUI(win_id)
#Create window and setup wrapper
pm.workspaceControl(win_id)
c_pointer = omUI.MQtUtil.findControl(win_id)
parent_wrap = shiboken2.wrapInstance(int(c_pointer), QtWidgets.QWidget)
print parent_wrap.parent()
#Create actual window
#This will error if parent_wrap.parent() was called
win = QtWidgets.QMainWindow(parent_object)
如何在不引起问题的情况下获取包装实例的父级?我认为这与过早地从内存中取消引用有关,但我不确定如何修复它。
我找到了一个修复程序,它有点脏,但到目前为止似乎工作可靠。
所以首先我发现如果您创建上述 parent_wrap
的两个实例,并在创建第二个实例之前获取父实例,则可以单独传递到 window 而不会导致问题。它一直工作到 window 为 docked/detached 为止,但是这会删除旧的父级并提供新的父级,因此旧指针不再有效。
似乎在初始化 window 之前提供这个父级允许我在不破坏代码的情况下用 self.parent().parent()....
重新生成它。
如果状态发生变化 (floating/docked),并且每当 RuntimeError
发生时,它都需要更新,但由于它不会对性能造成巨大影响,为简单起见,我'我只是在每次需要时重新生成它。
要覆盖一个函数,例如 move
,这就是如何使用它:
def move(self, x, y):
if self.dockable:
return self._parent_override().move(x, y)
return QtWidgets.QMainWindow.move(self, x, y)
这是解决问题的覆盖 class:
def _parent_override(self, create=True):
#Determine if it's a new window, we need to get the C++ pointer again
if not hasattr(self, '__temp_parent'):
base = qt_get_window(self.ID)
else:
base = self.parent()
#Get the correct parent level
if pm.workspaceControl(self.ID, query=True, floating=True):
parent = base.parent().parent().parent().parent()
else:
parent = base.parent().parent()
#Even though this attribute is never used,
#PySide2 is dumb and deletes the parent if it's not set
self.__temp_parent = parent
return parent