当你需要向用户展示一个列表,或让用户在列表中进行选择时,QListWidget
是一个非常有用的控件。你还可以在列表项之间拖放数据或重新排序。本文将详细讲解如何在PyQt5
中使用QListWidget
实现拖放功能。
设置拖放属性
要启用QListWidget
中的拖放功能,需要设置dragEnabled
和 dropEnabled
为True。其中,dragEnabled
控制列表项的拖动前的初始操作,而dropEnabled
控制列表项如何放置或接受数据。
list_widget = QtWidgets.QListWidget()
list_widget.setDragEnabled(True)
list_widget.setDropEnabled(True)
拖放事件处理
当用户在QListWidget
控件上拖动鼠标时,会发出一系列的QDrag
事件和QDrop
事件。要处理这些事件,我们需要重写QListWidget
的dragEnterEvent
和dropEvent
方法。
# 重写dragEnterEvent
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
# 重写dropEvent
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
urls = []
for url in event.mimeData().urls():
urls.append(str(url.toLocalFile()))
self.addItems(urls)
else:
event.ignore()
在这个事件处理代码中,我们首先判断拖放事件中的数据是否是URL,如果是,我们接受事件数据并使用addItems()
方法将数据添加到列表中。如果不是URL,则忽略事件数据。
完整示例
import sys
from PyQt5 import QtCore, QtWidgets
class ListWidget(QtWidgets.QListWidget):
def __init__(self, parent):
super().__init__(parent)
self.setDragEnabled(True)
self.setDropEnabled(True)
# 重写dragEnterEvent
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
# 重写dropEvent
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
urls = []
for url in event.mimeData().urls():
urls.append(str(url.toLocalFile()))
self.addItems(urls)
else:
event.ignore()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
list_widget = ListWidget(window)
window.setCentralWidget(list_widget)
window.show()
sys.exit(app.exec_())
这个示例展示了如何使用ListWidget
实现拖放文件到列表中。当用户在ListWidget
上拖拽一个或多个文件时,这些文件的路径被添加到列表中。
示例二:重新排序
除了接受拖放数据,QListWidget
还支持在列表项中进行拖放排序。下面的示例代码实现了在同一个ListWidget
控件中,对数据进行拖动排序的功能。
import sys
from PyQt5 import QtCore, QtWidgets
class ListWidget(QtWidgets.QListWidget):
def __init__(self, parent):
super().__init__(parent)
self.setDragEnabled(True)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'):
event.accept()
def dropEvent(self, event):
if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'):
data = event.mimeData()
bstream = data.retrieveData('application/x-qabstractitemmodeldatalist', QtCore.QVariant.Bytearray)[0]
istream = QtCore.QDataStream(bstream)
row, col, _ = (QtCore.QModelIndex() / row / col).fromDataStream(istream)
target = self.itemAt(event.pos())
if not target:
target = self.item(self.count() - 1)
self.takeItem(row)
self.insertItem(self.row(target), self.decode(bstream))
event.acceptProposedAction()
def startDrag(self, dropActions):
mimeData = self.model().mimeData(self.selectedIndexes())
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.start(QtCore.Qt.MoveAction)
def decode(self, byte):
stream = QtCore.QDataStream(byte)
data = {}
while not stream.atEnd():
row = stream.readInt()
dicts = {}
keys = []
while True:
key = stream.readQString()
if key == 'end':
break
keys.append(key)
for key in keys:
value = stream.readQString()
dicts[key] = value
data[row] = dicts
return list(data.values())[0]['text']
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
list_widget = ListWidget(window)
list_widget.addItems(['Item {}'.format(i) for i in range(10)])
window.setCentralWidget(list_widget)
window.show()
sys.exit(app.exec_())
这个示例展示了如何在一个QListWidget
控件中对列表项进行拖动重新排序。当用户在列表项上拖动鼠标时,它们会自动重新排序。