写在前面:
在本篇教程中,将实现一个基于 PyQt5 的自定义列表组件,这个组件支持拖拽排序、点击按钮上下移动、以及点击删除的功能。
实现效果:
undefined
为什么不用Qt自带的QListWidget
和 QListView
?
QListWidget
支持拖拽,但仅限于默认的文字图标样式的item,不支持item上显示自定义widget(拖拽之后会出现空白)QListWidget
直接拖动列表项的文字或图标,而我们希望通过截图方式,让拖拽过程中显示小部件的实际样式。首先,请确保你的环境中安装了 PyQt5,可以使用以下命令安装:
pythonpip install PyQt5
实现一个自定义列表组件,要求如下:
首先我们创建以下几个类:
CustomWidget
: 定义列表项样式,包括标签和按钮。FileInfo
: 存储每个列表项的信息。FileItem
: 继承 QStandardItem
,保存自定义数据。FileListView
: 主列表视图类,实现拖拽、排序和按钮操作的核心逻辑。CustomWidget
CustomWidget
负责定义每个列表项的外观,包括:
↑
按钮(上移)、↓
按钮(下移)、以及 删除
按钮。代码实现如下:
pythonclass CustomWidget(QWidget):
"""自定义列表项,带有标签和删除按钮"""
def __init__(self, text):
super(CustomWidget, self).__init__()
self.is_selected = False
self.label = QLabel(os.path.basename(text))
self.btn_up = QPushButton("↑")
self.btn_down = QPushButton("↓")
self.btn_delete = QPushButton("删除")
# 创建布局
layout = QHBoxLayout()
layout.addWidget(self.label)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
layout.addItem(spacerItem)
layout.addWidget(self.btn_up)
layout.addWidget(self.btn_down)
layout.addWidget(self.btn_delete)
layout.setContentsMargins(0, 0, 10, 0)
self.setLayout(layout)
self.setStyleSheet("QWidget,QLabel{background: rgb(238,244,249);}")
通过 QLabel
显示标签信息,QPushButton
添加操作按钮,并设置 QHBoxLayout
布局,使标签和按钮水平排列。
FileInfo
和 FileItem
FileInfo
类保存每个列表项的具体信息,如文件名、路径和排序所需的页码。
pythonclass FileInfo:
def __init__(self, file, index):
self.filename = os.path.basename(file)
self.filepath = file
self.index = index
self.selected = True
FileItem
继承自 QStandardItem
,在每项中存储 FileInfo
数据。
pythonclass FileItem(QStandardItem):
def __init__(self, fileinfo):
super(FileItem, self).__init__()
self.setData(fileinfo, Qt.UserRole) # 存储自定义文本数据
FileListView
FileListView
是组件的核心部分,定义了以下功能:
mousePressEvent
和 startDrag
实现拖拽效果。add_item
添加列表项,通过 remove_item
删除项。在 FileListView
的 startDrag
方法中,生成自定义小部件的截图作为拖拽图像,并设置拖拽热点,确保拖拽开始时图像与鼠标对齐。
pythondef startDrag(self, supportedActions):
index = self.currentIndex()
if index.isValid():
item_widget = self.indexWidget(index)
if item_widget:
pixmap = item_widget.grab()
drag = QDrag(self)
drag.setPixmap(pixmap)
drag.setHotSpot(self.start_drag_pos - item_widget.pos())
drag.exec_(supportedActions)
按钮 ↑
和 ↓
实现上下移动功能。通过获取目标行号和源行号,进行插入和删除操作。
pythondef move_item_up(self, item):
row = item.row()
if row > 0:
new_item = FileItem(item.data(Qt.UserRole).copy())
self.model.removeRow(item.row())
self.model.insertRow(row - 1, new_item)
self.set_item_widget(new_item)
当点击删除按钮时,调用 remove_item
方法,将指定项从模型中移除。
pythondef remove_item(self, item):
self.model.removeRow(item.row())
在 main
函数中,我们创建一个 FileListView
实例,并添加几个示例项,展示组件的完整效果。
pythonif __name__ == '__main__':
app = QApplication(sys.argv)
view = FileListView()
for i in range(5):
view.add_item(f'Item {i + 1}', i)
view.show()
sys.exit(app.exec_())
运行后,窗口会显示一个列表,每个项可以通过拖拽排序、点击按钮上移或下移,或者删除,方便用户进行自由操作。
通过本教程,我们实现了一个功能丰富的 PyQt5 自定义列表组件,主要包括以下要点:
QStandardItem
和 QStandardItemModel
维护列表数据。本组件适用于需要动态排序的项目管理类应用,如文件列表、任务管理等。
本文作者:司小远
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!