2024-11-12
PyQt
00

目录

PyQt5 自定义可拖拽列表组件:实现动态排序、上下移动与删除功能
环境准备
项目需求分析
代码详解
1. 项目结构
2. 自定义列表项 CustomWidget
3. 数据结构 FileInfo 和 FileItem
4. 列表视图 FileListView
关键功能实现
5. 初始化组件
效果预览
总结
完整代码

PyQt5 自定义可拖拽列表组件:实现动态排序、上下移动与删除功能

写在前面:

在本篇教程中,将实现一个基于 PyQt5 的自定义列表组件,这个组件支持拖拽排序、点击按钮上下移动、以及点击删除的功能。

实现效果:

预览.gif

undefined

为什么不用Qt自带的QListWidgetQListView

  1. QListWidget 支持拖拽,但仅限于默认的文字图标样式的item,不支持item上显示自定义widget(拖拽之后会出现空白)
  2. 自定义拖拽图像:默认的 QListWidget 直接拖动列表项的文字或图标,而我们希望通过截图方式,让拖拽过程中显示小部件的实际样式。
  3. 控制拖拽行为:在自定义组件中,可以细粒度地控制拖拽行为,甚至动态调整拖拽图像、拖拽位置、以及拖拽结果的处理逻辑。例如,我们可以在拖拽时调整列表项的大小,或者设置复杂的拖拽区域判断。

环境准备

首先,请确保你的环境中安装了 PyQt5,可以使用以下命令安装:

python
pip install PyQt5

项目需求分析

实现一个自定义列表组件,要求如下:

  1. 每个列表项由一个标签和三个操作按钮组成(上移、下移、删除)。
  2. 支持拖拽排序,使用户可以自由地重新排列列表项的顺序。
  3. 能够通过按钮快速将项上下移动或删除。

代码详解

1. 项目结构

首先我们创建以下几个类:

  • CustomWidget: 定义列表项样式,包括标签和按钮。
  • FileInfo: 存储每个列表项的信息。
  • FileItem: 继承 QStandardItem,保存自定义数据。
  • FileListView: 主列表视图类,实现拖拽、排序和按钮操作的核心逻辑。

2. 自定义列表项 CustomWidget

CustomWidget 负责定义每个列表项的外观,包括:

  • 标签显示项的名称。
  • 按钮(上移)、 按钮(下移)、以及 删除 按钮。
  • 鼠标悬停效果。

代码实现如下:

python
class 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 布局,使标签和按钮水平排列。

3. 数据结构 FileInfoFileItem

FileInfo 类保存每个列表项的具体信息,如文件名、路径和排序所需的页码。

python
class FileInfo: def __init__(self, file, index): self.filename = os.path.basename(file) self.filepath = file self.index = index self.selected = True

FileItem 继承自 QStandardItem,在每项中存储 FileInfo 数据。

python
class FileItem(QStandardItem): def __init__(self, fileinfo): super(FileItem, self).__init__() self.setData(fileinfo, Qt.UserRole) # 存储自定义文本数据

4. 列表视图 FileListView

FileListView 是组件的核心部分,定义了以下功能:

  • 拖拽排序:通过 mousePressEventstartDrag 实现拖拽效果。
  • 列表操作:调用 add_item 添加列表项,通过 remove_item 删除项。
关键功能实现
  • 拖拽

FileListViewstartDrag 方法中,生成自定义小部件的截图作为拖拽图像,并设置拖拽热点,确保拖拽开始时图像与鼠标对齐。

python
def 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)
  • 上下移动

按钮 实现上下移动功能。通过获取目标行号和源行号,进行插入和删除操作。

python
def 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 方法,将指定项从模型中移除。

python
def remove_item(self, item): self.model.removeRow(item.row())

5. 初始化组件

main 函数中,我们创建一个 FileListView 实例,并添加几个示例项,展示组件的完整效果。

python
if __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 自定义列表组件,主要包括以下要点:

  1. 自定义小部件,实现项目内容的布局和交互。
  2. 使用 QStandardItemQStandardItemModel 维护列表数据。
  3. 通过自定义拖拽和按钮操作,实现上下移动、删除和排序功能。

本组件适用于需要动态排序的项目管理类应用,如文件列表、任务管理等。

完整代码

https://github.com/LC044/pyqt_component_library

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:司小远

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!