Search code examples
pythonpyqt5overlaydragdrop

How do I create an item overlay under the mouse during a drag and dropbetween two QGraphicscene?


I'm trying to create two Qgraphicscene where I can drag an item from the left scene and drop it on the rigth scene. I succeed in making the drad and drop, but I don't understand how I can create an overlay of the svg item during the drag. What I would like to have is at least display the overlay when the mouse is on the rigth scene.

So far I have this code:

import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtSvg import QGraphicsSvgItem


class myQGraphicsScene(QGraphicsScene):
    def __init__(self,parent=None):
        super(myQGraphicsScene, self).__init__()
        self.parent = parent

    def dragEnterEvent(self, event):
        event.accept()

    def dragMoveEvent(self, event):
        event.accept()

    def dragLeaveEvent(self, event):
        event.accept()

    def dropEvent(self, event):
        text = event.mimeData().text()
        item = self.parent.getSelecedItemfromname(text)
        br = item.boundingRect()
        s = item.scale()
        w = int(br.width() * s)/2
        h = int(br.height() * s)/2
        pos = event.scenePos()
        item.setPos(pos - QPointF(w,h))
        self.addItem(item)
        event.accept()


class myQGraphicsScene2(QGraphicsScene):
    def __init__(self, parent=None):
        super(myQGraphicsScene2, self).__init__()
        self.parent = parent

    def dragEnterEvent(self, event):
        event.setDropAction(Qt.MoveAction)
        event.accept()

    def startDrag(self, event):
        item = self.itemAt(event.scenePos(), QTransform())
        print(item)
        if item is None:
            return

        # selected = self.model().data(item, Qt.DisplayRole)
        name = self.parent.getSelecedNamefromitem(item)
        mimeData = QMimeData()
        mimeData.setText(name )

        drag = QDrag(self)
        drag.setMimeData(mimeData)

        result = drag.exec(Qt.MoveAction)
        if result:  # == Qt.MoveAction:
            pass

    def mouseMoveEvent(self, event):
        self.startDrag(event)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setMouseTracking(True)
        self.names = ['fjJ.svg','fjJ.svg','fjJ.svg']
        self. items = []
        shift = 200
        for i, n in enumerate(self.names):
            item = QGraphicsSvgItem(n)
            # item.setFlag(QGraphicsItem.ItemIsMovable)
            item.setFlag(not QGraphicsItem.ItemIsMovable)
            # item.setFlag(QGraphicsItem.ItemIsSelectable)
            item.setScale(0.25)
            item.setPos(0, i * shift)
            self.items.append(item)

        self.scene = myQGraphicsScene2(self)
        for i in self.items:
            self.scene.addItem(i)

        self.scene2 = myQGraphicsScene(self)

        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.view2 = QGraphicsView()
        self.view2.setMouseTracking(True)
        self.view2.setScene(self.scene2)

        HBOX = QHBoxLayout()
        HBOX.addWidget(self.view)
        HBOX.addWidget(self.view2)
        widget = QWidget()
        widget.setLayout(HBOX)
        self.setCentralWidget(widget)
        self.setFixedSize(QSize(800,600))

    def getSelecedItem(self):
        item = -1
        for k, i in enumerate(self.items):
            if i.isSelected():
                item = k
        if not item == -1:
            new_item = QGraphicsSvgItem(self.names[item])
            new_item.setFlag(QGraphicsItem.ItemIsMovable)
            new_item.setScale(0.25)
            return new_item
        else:
            return None
    def getSelecedNamefromitem(self,itemfrom):
        item = -1
        for k, i in enumerate(self.items):
            if i == itemfrom:
                item = k
        if not item == -1:
            return self.names[k]
        else:
            return None

    def getSelecedItemfromname(self,name):
        item = -1
        for k, n  in enumerate(self.names):
            if n == name:
                item = k
        if not item == -1:
            new_item = QGraphicsSvgItem(self.names[item])
            new_item.setFlag(QGraphicsItem.ItemIsMovable)
            new_item.setScale(0.25)
            return new_item
        else:
            return None

    def getSelecedName(self):
        item = -1
        for k, i in enumerate(self.items):
            if i.isSelected():
                item = k
        if not item == -1:
            return self.names[item]
        else:
            return None
 

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec()

Here the .svg https://svgshare.com/i/fjJ.svg


