Qt.py icon indicating copy to clipboard operation
Qt.py copied to clipboard

nuke 9.0 Internal C++ object already deleted

Open wblion opened this issue 8 years ago • 13 comments

i use nuke 9.0 qtpy 1.0.0.b6

have error nuke 9.0 Internal C++ object already deleted can not show ui

but same code in nuke 10.0 is work。

wblion avatar Jan 15 '18 05:01 wblion

Thanks @wblion, can you provide a short reproducible example and confirm whether the issue occurs without Qt.py, such as with PySide or PyQt4?

mottosso avatar Jan 15 '18 07:01 mottosso

i think the error in

use qt.py have error

def loadUiWidget(self,uifilename, parent=None):
    ui = QtCompat.load_ui(uifilename)
    return ui

use pyside no qt.py is ok

def loadUiWidget(self,uifilename, parent=None):
        loader = QtUiTools.QUiLoader()
        uifile = QFile(uifilename)
        uifile.open(QFile.ReadOnly)
        ui = loader.load(uifile, parent)
        #ui = QtCompat.load_ui(uifilename)
        return ui

all in nuke 9.0

uifile:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>378</width>
    <height>406</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>审核上传工具</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_4">
   <item>
    <widget class="QWidget" name="widget_4" native="true">
     <layout class="QVBoxLayout" name="verticalLayout_6">
      <item>
       <widget class="QWidget" name="widget_5" native="true">
        <layout class="QVBoxLayout" name="verticalLayout_5">
         <item>
          <layout class="QHBoxLayout" name="horizontalLayout_3">
           <item>
            <widget class="QRadioButton" name="up_radioButton">
             <property name="text">
              <string>上传</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QRadioButton" name="down_radioButton">
             <property name="text">
              <string>下载</string>
             </property>
            </widget>
           </item>
          </layout>
         </item>
         <item>
          <widget class="QWidget" name="shot_sq_filter_widget" native="true">
           <layout class="QVBoxLayout" name="verticalLayout_7">
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_5">
              <item>
               <widget class="QLabel" name="label_4">
                <property name="text">
                 <string>下载地址</string>
                </property>
               </widget>
              </item>
              <item>
               <widget class="QLineEdit" name="tmp_lineEdit"/>
              </item>
              <item>
               <widget class="QPushButton" name="load_pushButton">
                <property name="text">
                 <string>file</string>
                </property>
               </widget>
              </item>
             </layout>
            </item>
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_6">
              <item>
               <widget class="QLabel" name="label_6">
                <property name="text">
                 <string>场次镜头</string>
                </property>
               </widget>
              </item>
              <item>
               <widget class="QLineEdit" name="shot_sq_filter_lineEdit"/>
              </item>
             </layout>
            </item>
           </layout>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_4">
        <item>
         <widget class="QLabel" name="label_5">
          <property name="text">
           <string>项目</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QComboBox" name="project_name_comboBox"/>
        </item>
        <item>
         <spacer name="horizontalSpacer_3">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QWidget" name="widget" native="true">
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
         <widget class="QLabel" name="label">
          <property name="text">
           <string>环节</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QComboBox" name="ple_step_comboBox"/>
        </item>
        <item>
         <widget class="QLabel" name="label_2">
          <property name="text">
           <string>任务</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QComboBox" name="task_comboBox">
          <property name="minimumSize">
           <size>
            <width>100</width>
            <height>0</height>
           </size>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QWidget" name="widget_2" native="true">
     <layout class="QVBoxLayout" name="verticalLayout_2">
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_2">
        <item>
         <widget class="QLabel" name="label_3">
          <property name="text">
           <string>预览文件夹路径</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="floder_lineEdit"/>
        </item>
        <item>
         <widget class="QPushButton" name="file_pushButton">
          <property name="text">
           <string>..</string>
          </property>
         </widget>
        </item>
       </layout>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QWidget" name="widget_3" native="true">
     <layout class="QVBoxLayout" name="verticalLayout_3">
      <item>
       <widget class="QTextEdit" name="info_textEdit"/>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="upload_pushButton">
     <property name="text">
      <string>开始上传</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

wblion avatar Jan 15 '18 07:01 wblion

