pyqt 5カスタムドラッグ&ドロップ機能の実装説明

12764 ワード

サンプルは依然として『Rapid GUI Programming with Python and Qt』から来ている.中国語版240ページはドラッグアンドドロップのサポートについて重要な説明がありますが、少し言葉がはっきりしないので、コード部分と結びつけてもう一度自分に説明します.本には次のように書かれています.
setAcceptDrops()メソッドはQWidgetから継承されていますが、setDragEnabled()はそうではありませんので、デフォルトでは一部のウィンドウコンポーネントでのみ使用できます.ドロップ操作をサポートできるカスタムウィンドウコンポーネントを作成する場合は、前述の例のようにsetAcceptDrops(True)を簡単に呼び出し、dragEnterEvent()、dragMoveEvent、dropEvent()を再実装するだけでよい.このカスタムウィンドウがドラッグをサポートし、ウィンドウがQWidgetから継承されているか、setDragEnabled()のないQWidgetサブクラスから継承されている場合は、コンポーネントにdragをサポートする2つのことをする必要があります.一つは、Qdragオブジェクトを作成できるようにstartDrag()メソッドを提供することであり、もう一つは、startDrag()メソッドを適切な時間に呼び出すことができることを確保することである.startDrag()の呼び出しを確保する最も簡単な方法はmouseMoveEventの再実現......コードを振り返って、上記の説をどのように実行するかです.
class DropLineEdit(QLineEdit):
    """QLineEdit   QWidget,        step   '  '"""

    def __init__(self, parent=None):
        super(DropLineEdit, self).__init__(parent)
        self.setAcceptDrops(True) #step1 True
        self.setToolTip("DropLineEdit")


    def dragEnterEvent(self, event): #step2 dragEnterEvent:accept
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            event.accept()
        else:
            event.ignore()


    def dragMoveEvent(self, event): #step3 dragMoveEvent:Copy or Move
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()


    def dropEvent(self, event): #step4 dropEvent:get data
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            data = event.mimeData().data("application/x-icon-and-text")
            stream = QDataStream(data, QIODevice.ReadOnly)
            text = stream.readQString()
            self.setText(text)
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

2つ目の例は、祖先に徳があり、dragを支持している.
class DnDListWidget(QListWidget):
    """QListWidget    ,       QAbstractItemView,  setDragEnabled(),
             True,      startDrag()     Drag  """
    def __init__(self, parent=None):
        super(DnDListWidget, self).__init__(parent)
        self.setAcceptDrops(True)
        self.setDragEnabled(True)
        self.setToolTip("DnDListWidget")


    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            event.accept()
        else:
            event.ignore()


    def dragMoveEvent(self, event):
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            event.ignore()


    def dropEvent(self, event):
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            data = event.mimeData().data("application/x-icon-and-text")
            stream = QDataStream(data, QIODevice.ReadOnly)
            text = stream.readQString()
            # text=""
            # stream>>text
            icon = QIcon()
            stream >> icon
            item = QListWidgetItem(text, self)
            item.setIcon(icon)
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            event.ignore()



    def startDrag(self, dropActions):
        item = self.currentItem()
        icon = item.icon()
        data = QByteArray()
        stream = QDataStream(data, QIODevice.WriteOnly)
        stream.writeQString(item.text())
        # stream<
        stream << icon
        mimeData = QMimeData()
        mimeData.setData("application/x-icon-and-text", data)
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        pixmap = icon.pixmap(24, 24)
        drag.setHotSpot(QPoint(12, 12))
        drag.setPixmap(pixmap)
        if drag.exec(Qt.MoveAction) == Qt.MoveAction:
            self.takeItem(self.row(item))

3つ目の例は自己奮闘型の鳳凰男です
class DnDWidget(QWidget):
    """       Qwidget,       Drag,      startDrag()         ,    mouseMoveEvent"""
    def __init__(self, text, icon=QIcon(), parent=None):
        super(DnDWidget, self).__init__(parent)
        self.setAcceptDrops(True) #drop step1
        #self.setDragEnabled(True),     ,   'DnDWidget' object has no attribute 'setDragEnabled'
        self.text = text
        self.icon = icon
        self.setToolTip("DnDWidget")


    def minimumSizeHint(self):
        fm = QFontMetricsF(self.font())
        if self.icon.isNull():
            return QSize(fm.width(self.text), fm.height() * 1.5)
        return QSize(34 + fm.width(self.text), max(34, fm.height() * 1.5))


    def paintEvent(self, event):
        height = QFontMetricsF(self.font()).height()
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.TextAntialiasing)
        painter.fillRect(self.rect(), QColor(Qt.yellow).lighter())
        if self.icon.isNull():
            painter.drawText(10, height, self.text)
        else:
            pixmap = self.icon.pixmap(24, 24)
            painter.drawPixmap(0, 5, pixmap)
            painter.drawText(34, height, self.text + " (Drag to or from me!)")


    def dragEnterEvent(self, event): #drops step2
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            event.accept()
        else:
            event.ignore()


    def dragMoveEvent(self, event):#drop step3
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()


    def dropEvent(self, event): #drop step4 over
        if event.mimeData().hasFormat("application/x-icon-and-text"):
            data = event.mimeData().data("application/x-icon-and-text")
            stream = QDataStream(data, QIODevice.ReadOnly)
            self.text=""
            self.text = stream.readQString()
            self.icon = QIcon()
            stream >> self.icon
            event.setDropAction(Qt.CopyAction)
            event.accept()
            self.updateGeometry()
            self.update()
        else:
            event.ignore()


    def mouseMoveEvent(self, event): 
        self.startDrag() #drag step 1
        QWidget.mouseMoveEvent(self, event)


    def startDrag(self): #drag step 2
        icon = self.icon
        if icon.isNull():
            return
        data = QByteArray()
        stream = QDataStream(data, QIODevice.WriteOnly)
        stream.writeQString(self.text)
        # stream<
        stream << icon
        mimeData = QMimeData()
        mimeData.setData("application/x-icon-and-text", data)
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        pixmap = icon.pixmap(24, 24)
        drag.setHotSpot(QPoint(12, 12))
        drag.setPixmap(pixmap)
        drag.exec(Qt.CopyAction)