Solution

  • I found a solution myself. It is not a perfect one but it works. You can put other solutions if they are more optimized.

    import sys
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtSvg import QGraphicsSvgItem
    
    
    class myQGraphicsScene(QGraphicsScene):
        def __init__(self,parent=None):
            super(myQGraphicsScene, self).__init__()
            self.parent = parent
    
        def dragEnterEvent(self, event):
            print('dragEnterEvent')
            event.accept()
    
        def dragMoveEvent(self, event):
            print('dragMoveEvent')
            event.accept()
    
        def dragLeaveEvent(self, event):
            print('dragLeaveEvent')
            event.accept()
    
        def dropEvent(self, event):
            text = event.mimeData().text()
            item = self.parent.getSelecedItemfromname(text)
            br = item.boundingRect()
            s = item.scale()
            w = int(br.width() * s)/2
            h = int(br.height() * s)/2
            pos = event.scenePos()
            item.setPos(pos - QPointF(w,h))
            self.addItem(item)
            event.accept()
    
    
    class myQGraphicsScene2(QGraphicsScene):
        def __init__(self, parent=None):
            super(myQGraphicsScene2, self).__init__()
            self.parent = parent
    
        def dragEnterEvent(self, event):
            event.setDropAction(Qt.MoveAction)
            event.accept()
    
        def startDrag(self, event):
            item = self.itemAt(event.scenePos(), QTransform())
            print(item)
            if item is None:
                return
    
            # # selected = self.model().data(item, Qt.DisplayRole)
            name = self.parent.getSelecedNamefromitem(item)
            # mimeData = QMimeData()
            # mimeData.setText(name )
            #
            # drag = QDrag(self)
            # drag.setMimeData(mimeData)
            #
            # result = drag.exec(Qt.MoveAction)
            # if result:  # == Qt.MoveAction:
            #     pass
    
            pixmap = self.parent.getSelecedimagefromname(name)
            drag = QDrag(self)
            mimedata = QMimeData()
            mimedata.setText(name)
            mimedata.setImageData(pixmap.toImage())
    
            drag.setMimeData(mimedata)
            painter = QPainter(pixmap)
            painter.drawPixmap(pixmap.rect(), pixmap)
            painter.end()
            drag.setPixmap(pixmap)
            # drag.setHotSpot(QPoint(event.scenePos().x(),event.scenePos().y()))
            drag.setHotSpot(QPoint((pixmap.size()/2).width(),(pixmap.size()/2).height()))
            drag.exec_(Qt.CopyAction | Qt.MoveAction)
    
        def mouseMoveEvent(self, event):
            self.startDrag(event)
    
    
    class MainWindow(QMainWindow):
    
        def __init__(self):
            super().__init__()
            self.setMouseTracking(True)
            self.names = ['function.svg','multiply.svg','minus.svg']
            self.items = []
            shift = 200
            for i, n in enumerate(self.names):
                item = QGraphicsSvgItem(n)
                # item.setFlag(QGraphicsItem.ItemIsMovable)
                item.setFlag(not QGraphicsItem.ItemIsMovable)
                # item.setFlag(QGraphicsItem.ItemIsSelectable)
                item.setScale(0.25)
                item.setPos(0, i * shift)
                self.items.append(item)
    
            self.scene = myQGraphicsScene2(self)
            for i in self.items:
                self.scene.addItem(i)
    
            self.scene2 = myQGraphicsScene(self)
    
            self.view = QGraphicsView()
            self.view.setScene(self.scene)
            self.view2 = QGraphicsView()
            self.view2.setMouseTracking(True)
            self.view2.setScene(self.scene2)
            self.view2.setFixedSize(QSize(400,600))
            self.view2.setSceneRect(0,0,400,600)
            # self.view2.setTransformationAnchor(QGraphicsView.NoAnchor)
            # self.view2.setResizeAnchor(QGraphicsView.NoAnchor)
    
            HBOX = QHBoxLayout()
            HBOX.addWidget(self.view)
            HBOX.addWidget(self.view2)
            widget = QWidget()
            widget.setLayout(HBOX)
            self.setCentralWidget(widget)
            # self.setFixedSize(QSize(800,600))
    
        def getSelecedItem(self):
            item = -1
            for k, i in enumerate(self.items):
                if i.isSelected():
                    item = k
            if not item == -1:
                new_item = QGraphicsSvgItem(self.names[item])
                new_item.setFlag(QGraphicsItem.ItemIsMovable)
                new_item.setScale(0.25)
                return new_item
            else:
                return None
        def getSelecedNamefromitem(self,itemfrom):
            item = -1
            for k, i in enumerate(self.items):
                if i == itemfrom:
                    item = k
            if not item == -1:
                return self.names[item]
            else:
                return None
    
        def getSelecedItemfromname(self,name):
            item = -1
            for k, n  in enumerate(self.names):
                if n == name:
                    item = k
            if not item == -1:
                new_item = QGraphicsSvgItem(self.names[item])
                new_item.setFlag(QGraphicsItem.ItemIsMovable)
                new_item.setScale(0.25)
                return new_item
            else:
                return None
    
        def getSelecedimagefromname(self,name):
            item = -1
            for k, n  in enumerate(self.names):
                if n == name:
                    item = k
            if not item == -1:
                new_item =  QIcon(self.names[item]).pixmap(self.items[item].boundingRect().size().toSize() * self.items[item].scale())
                return new_item
            else:
                return None
    
        def getSelecedName(self):
            item = -1
            for k, i in enumerate(self.items):
                if i.isSelected():
                    item = k
            if not item == -1:
                return self.names[item]
            else:
                return None
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        w = MainWindow()
        w.show()
        app.exec()