简体   繁体   中英

How to make drag and drop from QListWidget to QLabel in PyQt

In the application I'm writing using PyQt I want to do drag and drop functionality with dragging items from QListWidget to QLabel (setting text on QLabel basing on the text from item from QListWidget). In order to do that I made new class inheriting form QLabel to add dragEnterEvent and dropEvent. The code of my Label:

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

  def dragEnterEvent(self, event):
    print('drag')
    print(event.mimeData().text())
    if event.mimeData().hasText():
        event.accept()
    else:
        event.ignore()

  def dropEvent(self, event):
    print('drop')
    self.setText(event.mimeData().text())

The problem is that when I drag item from QListWidget it has no text, so my code is not working. As I understand it's because when I'm dragging item from QListWidget I'm not dragging text but the whole widget (because, as I understand, the items in list are not strings but QListWidgetItem). According to different questions I've found here I suppose I should make a new class also for dragged item but at this point I don't know if I should do it for QListWidget or QListWidgetItem. Or maybe I should do this in completely different way?

When dragging from a Qt item view, you're not "dragging the widget", but a serialized representation of the selection.

That representation is stored in the application/x-qabstractitemmodeldatalist mime format, and in order to read its contents you have to use a QDataStream.

The stored data is, for each item:

  • item row
  • item column
  • for each entry in the range of the data size (how many role/value pairs):
    • role
    • value

This data must always be read with the above structure, you cannot "skip" any part, otherwise the data won't be properly read, since it's stored in a "serialized" stream.

So, you can implement that in the following way:

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

    def dragEnterEvent(self, event):
        mime = event.mimeData()
        if (mime.hasText() or 
            mime.hasFormat('application/x-qabstractitemmodeldatalist')):
                event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        mime = event.mimeData()
        if mime.hasText():
            self.setText(mime.text())
        elif mime.hasFormat('application/x-qabstractitemmodeldatalist'):
            textList = []
            stream = QDataStream(mime.data('application/x-qabstractitemmodeldatalist'))
            while not stream.atEnd():
                # we're not using row and columns, but we *must* read them
                row = stream.readInt()
                col = stream.readInt()
                for dataSize in range(stream.readInt()):
                    role, value = stream.readInt(), stream.readQVariant()
                    if role == Qt.DisplayRole:
                        textList.append(value)
            self.setText(', '.join(textList))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM