Results 1 to 5 of 5

Thread: [PySide] QCloseEvent from one GUI getting passed to delegate of another GUI?

  1. #1
    if clause
    Join Date
    Sep 2011
    Location
    Austin, TX
    Posts
    122

    Default [PySide] QCloseEvent from one GUI getting passed to delegate of another GUI?



    We ran into a really strange bug at work. We have a GUI with a tree view and some delegates, and it works just fine. While that GUI was open, a user opened and closed another GUI. This second GUI had an unhandled exception in the close event. After that point, the first GUI started throwing all sorts of errors. It was complaining that the delegate paint function was receiving a QCloseEvent instead of a QPainter. The delegate is called once for every cell in the tree, so that is a lot of errors. The only way to make it stop was to restart Maya.

    I made a minimal test case. I discovered that the error happens only when I am using QTreeView. If I use QListView, there is no problem. Here is the code:
    Code:
    import shiboken
    
    from PySide import QtCore, QtGui
    from maya import OpenMayaUI
    
    #------------------------------------------------------------------------------
    def getMayaMainWindow():
        parentWindow = OpenMayaUI.MQtUtil.mainWindow()
        if parentWindow:
            return shiboken.wrapInstance(long(parentWindow), QtGui.QWidget)
    
    #------------------------------------------------------------------------------
    class ErrorGUI(QtGui.QMainWindow):
        def __init__(self, parent=getMayaMainWindow()):
            super(ErrorGUI, self).__init__(parent)
            
            self.setWindowTitle('Close event error')
            self.setObjectName('closeEventErrorWindow')
            
            self.centralWidget = QtGui.QWidget()
            self.setCentralWidget(self.centralWidget)
            
            self._foo = []
    
        def closeEvent(self, event):
            x = self._foo[0][-1]
    
    #------------------------------------------------------------------------------
    class SelectedItemDelegate(QtGui.QStyledItemDelegate):
        """ A delegate that ensures the text color of selected items matches what is
        specified in the model's ForegroundRole.
        
        Without this delegate, the text of selected items is always white, instead
        of the color specified in the model.
        
        """
        #----- Overridden functions ------------------------------------------------
        def paint(self, qPainter, option, qModelIndex):
            if (option.state & QtGui.QStyle.State_Selected):
                textColor = qModelIndex.data(QtCore.Qt.ForegroundRole)
                if textColor is not None:
                    brush = QtGui.QBrush(textColor)
                    option.palette.setBrush(QtGui.QPalette.HighlightedText, brush)
            super(SelectedItemDelegate, self).paint(qPainter, option, qModelIndex)
    
    #------------------------------------------------------------------------------
    class MyListModel(QtCore.QAbstractListModel):
        def __init__(self, parent=None):
            super(MyListModel, self).__init__(parent)
            
            self._data = []
            self._fgColors = []
        
        #----- Overridden functions -----------------------------------------------
        def data(self, index, role):
            if not index.isValid():
                return None
            
            if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
                return self._data[index.row()]
            
            elif role == QtCore.Qt.ForegroundRole:
                return self._fgColors[index.row()]
        
        #--------------------------------------------------------------------------
        def rowCount(self, parentIndex):
            return len(self._data)
        
        #----- Other functions ----------------------------------------------------
        def setModelData(self, stringList, foregroundColorList):
            if len(stringList) != len(foregroundColorList):
                print 'Arrays do not match in size'
                return
            self._data = stringList
            self._fgColors = foregroundColorList
            
    #------------------------------------------------------------------------------
    class DelegateGUI(QtGui.QMainWindow):
        def __init__(self, parent=getMayaMainWindow()):
            super(DelegateGUI, self).__init__(parent)
            
            self.setWindowTitle('GUI with delegate')
            self.setObjectName('testDelegateWindow')
            
            # # QListView version.  DOES NOT BREAK
            # self.listView = QtGui.QListView()
            # self.listModel = MyListModel()
            # self.fillListModel()
            # self.listView.setModel(self.listModel)
            # textColorDelegate = SelectedItemDelegate()
            # self.listView.setItemDelegate(textColorDelegate)
            # self.setCentralWidget(self.listView)
            
            # QTreeView version.  THIS BREAKS!
            self.treeView = QtGui.QTreeView()
            self.listModel = MyListModel()
            self.fillListModel()
            self.treeView.setModel(self.listModel)
            textColorDelegate = SelectedItemDelegate()
            self.treeView.setItemDelegate(textColorDelegate)
            self.setCentralWidget(self.treeView)
        
        def fillListModel(self):
            items = ['alpha', 'bravo', 'charlie', 'delta']
            color = QtGui.QColor(225, 130, 0)
            colors = [None, color, color, None]
            self.listModel.setModelData(items, colors)
    
    #------------------------------------------------------------------------------
    def openErrorWin():
        '''This ensures that only one instance of the UI is open at a time.'''
        global errorWin
        try: errorWin.close()
        except: pass
        errorWin = ErrorGUI()
        errorWin.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        errorWin.show()
        return errorWin
    
    #------------------------------------------------------------------------------
    def openDelegateWin():
        '''This ensures that only one instance of the UI is open at a time.'''
        global delegateWin
        try: delegateWin.close()
        except: pass
        delegateWin = DelegateGUI()
        delegateWin.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        delegateWin.show()
        return delegateWin
    Then in Maya, I run the following:
    Code:
    import closeEventError
    dWin = closeEventError.openDelegateWin()
    eWin = closeEventError.openErrorWin()
    1. At this point there are two windows open, and everything is fine.
    2. Close the window titled "Close event error".
    3. Put the focus back on the window titled "GUI with delegate".
    4. ERRORS!

  2. #2
    if clause
    Join Date
    Sep 2011
    Location
    Austin, TX
    Posts
    122

    Default

    The first error, from the close event of one GUI is as follows:
    Code:
    # Traceback (most recent call last):
    #   File "U:/maya/2016/scripts\closeEventError.py", line 26, in closeEvent
    #     x = self._foo[0][-1]
    # IndexError: list index out of range
    The following errors are from the delegate of the other GUI, one error per cell:
    Code:
    # Traceback (most recent call last):
    #   File "U:/maya/2016/scripts\closeEventError.py", line 44, in paint
    #     super(SelectedItemDelegate, self).paint(qPainter, option, qModelIndex)
    # TypeError: # 'PySide.QtGui.QStyledItemDelegate.paint' called with wrong argument types:
    #   PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QCloseEvent, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Supported signatures:
      PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QPainter, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Traceback (most recent call last):
    #   File "U:/maya/2016/scripts\closeEventError.py", line 44, in paint
    #     super(SelectedItemDelegate, self).paint(qPainter, option, qModelIndex)
    # TypeError: # 'PySide.QtGui.QStyledItemDelegate.paint' called with wrong argument types:
    #   PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QCloseEvent, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Supported signatures:
      PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QPainter, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Traceback (most recent call last):
    #   File "U:/maya/2016/scripts\closeEventError.py", line 44, in paint
    #     super(SelectedItemDelegate, self).paint(qPainter, option, qModelIndex)
    # TypeError: # 'PySide.QtGui.QStyledItemDelegate.paint' called with wrong argument types:
    #   PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QCloseEvent, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Supported signatures:
      PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QPainter, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Traceback (most recent call last):
    #   File "U:/maya/2016/scripts\closeEventError.py", line 44, in paint
    #     super(SelectedItemDelegate, self).paint(qPainter, option, qModelIndex)
    # TypeError: # 'PySide.QtGui.QStyledItemDelegate.paint' called with wrong argument types:
    #   PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QCloseEvent, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)
    # Supported signatures:
      PySide.QtGui.QStyledItemDelegate.paint(PySide.QtGui.QPainter, PySide.QtGui.QStyleOptionViewItem, PySide.QtCore.QModelIndex)

  3. #3
    if clause
    Join Date
    Sep 2011
    Location
    Austin, TX
    Posts
    122

    Default

    Okay, I found a way to make the errors stop, but it makes no sense. I made a dummy tree view class that does nothing but override the paint event. Even then, it just calls the superclass paint event. Essentially it is doing nothing, but using it makes the problem go away.
    Code:
    class CustomTreeView(QtGui.QTreeView):
        def paintEvent(self, qPaintEvent):
            super(CustomTreeView, self).paintEvent(qPaintEvent)
    Then, replace
    Code:
    self.treeView = QtGui.QTreeView()
    with
    Code:
    self.treeView = CustomTreeView()

  4. #4
    struct
    Join Date
    Mar 2011
    Location
    San Francisco
    Posts
    348

    Default

    I don't get the paint() error when using your code.

    Is your delegate being used in two places by chance? Are you importing the module with the delegate into other modules? Are you reloading python modules (I have fond that reloading modules with Qt code in it can cause issues)

  5. #5
    if clause
    Join Date
    Sep 2011
    Location
    Austin, TX
    Posts
    122

    Default

    I guess I should have mentioned I am using Maya 2016 with Extension 1 (not Extension 2) and Service Pack 6.

    In my real code, the delegate is being used in two places. But for the test case, the code shown above is the complete code. And I'm not really reloading modules because once the error happens, I have to restart Maya to get it to stop.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •