python pyside2 list widget(QListWidget) 作者:马育民 • 2025-09-18 18:58 • 阅读:10000 # 介绍 `QListWidget` 是 PySide2 中用于展示列表项的便捷控件,它是一种**自包含的列表组件**(内部集成了模型和视图),适合快速实现简单的列表功能。相比 `QListView`(需要手动关联模型),`QListWidget` 更简单易用,适合展示文本、图标等基础内容。 `QListWidget` 是简化版的列表控件,适合快速实现基础列表功能(如添加、删除、选择项),无需关注模型细节。如果需要更复杂的定制(如自定义项样式、复杂数据结构),则推荐使用 `QListView` 配合自定义模型。 ### 核心特点 - 自带数据模型,无需手动创建 `QStandardItemModel` - 支持添加 `QListWidgetItem` 类型的列表项 - 内置常用功能(如添加、删除、排序、多选选等) - 适合快速开发简单列表(如文件列表、选项列表等) ### 基本用法示例 以下是 `QListWidget` 的常用操作(添加项、删除项、获取选中项等): ``` import sys from PySide2.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QListWidgetItem, QPushButton, QLineEdit, QLabel, QMessageBox) from PySide2.QtCore import Qt from PySide2.QtGui import QIcon class ListWidgetDemo(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle("QListWidget 示例") self.setGeometry(300, 300, 500, 400) # 1. 创建 QListWidget 控件 self.list_widget = QListWidget() # 设置列表属性 self.list_widget.setSelectionMode(QListWidget.ExtendedSelection) # 支持多选 self.list_widget.setAlternatingRowColors(True) # 交替行颜色 self.list_widget.setSortingEnabled(True) # 启用排序(点击表头可排序) # 2. 添加示例项 self.init_items() # 3. 控制按钮区域 # 添加项输入框 add_layout = QHBoxLayout() self.item_input = QLineEdit() self.item_input.setPlaceholderText("输入要添加的项...") add_btn = QPushButton("添加项") add_btn.clicked.connect(self.add_item) add_layout.addWidget(self.item_input) add_layout.addWidget(add_btn) # 操作按钮 btn_layout = QHBoxLayout() del_btn = QPushButton("删除选中项") del_btn.clicked.connect(self.delete_selected) clear_btn = QPushButton("清空列表") clear_btn.clicked.connect(self.list_widget.clear) show_btn = QPushButton("显示选中项") show_btn.clicked.connect(self.show_selected) btn_layout.addWidget(del_btn) btn_layout.addWidget(clear_btn) btn_layout.addWidget(show_btn) # 4. 组装布局 main_layout = QVBoxLayout() main_layout.addWidget(QLabel("列表内容:")) main_layout.addWidget(self.list_widget) main_layout.addLayout(add_layout) main_layout.addLayout(btn_layout) self.setLayout(main_layout) self.show() def init_items(self): """初始化列表项(支持文本、图标、隐藏数据)""" # 示例1:纯文本项 QListWidgetItem("项目 1", self.list_widget) QListWidgetItem("项目 2", self.list_widget) # 示例2:带图标项(实际使用时替换为真实图标路径) icon_item = QListWidgetItem("带图标项", self.list_widget) # icon_item.setIcon(QIcon("path/to/icon.png")) # 设置图标 # 示例3:带隐藏数据的项(使用 setData 存储) hidden_data_item = QListWidgetItem("带隐藏数据", self.list_widget) hidden_data_item.setData(Qt.UserRole + 1, {"id": 1001, "desc": "这是隐藏数据"}) def add_item(self): """添加新项到列表""" text = self.item_input.text().strip() if text: # 添加新项到列表末尾 QListWidgetItem(text, self.list_widget) self.item_input.clear() else: QMessageBox.warning(self, "警告", "请输入内容!") def delete_selected(self): """删除选中的项""" # 获取所有选中的项 selected_items = self.list_widget.selectedItems() if not selected_items: QMessageBox.information(self, "提示", "请先选中项!") return # 从列表中移除选中项 for item in selected_items: row = self.list_widget.row(item) # 获取项的行索引 self.list_widget.takeItem(row) # 移除项(不销毁对象) def show_selected(self): """显示选中项的信息(包括隐藏数据)""" selected_items = self.list_widget.selectedItems() if not selected_items: QMessageBox.information(self, "提示", "请先选中项!") return info = "" for i, item in enumerate(selected_items, 1): # 获取显示文本 text = item.text() # 获取隐藏数据(通过自定义角色) hidden_data = item.data(Qt.UserRole + 1) info += f"选中项 {i}:{text}\n" if hidden_data: info += f" 隐藏数据:{hidden_data}\n" QMessageBox.information(self, "选中项信息", info) if __name__ == '__main__': app = QApplication(sys.argv) window = ListWidgetDemo() sys.exit(app.exec_()) ``` ### 关键用法解析 #### 1. 基本操作 - **创建列表**:直接实例化 `QListWidget` 即可,无需单独创建模型。 - **添加项**:使用 `QListWidgetItem(text, list_widget)` 创建项并添加到列表,或通过 `list_widget.addItem(item)` 手动添加。 - **删除项**:通过 `takeItem(row)` 移除指定行的项(`row` 可通过 `row(item)` 获取)。 - **清空列表**:调用 `clear()` 方法快速清空所有项。 #### 2. 选择模式 通过 `setSelectionMode()` 设置选择行为: - `QListWidget.SingleSelection`:单选(默认) - `QListWidget.ExtendedSelection`:按住 `Ctrl` 或 `Shift` 多选 - `QListWidget.MultiSelection`:直接点击多选 - `QListWidget.NoSelection`:禁止选择 #### 3. 存储隐藏数据 与 `QListView` 类似,`QListWidgetItem` 支持通过 `setData()` 存储不显示的数据: ```python item = QListWidgetItem("显示文本", self.list_widget) # 用自定义角色存储隐藏数据(如ID、字典等) item.setData(Qt.UserRole + 1, {"id": 1001, "status": "active"}) # 获取隐藏数据 hidden_data = item.data(Qt.UserRole + 1) ``` # 事件 在 PySide2 中,`QListWidget` 的事件用法主要围绕两类核心场景:**1. 利用其内置信号绑定槽函数(推荐,简单高效)**;**2. 重写事件处理方法(适用于深度定制交互逻辑)**。前者基于信号-槽机制,无需关注底层事件分发;后者需直接处理鼠标、键盘等原始事件,灵活性更高。 ### 一、核心:信号-槽机制(推荐优先使用) `QListWidget` 提供了大量封装好的**信号**,对应列表项的选中、点击、双击、删除等常见交互,直接绑定槽函数即可实现功能,无需手动解析事件。 #### 1. 常用信号及说明 | 信号名 | 触发时机 | 关键参数说明 | |---------------------------------|-------------------------------------------|---------------------------------------| | `itemClicked(QListWidgetItem *)`| 列表项被鼠标点击时 | 被点击的 `QListWidgetItem` 对象 | | `itemDoubleClicked(QListWidgetItem *)` | 列表项被双击时 | 被双击的 `QListWidgetItem` 对象 | | `currentItemChanged(QListWidgetItem *, QListWidgetItem *)` | 当前选中项变化时 | 新选中项、上一个选中项(均为对象) | | `itemSelectionChanged()` | 选中项集合变化时(如多选时勾选/取消勾选) | 无参数,需通过 `selectedItems()` 获取选中项 | | `itemPressed(QListWidgetItem *)`| 列表项被鼠标按下时(比 `itemClicked` 早) | 被按下的 `QListWidgetItem` 对象 | | `itemDeleted(QListWidgetItem *)`| 列表项被删除时 | 被删除的 `QListWidgetItem` 对象 | #### 2. 信号-槽完整示例 ```python from PySide2.QtWidgets import (QApplication, QMainWindow, QListWidget, QListWidgetItem, QLabel, QVBoxLayout, QWidget) import sys class ListWidgetSignalDemo(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle("QListWidget 信号-槽示例") self.setGeometry(300, 300, 400, 300) # 中心Widget和布局 central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) # 1. 创建QListWidget并添加项 self.list_widget = QListWidget() # 支持多选(可选,默认单选) self.list_widget.setSelectionMode(QListWidget.MultiSelection) # 添加测试项 items = ["项目1", "项目2", "项目3", "项目4", "项目5"] for item_text in items: # 可给项附加隐藏数据(通过setData存储,data读取) item = QListWidgetItem(item_text) item.setData(Qt.UserRole, f"隐藏数据_{item_text}") # 自定义角色存储额外信息 self.list_widget.addItem(item) # 2. 显示交互信息的标签 self.info_label = QLabel("请操作列表项(点击、双击、切换选中)") # 3. 绑定信号与槽函数 self.list_widget.itemClicked.connect(self.on_item_clicked) self.list_widget.itemDoubleClicked.connect(self.on_item_double_clicked) self.list_widget.currentItemChanged.connect(self.on_current_item_changed) self.list_widget.itemSelectionChanged.connect(self.on_selection_changed) # 添加控件到布局 layout.addWidget(self.list_widget) layout.addWidget(self.info_label) # ------------------------------ # 槽函数实现 # ------------------------------ def on_item_clicked(self, item: QListWidgetItem): """处理列表项点击事件""" text = item.text() hidden_data = item.data(Qt.UserRole) # 读取隐藏数据 self.info_label.setText(f"点击项: {text} | 隐藏数据: {hidden_data}") def on_item_double_clicked(self, item: QListWidgetItem): """处理列表项双击事件(示例:删除双击项)""" text = item.text() self.list_widget.takeItem(self.list_widget.row(item)) # 删除项 self.info_label.setText(f"双击删除项: {text}") def on_current_item_changed(self, new_item: QListWidgetItem, old_item: QListWidgetItem): """处理选中项变化事件""" if new_item: # 避免初始无选中项时的None self.info_label.setText(f"切换选中项: 从 {old_item.text() if old_item else '无'} 到 {new_item.text()}") def on_selection_changed(self): """处理多选时的选中集合变化""" selected_items = self.list_widget.selectedItems() # 获取所有选中项 selected_texts = [item.text() for item in selected_items] self.info_label.setText(f"当前选中项: {', '.join(selected_texts)}") if __name__ == "__main__": app = QApplication(sys.argv) window = ListWidgetSignalDemo() window.show() sys.exit(app.exec_()) ``` ### 二、进阶:重写事件处理方法(深度定制) 当信号-槽无法满足需求(如自定义鼠标右键菜单、拦截特定键盘按键、处理拖拽事件等)时,可通过**重写 `QListWidget` 的事件方法**或**安装事件过滤器**实现。 #### 1. 重写 `QListWidget` 自身的事件方法 直接继承 `QListWidget`,重写其 `mousePressEvent`、`keyPressEvent` 等方法,捕获原始事件。 ##### 示例:自定义右键菜单(重写鼠标按下事件) ```python from PySide2.QtWidgets import (QApplication, QMainWindow, QListWidget, QListWidgetItem, QMenu, QAction) from PySide2.QtCore import Qt import sys # 1. 继承QListWidget,重写事件方法 class CustomListWidget(QListWidget): def __init__(self, parent=None): super().__init__(parent) self.init_context_menu() # 初始化右键菜单 def init_context_menu(self): """创建右键菜单""" self.context_menu = QMenu(self) # 添加菜单动作 self.action_delete = QAction("删除选中项", self) self.action_delete.triggered.connect(self.delete_selected_items) self.action_clear = QAction("清空列表", self) self.action_clear.triggered.connect(self.clear) # 添加到菜单 self.context_menu.addAction(self.action_delete) self.context_menu.addAction(self.action_clear) def mousePressEvent(self, event): """重写鼠标按下事件:右键显示菜单""" # 先调用父类方法,确保正常的选中逻辑(如左键点击选中项) super().mousePressEvent(event) # 若右键点击,且点击位置有项 if event.button() == Qt.RightButton: # 获取右键点击位置对应的项 clicked_item = self.itemAt(event.pos()) if clicked_item: # 点击在项上 self.context_menu.exec_(event.globalPos()) # 显示菜单 def delete_selected_items(self): """删除选中项""" for item in self.selectedItems(): self.takeItem(self.row(item)) # 2. 主窗口使用自定义ListWidget class CustomEventDemo(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("QListWidget 重写事件示例") self.setGeometry(300, 300, 400, 300) # 使用自定义的ListWidget self.custom_list = CustomListWidget() # 添加测试项 for i in range(5): self.custom_list.addItem(f"自定义项{i+1}") self.setCentralWidget(self.custom_list) if __name__ == "__main__": app = QApplication(sys.argv) window = CustomEventDemo() window.show() sys.exit(app.exec_()) ``` #### 2. 安装事件过滤器(监控子控件或外部事件) 若不想修改 `QListWidget` 本身,可在其父控件上**安装事件过滤器**,监控 `QListWidget` 的所有事件(如拦截键盘按键)。 ##### 示例:拦截 "Delete" 键删除选中项 ```python from PySide2.QtWidgets import (QApplication, QMainWindow, QListWidget, QListWidgetItem) from PySide2.QtCore import QEvent, Qt import sys class EventFilterDemo(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle("QListWidget 事件过滤器示例") self.setGeometry(300, 300, 400, 300) self.list_widget = QListWidget() for i in range(5): self.list_widget.addItem(f"过滤事件项{i+1}") self.setCentralWidget(self.list_widget) # 给list_widget安装事件过滤器(监控者是当前主窗口) self.list_widget.installEventFilter(self) def eventFilter(self, watched, event): """重写事件过滤器:watched是被监控的对象,event是事件""" # 仅处理list_widget的事件 if watched == self.list_widget: # 拦截键盘按键事件 if event.type() == QEvent.KeyPress: key = event.key() if key == Qt.Key_Delete: # 按下Delete键 # 删除选中项 for item in self.list_widget.selectedItems(): self.list_widget.takeItem(self.list_widget.row(item)) return True # 返回True表示事件已处理,不再传递 # 其他事件交给默认处理 return super().eventFilter(watched, event) if __name__ == "__main__": app = QApplication(sys.argv) window = EventFilterDemo() window.show() sys.exit(app.exec_()) ``` ### 三、关键注意事项 1. **信号-槽优先**:绝大多数常规需求(点击、选中、双击)都可通过信号-槽实现,无需重写事件,代码更简洁易维护。 2. **`QListWidgetItem` 的隐藏数据**:通过 `item.setData(Qt.UserRole, 数据)` 存储额外信息(如ID、路径),`item.data(Qt.UserRole)` 读取,避免仅依赖显示文本。 3. **事件传递顺序**:重写事件时,若需保留原有逻辑(如左键选中项),务必先调用 `super().xxxEvent(event)`。 4. **多选模式**:通过 `setSelectionMode()` 设置(如 `QListWidget.MultiSelection` 支持多选),多选时用 `selectedItems()` 获取所有选中项。 ### 总结 `QListWidget` 的事件用法分为「基础信号-槽」和「进阶事件重写/过滤」: - 简单交互(点击、选中、删除)→ 用 **信号-槽**; - 深度定制(右键菜单、拦截按键、拖拽)→ 用 **重写事件方法** 或 **事件过滤器**。 两者结合可覆盖几乎所有列表交互场景。 原文出处:http://malaoshi.top/show_1GW1sw0piA0c.html