Search code examples
python-3.xdrag-and-droppysideqtreeviewqimage

Drag and drop in QTreeView fails with items that hold a QImage


I have a list of items in a QTreeView. Each item holds a QImage object. If I try to drag and drop the item, the program freezes. But when I comment out the line objMod._Image = QImage(flags = Qt.AutoColor), the program runs fine.

How can I drag and drop the items with the QImage object? The QImage holds an image which is rendered. The rendering process takes a while, so it would be nice to keep the QImage object.

import sys
import os

from PySide.QtCore    import *
from PySide.QtGui     import *
from PySide.QtUiTools import *

from PIL import Image, ImageCms, ImageQt

class ObjModel:
    def __init__(self):
        self._Image = None

class DragMoveTest(QMainWindow):
    def __init__(self):
        super(DragMoveTest,self).__init__()
        self.initGUI()
        self.show()

    def initGUI(self):
        self.treeView = QTreeView()
        modelTreeView = QStandardItemModel()
        self.treeView.setModel(modelTreeView)
        for i in range(0, 4):
            objMod = ObjModel()
            objMod._Image = None
            objMod._Image = QImage(flags = Qt.AutoColor)

            item = QStandardItem('Test: %s' % str(i))
            item.setData(objMod, Qt.UserRole + 1)
            modelTreeView.invisibleRootItem().appendRow(item)

        self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
        self.setCentralWidget(self.treeView)

def main(args):
    app = QApplication(sys.argv)
    qt_main_wnd = DragMoveTest()
    ret = app.exec_()
    sys.exit(ret)

if __name__ == "__main__":
    main(sys.argv)

Solution

  • I come up with a different solution. It is easier to have a object that holds a io.BytesIO. Your store the ImageData into the bytesIO variable. Upon on your image library you can open the image from the bytesIO variable. In the demo the class ObjModel can handle QImage and Image from Pillow/PIL. If you use the set methods the image object will be converted into a bytesIO. In short here a working example:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import sys
    import os
    import io
    
    from PySide.QtCore                          import *
    from PySide.QtGui                           import *
    from PySide.QtUiTools                       import *
    
    from PIL                import Image, ImageCms, ImageQt
    
    ########################################################################
    class ObjModel:
        """"""
        #----------------------------------------------------------------------
        def __init__(self):
            """Constructor"""
            self._ImageByteIO = None
    
    
        #----------------------------------------------------------------------
        def getObjByte(self):
            """"""
            return self._ImageByteIO
    
    
        #----------------------------------------------------------------------
        def getQImage(self):
            """"""
            try:
                self._ImageByteIO.seek(0)
                qImg = QImage.fromData(self._ImageByteIO.getvalue())
                return qImg
            except:
                return None
    
    
        #----------------------------------------------------------------------
        def getPILImage(self):
            """"""
            try:
                self._ImageByteIO.seek(0)
                img = Image.open(tBytesIO)
                return img
            except:
                return None
    
    
        #----------------------------------------------------------------------
        def setObjByte(self, fileName):
            """"""
            try:
                tBytesIO = io.BytesIO()
                f = open (fileName, 'rb')
                tBytesIO.write(f.read())
                f.close()
                self._ImageByteIO = tBytesIO
            except:
                self._ImageByteIO = None
    
    
        #----------------------------------------------------------------------
        def setQImage(self, qImg):
            """"""
            try:
                tBytesIO = io.BytesIO()
                qByteArray = QByteArray()
                qBuf = QBuffer(qByteArray)
                qBuf.open(QIODevice.ReadWrite)
                qImg.save(qBuf, 'PNG')
                tBytesIO = io.BytesIO()
                tBytesIO.write(qByteArray.data())
                self._ImageByteIO = tBytesIO
            except:
                self._ImageByteIO = None
    
    
        #----------------------------------------------------------------------
        def setPILImage(self, pImg):
            """"""
            tBytesIO = io.BytesIO()
            pImg.save(tBytesIO, 'png')
            self._ImageByteIO = tBytesIO
    
    
    
    #----------------------------------------------------------------------
    class DragMoveTest(QMainWindow):
        def __init__(self):
            """"""
            super(DragMoveTest,self).__init__()
            self.initGUI()
            self.show()
    
    
        #----------------------------------------------------------------------
        def initGUI(self):
            """"""
            self.treeView = QTreeView()
            modelTreeView = QStandardItemModel()
            self.treeView.setModel(modelTreeView)
            for i in range(0, 4):
                objMod = ObjModel()
                objMod.setQImage(QImage(flags = Qt.AutoColor))
                item = QStandardItem('Test: %s' % str(i))
                item.setData(objMod, Qt.UserRole + 1)
                modelTreeView.invisibleRootItem().appendRow(item)
    
            self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
            self.setCentralWidget(self.treeView)
    
    
    #----------------------------------------------------------------------
    def main(args):
        app = QApplication(sys.argv)
        qt_main_wnd = DragMoveTest()
        ret = app.exec_()
        sys.exit(ret)
    
    
    #----------------------------------------------------------------------
    if __name__ == "__main__":
        main(sys.argv)