Hey @wblion I've seen this happen when a e.g. a window which takes a long time to populate is prematurely closed by the user. I'm guessing that Nuke is closing something or removing something mid-population. I doubt that this has anything to do with Qt.py.

fredrikaverpil avatar Jan 15 '18 07:01 fredrikaverpil

now i use pyside instead of Qt.py in nuke9.0, it is nuke bug?

wblion avatar Jan 15 '18 07:01 wblion

@wblion I haven't tested your code, but we use QtCompat.loadUi(uifile) here without issues in Nuke 9, 10 and 11.

Can you post the full Python Traceback?

fredrikaverpil avatar Jan 15 '18 07:01 fredrikaverpil

@wblion I realized I was wrong. I see this issue (or at least a very similar issue) on our end as well with Nuke 9 when running Qt.py 1.1.0 and it's a complete showstopper for us in Nuke 9.

I reported a while back on that UI loading broke in Nuke 9 (PySide 1.0.9) for us when going from Qt.py 1.0.0b3 to 1.0.0b4: #208 It was because of this PySide bug: https://bugreports.qt.io/browse/PYSIDE-10 That particular issue was addressed with Qt.py 1.0.0b6. However, we never upgraded from 1.0.0b3 (which worked for us) and stayed on that until just recently, where we updated straight to 1.1.0.

I've now realized that we are seing the runtime error in Qt.py 1.0.0b6 as well as 1.1.0. If downgrading to 1.0.0b3, the error is gone and the UI loads fine for us.

I'm going to investigate to see what could be wrong and if there's something we can do to fix this -- or if it's time to move on from Nuke 9... (or rather PySide 1.0.9)

fredrikaverpil avatar Feb 14 '18 06:02 fredrikaverpil

@mottosso @MHendricks @dgovil There's an issue with Qt.py's _loadUi, like @wblion reported above.

If you're on Nuke 9.0v9 (or actually, PySide 1.0.9), you cannot load an UI like this without risking getting early deletion of widgets because of https://bugreports.qt.io/browse/PYSIDE-10:

my_ui = QtCompat.loadUi(ui_file)

