代码之家  ›  专栏  ›  技术社区  ›  Peter

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

  •  0
  • Peter  · 技术社区  · 7 年前

    我一直在使用的是 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 回复  |  直到 7 年前
        1
  •  0
  •   Peter    7 年前

    我找到了一个有点脏的修复方法,但到目前为止似乎工作可靠。

    所以首先,我发现如果你创建了上面的两个实例 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)
    

    这是解决这个问题的override类:

    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
    
    推荐文章