python pyside2 list widget(QListWidget)

介绍

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() 存储不显示的数据:

item = QListWidgetItem("显示文本", self.list_widget)
# 用自定义角色存储隐藏数据(如ID、字典等)
item.setData(Qt.UserRole + 1, {"id": 1001, "status": "active"})

# 获取隐藏数据
hidden_data = item.data(Qt.UserRole + 1)

设置选中

在 PySide2 中,QListWidget 提供了多种方法设置选中项,可根据需求选择直接选中单个项、多个项或按条件选中。以下是常用的实现方式及示例:

import sys
from PySide2.QtWidgets import (QApplication, QWidget, QVBoxLayout, 
                               QListWidget, QListWidgetItem, QPushButton,
                               QHBoxLayout, QLabel)
from PySide2.QtCore import Qt

class ListWidgetSelectionDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("QListWidget 设置选中项示例")
        self.setGeometry(300, 300, 500, 400)

        # 创建布局
        main_layout = QVBoxLayout()
        btn_layout = QHBoxLayout()

        # 创建QListWidget并添加项
        self.list_widget = QListWidget()
        self.list_widget.setSelectionMode(QListWidget.ExtendedSelection)  # 支持多选
        self.items = ["项目1", "项目2", "项目3", "项目4", "项目5", "项目6"]
        for text in self.items:
            self.list_widget.addItem(text)

        # 创建操作按钮
        self.btn_select_first = QPushButton("选中第一项")
        self.btn_select_last = QPushButton("选中最后一项")
        self.btn_select_by_text = QPushButton("选中'项目3'")
        self.btn_select_by_index = QPushButton("选中索引2的项")
        self.btn_select_all = QPushButton("全选")
        self.btn_deselect_all = QPushButton("取消全选")
        self.btn_select_even = QPushButton("选中偶数项")

        # 绑定按钮事件
        self.btn_select_first.clicked.connect(self.select_first)
        self.btn_select_last.clicked.connect(self.select_last)
        self.btn_select_by_text.clicked.connect(self.select_by_text)
        self.btn_select_by_index.clicked.connect(self.select_by_index)
        self.btn_select_all.clicked.connect(self.list_widget.selectAll)
        self.btn_deselect_all.clicked.connect(self.list_widget.clearSelection)
        self.btn_select_even.clicked.connect(self.select_even_items)

        # 添加控件到布局
        btn_layout.addWidget(self.btn_select_first)
        btn_layout.addWidget(self.btn_select_last)
        btn_layout.addWidget(self.btn_select_by_text)
        btn_layout.addWidget(self.btn_select_by_index)

        main_layout.addWidget(QLabel("列表项:"))
        main_layout.addWidget(self.list_widget)
        main_layout.addLayout(btn_layout)
        main_layout.addWidget(self.btn_select_all)
        main_layout.addWidget(self.btn_deselect_all)
        main_layout.addWidget(self.btn_select_even)

        self.setLayout(main_layout)
        self.show()

    # 方法1:选中第一项
    def select_first(self):
        if self.list_widget.count() > 0:
            item = self.list_widget.item(0)  # 获取第一项
            item.setSelected(True)  # 设置选中
            self.list_widget.setCurrentItem(item)  # 同步当前项

    # 方法2:选中最后一项
    def select_last(self):
        count = self.list_widget.count()
        if count > 0:
            item = self.list_widget.item(count - 1)  # 获取最后一项
            item.setSelected(True)

    # 方法3:按文本选中项
    def select_by_text(self):
        target_text = "项目3"
        # 遍历所有项查找匹配文本
        for i in range(self.list_widget.count()):
            item = self.list_widget.item(i)
            if item.text() == target_text:
                item.setSelected(True)
                break

    # 方法4:按索引选中项
    def select_by_index(self):
        index = 2  # 第3项(索引从0开始)
        if 0 <= index < self.list_widget.count():
            # 通过索引获取项并选中
            self.list_widget.item(index).setSelected(True)
            # 或通过setCurrentRow直接选中行
            # self.list_widget.setCurrentRow(index)

    # 方法5:按条件选中(示例:选中偶数索引项)
    def select_even_items(self):
        # 先取消现有选中
        self.list_widget.clearSelection()
        # 选中偶数索引项(0, 2, 4...)
        for i in range(0, self.list_widget.count(), 2):
            self.list_widget.item(i).setSelected(True)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ListWidgetSelectionDemo()
    sys.exit(app.exec_())