We Qt.py maintainers noticed this in 1.0.0b4 (#208) and thought we fixed this in 1.0.0b6. However, depending on how you load UIs and later manipulate them, you can still hit this issue. I think we used a minimal and reproducible code example to prove we fixed this, but in more advanced cases, this issue is definitively being hit in Qt.py 1.0.0b6 as well as in Qt.py 1.1.0 when using Nuke 9.0v9 (PySide 1.0.9).

Workaround 1

Without modifying Qt.py 1.1.0, the only way I can reliably load UIs without getting runtime errors when the UI is later modified in Nuke 9.0v9 (PySide 1.0.9) is doing it like this:

my_ui = QtWidgets.QMainWindow  # or QWidget
QtCompat.loadUi(ui_file, my_ui)

EDIT: This however causes the runtime error in Maya 2018.2 instead (PySide2).

Workaround 2

Another workaround is to change the following (Qt.py 1.1.0) in _pyside():

    if hasattr(Qt, "_QtUiTools"):
        Qt.QtCompat.loadUi = _loadUi

into...

    if hasattr(Qt, "_QtUiTools") and Qt.__binding_version__ <= '1.0.9':
        # https://bugreports.qt.io/browse/PYSIDE-10
        # https://github.com/mottosso/Qt.py/issues/208
        # https://github.com/mottosso/Qt.py/issues/266
        Qt.QtCompat.loadUi = lambda fname: \
            Qt._QtUiTools.QUiLoader().load(fname)
    else:
        if hasattr(Qt, "_QtUiTools"):
            Qt.QtCompat.loadUi = _loadUi

This would use the PySide-native and built-in QUiLoader.load. However, this would make it impossible to use feed this method a base instance argument.


I'm writing code which is supporting PySide and PySide2 and I got hit by this issue when updating to Qt.py 1.1.0. ~~My current workaround is the "Workaround 1", outlined above.~~ EDIT: Hmm nope, with that workaround I am getting the runtime error in Maya 2018.2... (PySide2).

@wblion could you please see if you also can work yourself around this issue by defining the base instance argument to QtCompat.loadUi ("Workaround 1")?

@mottosso @dgovil Judging from the Github blame, it looks like you guys made a joint effort to write the existing _loadUi implementation. Do you have any thoughts on all of this?

fredrikaverpil avatar Feb 14 '18 08:02 fredrikaverpil

We seem to be encountering this issue on Nuke 10, PySide 1.2.2 and Qt.py 1.1.0, but only under certain circumstances. Many widgets work fine, while some only work in the context of their constructor and throw this error when referred to later.

I haven't quite been able to pin down exactly what triggers it yet, but will post back when I do. Just wondered if this has been encountered by anyone else?

thimic avatar Jul 10 '18 18:07 thimic

@thimic I did run into this issue. What I found was my parent was being collected and causing the rest of controls to go with it. What seems to be working so far, is simply just storing my parent in a variable, then using that variable when I initialize MainWindow.

I was only getting this issue on objects that were relying on parents.

so something like this:

self.parent = parent
QtWidgets.QMainWindow.__init__(self ,self.parent)
QtCompat.loadUi(os.path.join(path_to_ui, 'nuke_file_open_gui.ui'), self)

Kind of new to using all this, so what I suggested might not make a lot of sense, but it did clear up the issue so far.

Acrlixe avatar Jul 13 '18 16:07 Acrlixe

@Acrlixe Are you using a different version of PyQt/PySide than what comes bundled with Nuke? We've seen the same behavior regardless of using Qt.py inside of Maya where if we didn't store the pointer in a variable, we'd start seeing the parent application not keep it in memory properly.

Sometimes this would manifest itself in the UI going out of scope and dying, but other times it would mean subtle things like signals not firing.

dgovil avatar Jul 13 '18 16:07 dgovil

Thanks @Acrlixe, this is working for us. @dgovil, we are seeing the issue with the built in PySide2 on Nuke 11.1v4.

thimic avatar Aug 05 '18 21:08 thimic

I wonder if there are different issues going on here depending on the PySide version (1.0.9 or above) and ui loading method. When using QtCompat.loadUi, You can load an uifile either into a baseinstance (method 1) or have the loaded ui returned as a widget (method 2):

# method 1
ui = QtCompat.loadUi(uifile)  # ...where ui become the baseinstance

# method 2
QtCompat.loadUi(uifile, self)  # ...where self is the baseinstance

I've noticed that PySide 1.0.9 + method 1 results in early deletion. I've managed to solve this by loading the ui like so:

# Loads without early deletion in PySide 1.0.9, 1.2.2 and above (PySide2-5.6, PySide2-5.11) with Qt.py 1.1.0
ui = QtWidgets.QWidget()
QtCompat.loadUi(uifile, ui)

I have also found that I can tweak Qt.py 1.1.0 to store the references of the baseinstance and the widgets of the uifile. This will prevent the early deletion of the ui in PySide 1.0.9. The caveat here is that the list can never be emptied and will therefore accumulate objects. Which is far from ideal.

I believe we should document the workaround mentioned by @Acrlixe and perhaps my workaround above, which I feel would likely cover both ui loading methods and PySide versions.

One thing puzzles me though, which is how you guys are experiencing this issue in newer PySide versions. This indicates that there's some issue with Qt.py's loading mechanism. Is it possible that PySide 1.0.9 in fact triggers its known early deletion bug but when in newer PySide versions the nature of the Qt.py loading mechanism triggers the early deletion?

EDIT: Nuke 9.x is using PySide 1.0.9

fredrikaverpil avatar Aug 23 '18 08:08 fredrikaverpil

Hello!

I have found the same issue with Maya 2018 as you have mentioned above. I have found a workaround that could make the trick if someone needs to use it!

I realized that the problem comes with the overriden method "createWidgets". What I did, I've override the "load" method except to load the UI and set all the widgets as class attributes (that is one of the things that "createWidgets" method does), iterating through all the widgets within the UI, and everything seems to be fine.

I know that it is not the smartest way to "fix" this, but it could work if someone needs to use it!

The only problem with this method, is that the UI is loaded without a "main" layout, but it something that we can "solve" easily with something like this:

    widget = loader.load(uifile)
    l = QtWidgets.QHBoxLayout()
    l.addWidget(widget)
    baseinstance.setLayout(l)

Just for info, I'm using Maya 2018.3 and latest version of Qt.py (1.2.0b2)

Hope it helps!

asierralozano avatar Sep 03 '18 10:09 asierralozano