You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyQt5中实现QComboBox选项可勾选并支持多选

实现可多选的QComboBox(无需硬编码Checkbox)

我明白你想要的是一个支持多选的下拉框,而且不想在每个选项里硬写Checkbox组件——其实用Qt的模型视图框架就能轻松实现,核心思路是利用QStandardItemModel给每个选项添加勾选状态,再配合自定义的视图点击逻辑来更新选中状态和显示文本。


1. 重构myCombo类

我们需要:

  • 初始化QStandardItemModel管理下拉选项的状态
  • 设置下拉视图为QListView(默认视图对勾选交互支持有限)
  • 处理视图的点击事件,切换选项的勾选状态
  • 实现输入框文本更新逻辑,把选中项拼接显示

修改后的myCombo代码如下:

from PyQt5.QtWidgets import (QComboBox, QLineEdit, QListView, QStandardItemModel, QStandardItem)
from PyQt5.QtCore import Qt, QModelIndex

class myCombo(QComboBox):
    def __init__(self, parent=None):
        super(myCombo, self).__init__(parent)
        # 保留你原本的样式设置
        self.setStyleSheet("""
            QComboBox{
                font-size:12px;
                color:black;
                background-color:white;
                border:1px solid black;
                padding:1px;
            }
        """)
        self.setEditable(True)
        self.lineEdit().setAlignment(Qt.AlignCenter)
        self.lineEdit().setReadOnly(True)
        
        # 初始化模型与视图
        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.list_view = QListView(self)
        self.setView(self.list_view)
        # 绑定点击事件处理勾选切换
        self.list_view.clicked.connect(self.on_item_clicked)
        
        # 存储选中项文本
        self.selected_items = []

    def addItems(self, items):
        # 重写addItems,给每个选项添加勾选属性
        self.model.clear()
        self.selected_items.clear()
        for text in items:
            item = QStandardItem(text)
            # 设置项可勾选、可交互
            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            # 默认未勾选
            item.setData(Qt.Unchecked, Qt.CheckStateRole)
            self.model.appendRow(item)
        # 更新初始显示文本
        self.update_display_text()

    def on_item_clicked(self, index: QModelIndex):
        # 切换点击项的勾选状态
        item = self.model.itemFromIndex(index)
        if item.checkState() == Qt.Checked:
            item.setData(Qt.Unchecked, Qt.CheckStateRole)
            self.selected_items.remove(item.text())
        else:
            item.setData(Qt.Checked, Qt.CheckStateRole)
            self.selected_items.append(item.text())
        # 更新输入框显示
        self.update_display_text()

    def update_display_text(self):
        # 拼接选中项为字符串显示
        if not self.selected_items or self.selected_items == [' ']:
            self.lineEdit().setText(' ')
        else:
            # 过滤空选项
            filtered = [item for item in self.selected_items if item != ' ']
            self.lineEdit().setText(', '.join(filtered))

    def get_selected_items(self):
        # 提供外部获取选中项的接口
        return [item for item in self.selected_items if item != ' ']

2. 修改主窗口逻辑

在sWindow的okClicked方法中,调用get_selected_items()获取用户选中的年份和月份,方便后续处理:

def okClicked(self):
    selected_years = self.firstLine.get_selected_items()
    selected_months = self.secondLine.get_selected_items()
    print(f"选中的年份: {selected_years}")
    print(f"选中的月份: {selected_months}")
    self.close()

3. 完整可运行代码

整合所有部分后的完整代码:

import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, QComboBox, QLineEdit, QListView, QStandardItemModel, QStandardItem)
from PyQt5.QtCore import Qt, QModelIndex

class myCombo(QComboBox):
    def __init__(self, parent=None):
        super(myCombo, self).__init__(parent)
        self.setStyleSheet("""
            QComboBox{
                font-size:12px;
                color:black;
                background-color:white;
                border:1px solid black;
                padding:1px;
            }
        """)
        self.setEditable(True)
        self.lineEdit().setAlignment(Qt.AlignCenter)
        self.lineEdit().setReadOnly(True)
        
        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.list_view = QListView(self)
        self.setView(self.list_view)
        self.list_view.clicked.connect(self.on_item_clicked)
        
        self.selected_items = []

    def addItems(self, items):
        self.model.clear()
        self.selected_items.clear()
        for text in items:
            item = QStandardItem(text)
            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            item.setData(Qt.Unchecked, Qt.CheckStateRole)
            self.model.appendRow(item)
        self.update_display_text()

    def on_item_clicked(self, index: QModelIndex):
        item = self.model.itemFromIndex(index)
        if item.checkState() == Qt.Checked:
            item.setData(Qt.Unchecked, Qt.CheckStateRole)
            self.selected_items.remove(item.text())
        else:
            item.setData(Qt.Checked, Qt.CheckStateRole)
            self.selected_items.append(item.text())
        self.update_display_text()

    def update_display_text(self):
        if not self.selected_items or self.selected_items == [' ']:
            self.lineEdit().setText(' ')
        else:
            filtered = [item for item in self.selected_items if item != ' ']
            self.lineEdit().setText(', '.join(filtered))

    def get_selected_items(self):
        return [item for item in self.selected_items if item != ' ']

class sWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        years = [' ', '2017', '2018', '2019', '2020']
        months = [' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
        self.setMinimumSize(360, 140)
        self.setWindowTitle("Dialog")
        
        self.yearLabel = QLabel('Select Year(s):', self)
        self.yearLabel.move(20, 20)
        
        self.firstLine = myCombo(self)
        self.firstLine.addItems(years)
        self.firstLine.move(120, 20)
        self.firstLine.resize(200, 32)
        
        self.monthLabel = QLabel('Select Month(s):', self)
        self.monthLabel.move(20, 60)
        
        self.secondLine = myCombo(self)
        self.secondLine.addItems(months)
        self.secondLine.move(120, 60)
        self.secondLine.resize(200, 32)
        
        okButton = QPushButton('OK', self)
        okButton.clicked.connect(self.okClicked)
        okButton.resize(100, 32)
        okButton.move(120, 100)
        
        cancelB = QPushButton('Cancel', self)
        cancelB.clicked.connect(self.cancelClicked)
        cancelB.resize(100, 32)
        cancelB.move(220, 100)

    def okClicked(self):
        selected_years = self.firstLine.get_selected_items()
        selected_months = self.secondLine.get_selected_items()
        print(f"选中的年份: {selected_years}")
        print(f"选中的月份: {selected_months}")
        self.close()

    def cancelClicked(self):
        self.close()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = sWindow()
    main.show()
    sys.exit(app.exec_())

关键说明

  • 全程没有硬编码QCheckBox组件,而是通过QStandardItem的CheckStateRole管理勾选状态,这是Qt模型视图的标准实现方式,更灵活易维护。
  • 点击下拉选项会自动切换勾选状态,输入框实时显示选中项(逗号分隔)。
  • 通过get_selected_items()可以轻松获取用户选中的内容,适配后续业务逻辑。

内容的提问来源于stack exchange,提问作者New2coding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:31:21