基本选中方法

item.setSelected(True):通过列表项对象设置选中状态(最常用)
item = self.list_widget.item(0)  # 获取索引0的项
item.setSelected(True)  # 选中
item.setSelected(False)  # 取消选中
setCurrentRow(index):通过行索引选中项(同时会设置为当前项)
self.list_widget.setCurrentRow(2)  # 选中索引2的项
setCurrentItem(item):通过项对象设置为当前选中项
item = self.list_widget.item(1)
self.list_widget.setCurrentItem(item)  # 选中该项

批量选中方法

全选:selectAll()
self.list_widget.selectAll()  # 选中所有项(需开启多选模式)
取消全选:clearSelection()
self.list_widget.clearSelection()  # 取消所有选中项
按条件选中:遍历项并设置 setSelected()
# 示例:选中包含"关键词"的项
for i in range(self.list_widget.count()):
    item = self.list_widget.item(i)
    if "关键词" in item.text():
        item.setSelected(True)

选择模式设置

需先通过 setSelectionMode() 设置多选规则,否则部分批量选中方法无效:

# 常用选择模式
self.list_widget.setSelectionMode(QListWidget.SingleSelection)  # 单选(默认)
self.list_widget.setSelectionMode(QListWidget.MultiSelection)  # 多选(点击即选)
self.list_widget.setSelectionMode(QListWidget.ExtendedSelection)  # 扩展多选(Ctrl/Shift辅助)

注意事项

  • 单选模式下,新选中项会自动取消之前的选中项;
  • setCurrentRow() 和 setCurrentItem() 不仅会选中项,还会将其设为“当前项”(带虚线边框);
  • 批量选中前最好用 clearSelection() 清空现有选中状态,避免冲突。

通过上述方法,可灵活实现 QListWidget 中各种选中需求,从简单的单项选到复杂的条件批量选都能覆盖。

获取选中的项

在 PySide2 中,QListWidget 获取选中值的方法取决于选择模式(单选/多选),常用方式有以下几种:

例子

import sys
from PySide2.QtWidgets import (QApplication, QWidget, QVBoxLayout, 
                               QListWidget, QListWidgetItem, QPushButton,
                               QLabel, QHBoxLayout)
from PySide2.QtCore import Qt

