Drag and Drop QLabels with PyQt5

橙三吉。 提交于 2020-01-23 01:39:06

问题


I'm trying to drag and drop a Qlabel on another Qlabel with PyQt5:

from PyQt5.QtWidgets import QApplication, QWidget, QToolTip, QPushButton, QMessageBox, QHBoxLayout, QVBoxLayout, QGridLayout,QFrame, QComboBox, QLabel, QLineEdit
from PyQt5.QtGui import QIcon, QFont, QPixmap, QImage
import sys


class my_label(QLabel):
    def __init__(self,title,parent):
        super().__init__(title,parent)
        self.setAcceptDrops(True)

    def dragEnterEvent(self,event):
        if event.mimeData().hasFormat("text/plain"):
            event.accept()
        else:
            event.ignore()
    def dropEvent(self,event):
        self.setText(event.mimeData().text())


class application(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):


        label = my_label("drop there",self)
        label.resize(100,100)
        label.move(190,65)

        label_to_drag = QLabel("drag this",self)
        #label_to_drag.setDragEnabled(True)    #doesn't work with QLabel        
        self.show()


    def closeEvent(self,event):
        message = QMessageBox.question(self,"Message","Quit ?",QMessageBox.Yes | QMessageBox.No,QMessageBox.No)

        if message == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

app = QApplication(sys.argv)
fenetre = application()
sys.exit(app.exec_())

I wanted to make my first label "draggable",by calling the setDragEnabled(True) method (as i was doing for QLineEdit),and drop it on the second label to change his text. Dropping text from another app is working fine,but I can't find how to drag the QLabel inside my own app... What did I miss ?

EDIT : modified the code to try to Drag&Drop Images :

class DraggableLabel(QLabel):
def __init__(self,parent,image):
    super(QLabel,self).__init__(parent)
    self.setPixmap(QPixmap(image))    
    self.show()
def mousePressEvent(self, event):
    if event.button() == Qt.LeftButton:
        self.drag_start_position = event.pos()

def mouseMoveEvent(self, event):
    if not (event.buttons() & Qt.LeftButton):
        return
    if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
        return
    drag = QDrag(self)
    mimedata = QMimeData()
    mimedata.setText(self.text())

    drag.setMimeData(mimedata)
    pixmap = QPixmap(self.size())
    painter = QPainter(pixmap)
    painter.drawPixmap(self.rect(), self.grab())
    painter.end()
    drag.setPixmap(pixmap)
    drag.setHotSpot(event.pos())
    drag.exec_(Qt.CopyAction | Qt.MoveAction)

   class my_label(QLabel):
    def __init__(self,title,parent):
        super().__init__(title,parent)
        self.setAcceptDrops(True)

    def dragEnterEvent(self,event):
        if event.mimeData().hasFormat("text/plain"):
            print("event accepted")
            event.accept()
        else:
            print("event rejected")
            event.ignore()
    def dropEvent(self,event):
        if event.mimeData().hasImage():
            self.setPixmap(QPixmap.fromImage(QImage(event.mimeData().imageData())))

class application(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):

        label_to_drag = DraggableLabel(self,"index.jpg")

        label = my_label("drop there",self)
        label.resize(100,100)
        label.move(190,65)



        self.show()

When I drop the DraggableLabel (displaying the image) on my_label,the event is accepted, but hasImage() always returns false...Is the way I set the image up wrong ?


回答1:


In the case of QLabel you must create everything from the beginning, for this you can follow the examples of the docs.

In the following example I have placed an example where one class only accepts the drop and the other the drag so that you can see each part and understand better.

import sys

from PyQt5.QtWidgets import QApplication, QLabel, QWidget
from PyQt5.QtGui import QDrag, QPixmap, QPainter, QCursor
from PyQt5.QtCore import QMimeData, Qt


class DraggableLabel(QLabel):
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_start_position = event.pos()

    def mouseMoveEvent(self, event):
        if not (event.buttons() & Qt.LeftButton):
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
            return
        drag = QDrag(self)
        mimedata = QMimeData()
        mimedata.setText(self.text())
        drag.setMimeData(mimedata)
        pixmap = QPixmap(self.size())
        painter = QPainter(pixmap)
        painter.drawPixmap(self.rect(), self.grab())
        painter.end()
        drag.setPixmap(pixmap)
        drag.setHotSpot(event.pos())
        drag.exec_(Qt.CopyAction | Qt.MoveAction)

class DropLabel(QLabel):
    def __init__(self, *args, **kwargs):
        QLabel.__init__(self, *args, **kwargs)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasText():
            event.acceptProposedAction()

    def dropEvent(self, event):
        pos = event.pos()
        text = event.mimeData().text()
        self.setText(text)
        event.acceptProposedAction()


class Widget(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        label = DropLabel("drop there",self)
        label.setGeometry(190, 65, 100,100)

        label_to_drag = DraggableLabel("drag this",self)  
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

Update:

Do not confuse the QDrag with the QMimeData, if you want to use imageData() you must set it with setImageData() as indicated by the docs:

class DraggableLabel(QLabel):
    def __init__(self,parent,image):
        super(QLabel,self).__init__(parent)
        self.setPixmap(QPixmap(image))    
        self.show()
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_start_position = event.pos()

    def mouseMoveEvent(self, event):
        if not (event.buttons() & Qt.LeftButton):
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
            return
        drag = QDrag(self)
        mimedata = QMimeData()
        mimedata.setText(self.text())
        mimedata.setImageData(self.pixmap().toImage())

        drag.setMimeData(mimedata)
        pixmap = QPixmap(self.size())
        painter = QPainter(pixmap)
        painter.drawPixmap(self.rect(), self.grab())
        painter.end()
        drag.setPixmap(pixmap)
        drag.setHotSpot(event.pos())
        drag.exec_(Qt.CopyAction | Qt.MoveAction)

class my_label(QLabel):
    def __init__(self,title,parent):
        super().__init__(title,parent)
        self.setAcceptDrops(True)

    def dragEnterEvent(self,event):
        if event.mimeData().hasImage():
            print("event accepted")
            event.accept()
        else:
            print("event rejected")
            event.ignore()
    def dropEvent(self,event):
        if event.mimeData().hasImage():
            self.setPixmap(QPixmap.fromImage(QImage(event.mimeData().imageData())))


来源:https://stackoverflow.com/questions/50232639/drag-and-drop-qlabels-with-pyqt5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!