本文分成兩部分,第一部分通過python3+PyQt5實現自定義數據的拖放操作。第二部分則對第一部分的程序進行修改,增加拖放操作時,菜單提示是否移動或拷貝,還有可以通過ctrl鍵盤來設置移動過程中拷貝源而非會將源刪除。
自定義數據MIME數據類型QMimeData,MIME是一種用于處理具有多個組成部分的自定義數據的標準化格式。MIME數據由一個數據類型和一個子類型構成–例如,text/plain,text/html,image/png,要處理自定義MIME數據,就必須要選用一種自定義數據類型和一種子類型,然后將數據封裝到QMimeData對象中。本例子中,我們創建端為application/x-icon-and-text類型的新MIME數據。
注:
dragEnterEvent這是一個拖拽事件的函數,我們把文件拖拽進程序界面打開,之前必須setAcceptDrops(true)了以后拖拽,但是只設置acceptDrops還不夠,還需要在dragEnterEvent事件中對拖入的對象進行篩選,判斷mimeData的類型是否是你能處理的,如果是,則調用event.acceptProposedAction()放行。拖放結束后會產生dropEvent事件,在那里進行最后的放置操作。總之這是拖拽事件函數的一個篩選事件并放置的函數。
第一部分:
#!/usr/bin/env python3import osimport sysfrom PyQt5.QtCore import (QByteArray, QDataStream, QIODevice, QMimeData, QPoint, QSize, Qt)from PyQt5.QtWidgets import (QApplication, QDialog,QGridLayout, QLineEdit, QListWidget,QListWidgetItem, QWidget)from PyQt5.QtGui import QIcon,QColor,QPainter,QFontMetricsF,QDragclass DropLineEdit(QLineEdit): def __init__(self, parent=None): super(DropLineEdit, self).__init__(parent) self.setAcceptDrops(True) 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.CopyAction) 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 >> text text=stream.readQString() self.setText(text) event.setDropAction(Qt.CopyAction) event.accept() else: event.ignore()class DnDListWidget(QListWidget): def __init__(self, parent=None): super(DnDListWidget, self).__init__(parent) self.setAcceptDrops(True) self.setDragEnabled(True) 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 = "" icon = QIcon() #stream >> text >> icon text=stream.readQString() 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 << item.text() << icon stream.writeQString(item.text()) 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))class DnDWidget(QWidget): def __init__(self, text, icon=QIcon(), parent=None): super(DnDWidget, self).__init__(parent) self.setAcceptDrops(True) self.text = text self.icon = icon 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): 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.CopyAction) 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) self.text = "" self.icon = QIcon() #stream >> self.text >> self.icon self.text=stream.readQString() stream>>self.icon event.setDropAction(Qt.CopyAction) event.accept() self.updateGeometry() self.update() else: event.ignore() def mouseMoveEvent(self, event): self.startDrag() QWidget.mouseMoveEvent(self, event) def startDrag(self): icon = self.icon if icon.isNull(): return data = QByteArray() stream = QDataStream(data, QIODevice.WriteOnly) #stream << self.text << icon stream.writeQString(self.text) 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)class Form(QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) dndListWidget = DnDListWidget() path = os.path.dirname(__file__) for image in sorted(os.listdir(os.path.join(path, "images"))): if image.endswith(".png"): item = QListWidgetItem(image.split(".")[0].capitalize()) item.setIcon(QIcon(os.path.join(path, "images/{0}".format(image)))) dndListWidget.addItem(item) dndIconListWidget = DnDListWidget() dndIconListWidget.setViewMode(QListWidget.IconMode) dndWidget = DnDWidget("Drag to me!") dropLineEdit = DropLineEdit() layout = QGridLayout() layout.addWidget(dndListWidget, 0, 0) layout.addWidget(dndIconListWidget, 0, 1) layout.addWidget(dndWidget, 1, 0) layout.addWidget(dropLineEdit, 1, 1) self.setLayout(layout) self.setWindowTitle("Custom Drag and Drop")if __name__ == "__main__": app = QApplication(sys.argv) form = Form() form.show() app.exec_()
新聞熱點
疑難解答