class ListWidgetGetSelected(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("QListWidget 获取选中值")
        self.setGeometry(300, 300, 500, 400)

        # 主布局
        main_layout = QVBoxLayout()

        # 创建列表并设置为多选模式
        self.list_widget = QListWidget()
        self.list_widget.setSelectionMode(QListWidget.ExtendedSelection)  # 支持Ctrl/Shift多选

        # 添加示例项(同时存储隐藏数据)
        items = [
            {"text": "项目A", "data": {"id": 101, "desc": "类型A"}},
            {"text": "项目B", "data": {"id": 102, "desc": "类型B"}},
            {"text": "项目C", "data": {"id": 103, "desc": "类型C"}},
            {"text": "项目D", "data": {"id": 104, "desc": "类型D"}},
            {"text": "项目E", "data": {"id": 105, "desc": "类型E"}}
        ]
        for item_data in items:
            item = QListWidgetItem(item_data["text"])
            # 存储隐藏数据(使用UserRole)
            item.setData(Qt.UserRole, item_data["data"])
            self.list_widget.addItem(item)

        # 按钮区域
        btn_layout = QHBoxLayout()
        self.btn_get_single = QPushButton("获取当前选中项")
        self.btn_get_multi = QPushButton("获取所有选中项")
        self.btn_get_hidden = QPushButton("获取选中项隐藏数据")

        # 绑定按钮事件
        self.btn_get_single.clicked.connect(self.get_single_selected)
        self.btn_get_multi.clicked.connect(self.get_multi_selected)
        self.btn_get_hidden.clicked.connect(self.get_hidden_data)

        # 结果显示标签
        self.result_label = QLabel("选中项信息将显示在这里")
        self.result_label.setStyleSheet("border: 1px solid #eee; padding: 8px;")

        # 组装布局
        btn_layout.addWidget(self.btn_get_single)
        btn_layout.addWidget(self.btn_get_multi)
        btn_layout.addWidget(self.btn_get_hidden)

        main_layout.addWidget(QLabel("请选择列表项:"))
        main_layout.addWidget(self.list_widget)
        main_layout.addLayout(btn_layout)
        main_layout.addWidget(QLabel("结果:"))
        main_layout.addWidget(self.result_label)

        self.setLayout(main_layout)
        self.show()

    # 方法1:获取当前选中的单个项(适合单选模式)
    def get_single_selected(self):
        # 获取当前选中项(当前项指带虚线边框的项)
        current_item = self.list_widget.currentItem()
        if current_item:
            self.result_label.setText(f"当前选中项:{current_item.text()}")
        else:
            self.result_label.setText("未选中任何项")

    # 方法2:获取所有选中项(适合多选模式)
    def get_multi_selected(self):
        # 获取所有选中的项
        selected_items = self.list_widget.selectedItems()
        if not selected_items:
            self.result_label.setText("未选中任何项")
            return

        # 提取选中项的文本
        selected_texts = [item.text() for item in selected_items]
        self.result_label.setText(
            f"共选中 {len(selected_texts)} 项:\n" + 
            "\n".join(selected_texts)
        )

    # 方法3:获取选中项的隐藏数据(如ID、额外属性)
    def get_hidden_data(self):
        selected_items = self.list_widget.selectedItems()
        if not selected_items:
            self.result_label.setText("未选中任何项")
            return

        # 提取隐藏数据(通过UserRole)
        hidden_info = []
        for item in selected_items:
            data = item.data(Qt.UserRole)  # 获取存储的隐藏数据
            hidden_info.append(
                f"{item.text()} - ID: {data['id']}, 描述: {data['desc']}"
            )

        self.result_label.setText(
            f"选中项隐藏数据:\n" + 
            "\n".join(hidden_info)
        )

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ListWidgetGetSelected()
    sys.exit(app.exec_())

获取单个选中项(适合单选模式)

currentItem():返回当前获得焦点的项(带虚线边框的项)
  current_item = self.list_widget.currentItem()
  if current_item:
      text = current_item.text()  # 获取显示文本
currentRow():返回当前选中项的索引,再通过索引获取项
  row = self.list_widget.currentRow()
  if row != -1:  # -1表示无选中项
      item = self.list_widget.item(row)
      text = item.text()

获取所有选中项(适合多选模式)

selectedItems():返回所有选中项的列表(QListWidgetItem 对象集合)
  selected_items = self.list_widget.selectedItems()
  # 提取文本列表
  selected_texts = [item.text() for item in selected_items]

获取选中项的隐藏数据

如果项中存储了隐藏数据(通过 setData() 方法),可通过 data() 提取:

# 假设用 Qt.UserRole 存储了隐藏数据
for item in self.list_widget.selectedItems():
    hidden_data = item.data(Qt.UserRole)  # 获取隐藏数据
    print(f"文本: {item.text()}, 隐藏数据: {hidden_data}")

注意事项

  • 选择模式影响结果:

    • 单选模式(SingleSelection)下,selectedItems() 始终返回长度为 0 或 1 的列表
    • 多选模式(MultiSelection/ExtendedSelection)下,返回所有选中项
  • 空值判断:操作前需判断是否有选中项(currentItem() 可能返回 None,selectedItems() 可能返回空列表)

  • 性能考虑:对于大量选中项(上千项),遍历 selectedItems() 时需注意效率

通过上述方法,可根据实际需求灵活获取 QListWidget 中的选中值,包括显示文本和隐藏数据。

事件

在 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. 信号-槽完整示例

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 等方法,捕获原始事件。

示例:自定义右键菜单(重写鼠标按下事件)
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” 键删除选中项
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 的事件用法分为「基础信号-槽」和「进阶事件重写/过滤」:

  • 简单交互(点击、选中、删除)→ 用 信号-槽;
  • 深度定制(右键菜单、拦截按键、拖拽)→ 用 重写事件方法 或 事件过滤器。
    两者结合可覆盖几乎所有列表交互场景。

原文出处:/show_1GW1sw0piA0c.html