获取wrapInstance的父级导致窗口中断

时间:2018-08-21 11:56:22

标签: python qt pyside2

我一直在使用this代码的修改版本来将Qt窗口包装在Maya自己的workspaceControl中。要获取小部件的外部水平以查询几何形状,大小,移动等,我实际上需要执行self.parent().parent().parent().parent().parent(),因为它包装在很多小部件中。

我一直在解决由该问题引起的一两个问题,但今天我遇到了更重要的事情,并决定确切地找出原因。

通过测试,我尽可能地缩小了代码的范围,并且发现它是在尝试获取shiboken2.wrapInstance的父级的时候。尝试创建该窗口之后,出现错误消息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)

如何在不引起问题的情况下获取wrap实例的父级?我认为这与过早地从内存中取消引用有关,但是我不确定如何解决该问题。

1 个答案:

答案 0 :(得分:0)

我发现一个修复程序有点脏,但到目前为止似乎可以可靠地工作。

因此,首先,我发现如果您创建上述parent_wrap的两个实例,并在创建第二个实例之前获得了父实例,则可以单独传递到窗口而不会引起问题。它可以一直工作到停靠/分离窗口之前,但是会删除旧的父级并提供新的父级,因此旧的指针不再有效。

似乎在初始化窗口之前提供此父项使我可以在不破坏代码的情况下使用self.parent().parent()....重新对其进行重新编写。

如果状态已更改(浮动/停靠),并且每当RuntimeError发生时,都需要对其进行更新,但是由于它不会对性能造成重大影响,为简单起见,我只是对其进行重新生成每次需要它时。

要覆盖某个功能(例如move),将使用以下方法:

def move(self, x, y):
    if self.dockable:
        return self._parent_override().move(x, y)
    return QtWidgets.QMainWindow.move(self, x, y)

这是解决问题的替代类:

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