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

PyQt6下拉多选复选框交互异常及逻辑问题修复求助

解决PyQt6复选框下拉列表点击响应问题

问题说明

  • 需求:实现带复选框的下拉选择列表,要求"Run All Tests"默认选中;勾选其他任意复选框时,"Run All Tests"自动取消选中;勾选"Run All Tests"时,所有其他复选框自动取消选中。
  • 当前异常:
    • 点击"Run All Tests"的标签无响应,仅点击复选框区域功能生效
    • 点击其他项的复选框无响应,仅点击标签区域功能生效
  • 环境:Python 3.11、PyQt6 6.8.1

解决方案

核心问题是clicked信号仅在点击文本区域时触发,点击复选框区域不会触发;改用pressed信号可响应所有点击区域,但需要手动处理复选框状态切换,避免和Qt默认行为冲突。

修改要点

  1. 绑定pressed信号到处理函数,替代原clicked信号
  2. 在处理函数中,先手动切换当前项的复选状态,再执行业务逻辑
  3. 优化"Run All Tests"的状态同步逻辑,确保选中时其他项全部取消

修改后的完整代码

import sys
from PyQt6.QtCore import Qt, QThreadPool
from PyQt6.QtGui import QStandardItemModel, QStandardItem
from PyQt6.QtWidgets import (
    QApplication,
    QComboBox,
    QLabel,
    QMainWindow,
    QMessageBox,
    QVBoxLayout,
    QAbstractItemView,
    QListView,
    QWidget,
)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.threadpool = QThreadPool.globalInstance()
        self.crawl = None
        self.current_browser = None
        self.driver = None
        self.show_error_popup = True
        self.error_popup_response = None

        self.setWindowTitle("APP_NAME")
        self.layout = QVBoxLayout()

        self.ui_catg_names = QComboBox()
        self.ui_catg_names.setModel(QStandardItemModel(self))
        self.ui_catg_names.setView(QListView(self))
        self.ui_catg_names.view().setSelectionMode(
            QAbstractItemView.SelectionMode.MultiSelection
        )
        # 改用pressed信号响应所有点击区域
        self.ui_catg_names.view().pressed.connect(self.handle_item_pressed)
        self.ui_catg_names.setEditable(True)
        self.ui_catg_names.lineEdit().setReadOnly(True)
        self.ui_catg_names.lineEdit().setPlaceholderText("Select Categories")
        self.layout.addWidget(QLabel("Select Test Categories:"))
        self.layout.addWidget(self.ui_catg_names)

        catgnames = self.get_catg_names()
        self.set_catg_names(["Run All Tests"] + sorted(catgnames))
        # 默认选中Run All Tests
        run_all_item = self.ui_catg_names.model().item(0)
        if run_all_item and run_all_item.text() == "Run All Tests":
            run_all_item.setCheckState(Qt.CheckState.Checked)

        central_widget = QWidget()
        central_widget.setLayout(self.layout)
        self.setCentralWidget(central_widget)

    def handle_item_pressed(self, index):
        item = self.ui_catg_names.model().itemFromIndex(index)
        if not item:
            return

        # 先手动切换当前项的复选状态
        current_state = item.checkState()
        new_state = Qt.CheckState.Unchecked if current_state == Qt.CheckState.Checked else Qt.CheckState.Checked
        item.setCheckState(new_state)

        # 处理Run All Tests项的逻辑
        if item.text() == "Run All Tests":
            if new_state == Qt.CheckState.Checked:
                # 选中时取消所有其他项
                self.select_all_items(False)
                item.setCheckState(Qt.CheckState.Checked)
            # 取消选中时无需额外操作
        else:
            # 处理其他项:如果有任意项选中,取消Run All Tests
            run_all_item = self.ui_catg_names.model().item(0)
            if run_all_item and run_all_item.text() == "Run All Tests":
                # 检查是否还有其他选中项
                has_checked = any(self.ui_catg_names.model().item(i).checkState() == Qt.CheckState.Checked 
                                 for i in range(1, self.ui_catg_names.model().rowCount()))
                run_all_item.setCheckState(Qt.CheckState.Unchecked if has_checked else Qt.CheckState.Checked)

        self.update_text()

    def select_all_items(self, check):
        for index in range(1, self.ui_catg_names.model().rowCount()):
            item = self.ui_catg_names.model().item(index)
            item.setCheckState(
                Qt.CheckState.Checked if check else Qt.CheckState.Unchecked
            )

    def update_text(self):
        selected_items = []
        for index in range(self.ui_catg_names.model().rowCount()):
            item = self.ui_catg_names.model().item(index)
            if item.checkState() == Qt.CheckState.Checked:
                selected_items.append(item.text())
        self.ui_catg_names.lineEdit().setText(", ".join(selected_items))

    def add_items(self, items):
        for item_text in items:
            item = QStandardItem(item_text)
            item.setFlags(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled)
            item.setData(Qt.CheckState.Unchecked, Qt.ItemDataRole.CheckStateRole)
            self.ui_catg_names.model().appendRow(item)

    def get_selected_items(self):
        selected_items = []
        for index in range(self.ui_catg_names.model().rowCount()):
            item = self.ui_catg_names.model().item(index)
            if item.checkState() == Qt.CheckState.Checked:
                item_text = item.text()
                if item_text != "Run All Tests":
                    selected_items.append(item_text)
        return selected_items

    def on_crawl_error(self, error_info):
        global POPUP_RESPONSE
        url, e = error_info
        POPUP_RESPONSE = QMessageBox.critical(
            self,
            repr(e),
            f"Error while crawling {url}\n(Ignore will prevent this popup for the rest of the run)",
            buttons=QMessageBox.StandardButton.Retry
            | QMessageBox.StandardButton.Ignore
            | QMessageBox.StandardButton.Abort,
        )
        print("COMPLETE on_crawl_error() with", POPUP_RESPONSE)

    def stop_test(self):
        if "process" in locals():
            self.process.stop()
            del self.process
        self.exit_app()

    def exit_app(self):
        if self.driver:
            self.driver.quit()
        sys.exit()

    def closeEvent(self, event):
        self.stop_test()
        event.accept()

    def get_catg_names(self):
        return ["test1", "test2", "test3"]

    def set_catg_names(self, catg_names):
        self.ui_catg_names.clear()
        self.add_items(catg_names)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:19:51