找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2412

积分

1

好友

333

主题
发表于 前天 19:14 | 查看: 2| 回复: 0

本文将通过Python的PyQt(或PySide6)框架,实现一个常见的界面交互逻辑:当选择不同的产品型号(单选按钮)时,界面中动态展示并切换该型号对应的可选功能(复选框)列表。

功能说明

假设我们有一款产品,它拥有多个不同的型号。每个型号都配备了特定的一组功能,不同型号之间的功能列表可能存在差异。我们的目标是设计一个直观的图形界面来实现以下效果:

  1. 型号选择:通过一组单选按钮(QRadioButton)来展示所有可选型号,同一时间只能选择其中一个型号。
  2. 功能展示:通过一组复选框(QCheckBox)来展示当前选中型号所支持的功能,用户可以从中进行多选。

当用户切换型号时,下方展示的复选框列表需要实时更新,仅显示新选中型号所支持的功能项。

PyQt动态复选框界面效果对比

代码实现

为了实现上述需求,我们将使用以下PyQt组件:

  • QRadioButton:用于创建型号单选按钮。
  • QCheckBox:用于创建功能复选框。
  • QGroupBox:用于将相关组件(如所有型号按钮或所有功能复选框)归类并框选显示,提升界面组织性。
  • QHBoxLayoutQVBoxLayout:用于管理组件在水平和垂直方向上的布局。

有了基础组件,实现型号切换联动更新功能列表的核心思路如下:

  1. 预创建与存储:在程序初始化时,根据预定义的数据结构,创建所有可能的功能对应的QCheckBox组件,并将其存储在一个Python字典中以便后续检索。
  2. 初始显示:设置一个默认选中的型号,并根据该型号的功能列表,将对应的QCheckBox组件添加到界面布局中进行显示。
  3. 动态更新:当型号切换时,执行“先清除,后添加”的操作。即先将当前布局中显示的所有QCheckBox组件全部移除,然后再将新选中型号对应的功能QCheckBox组件添加到布局中,从而实现列表的动态刷新。

2.1 初始化

首先,我们定义产品的型号与功能映射关系。这里使用Python的字典数据结构 self.model_funcs 来存储。

def __init__(self):
    super().__init__()

    # 定义型号与功能的映射关系
    self.model_funcs = {
        “型号1” : [“功能A”, “功能B”, “功能C”],
        “型号2” : [“功能C”, “功能D”]
    }

    self.model_radio_button = {} # 存储型号单选按钮
    self.func_checkboxes = {}    # 存储所有功能复选框

    self.init_ui()

接下来是界面初始化代码 init_ui。首先是型号选择部分的实现:

  • model_layout 定义一个水平布局,用于横向排列所有型号的单选按钮。
  • model_group 定义一个分组框,将上述水平布局纳入其中,并为分组设置标题“型号”。
  • 通过遍历 self.model_funcs.keys() 获取所有型号名称,并依次创建对应的 QRadioButton
  • 将第一个型号的按钮设置为默认选中状态。
  • 将每个按钮的 clicked 信号连接到同一个槽函数 self.on_model_changed,以便在型号切换时触发更新逻辑。
  • 将创建的按钮组件及其名称记录到 self.model_radio_button 字典中,便于后续管理。
def init_ui(self):
    # 型号水平布局,并集中到一个型号组中
    model_layout = QHBoxLayout()
    for i, model_name in enumerate(self.model_funcs.keys()):
        logger.info(f“i:{i}, model_name:{model_name}“)
        radio = QRadioButton(model_name)
        # 默认第0个型号被选中
        if i == 0:
            radio.setChecked(True)
        # 给每个型号的radio连接槽函数
        radio.clicked.connect(self.on_model_changed)
        # 将radio组件添加到布局
        model_layout.addWidget(radio)
        # 将radio组件及名称记录到self.model_radio_button[]中
        self.model_radio_button[model_name] = radio

    model_group = QGroupBox(“型号”)
    model_group.setLayout(model_layout)

接着是功能展示区域的初始化:

  • self.funcs_layout 定义一个垂直布局,注意这里使用了实例变量,因为我们需要在另一个方法中修改这个布局的内容。
  • funcs_group 定义一个分组框,标题为“功能”,并将垂直布局设置给它。
  • 为了创建所有可能的功能复选框,我们需要从 self.model_funcs 的所有值(即各个功能列表)中提取出不重复的功能名。这里使用 集合(set) 数据结构 all_funcs 来实现自动去重。
  • 遍历去重后的功能名集合,为每个功能创建一个 QCheckBox 组件,并存储到 self.func_checkboxes 字典中(键为功能名,值为复选框组件)。注意:此时这些复选框尚未添加到任何布局中。
    # 功能点垂直布局,并集中到一个功能组中
    self.funcs_layout = QVBoxLayout()
    funcs_group = QGroupBox(“功能”)
    funcs_group.setLayout(self.funcs_layout)

    # 根据self.model_funcs中的定义,提取出非重复的所有功能点
    all_funcs = set()
    for func in self.model_funcs.values():
        all_funcs.update(func)

    # 创建所有功能点的checkbox
    for func in sorted(all_funcs):
        logger.info(f“func:{func}“)
        checkbox = QCheckBox(func)
        # 将checkbox组件及名称暂存到self.func_checkboxes[]中
        self.func_checkboxes[func] = checkbox

初始化显示默认型号对应的功能。我们通过 self.update_funcs_show(list(self.model_funcs.keys())[0]) 来触发第一次的功能列表渲染。

    # 初始化显示默认型号对应的功能
    logger.info(f“list(self.model_funcs.keys())[0]:{list(self.model_funcs.keys())[0]}“)
    self.update_funcs_show(list(self.model_funcs.keys())[0])

最后,设置主窗口的整体布局,将型号组和功能组垂直排列。

    # 主布局
    main_layout = QVBoxLayout(self)
    main_layout.addWidget(model_group)
    main_layout.addWidget(funcs_group)

2.2 按钮切换的槽函数

当用户点击不同的型号单选按钮时,会触发 on_model_changed 槽函数。其逻辑是遍历存储的所有单选按钮,找到当前被选中的那一个,然后调用 update_funcs_show 函数并传入该型号的名称,以更新功能列表。

    # 切换型号
    def on_model_changed(self):
        # 遍历model_radio_button
        for model_name, radio in self.model_radio_button.items():
            logger.debug(f“judge model_name:{model_name} …“)
            if radio.isChecked():
                logger.debug(f“model_name:{model_name} isChecked“)
                self.update_funcs_show(model_name)
                break

2.3 根据型号更新显示对应的功能

update_funcs_show 函数是实现动态更新的核心。它接收一个型号名作为参数,并执行以下操作:

  1. 清除现有组件:首先检查 self.funcs_layout 垂直布局中是否已有子组件(通过 count() 判断)。如果有,则通过循环使用 takeAt(0) 方法将这些组件从布局中移除,并调用 setParent(None) 将其从界面widget树中彻底删除。
  2. 添加新组件:然后根据传入的 model_name,从 self.model_funcs 字典中获取该型号对应的功能列表。遍历这个列表,通过功能名从 self.func_checkboxes 字典中取出预先创建好的 QCheckBox 组件,并使用 addWidget 方法将其添加到 self.funcs_layout 布局中。

这样,就完成了功能复选框列表的“先清空,后填充”的动态更新过程。

    # 根据型号和更新显示对应的功能
    def update_funcs_show(self, model_name):
        logger.debug(f“model_name:{model_name}“)

        # 先清除
        logger.debug(f“funcs_layout.count:{self.funcs_layout.count()}“)
        while self.funcs_layout.count():
            child = self.funcs_layout.takeAt(0)
            if child.widget():
                logger.debug(f“remove child:{child}“)
                child.widget().setParent(None)

        # 再添加
        for func in self.model_funcs[model_name]:
            logger.debug(f“add func:{func}“)
            # 将checkbox组件添加到布局
            self.funcs_layout.addWidget(self.func_checkboxes[func])

2.4 完整代码

以下是完整的实现代码。本例使用的是 PySide6(其API与PyQt6几乎完全一致),并通过 loguru 库输出运行日志以便调试。

import sys
from loguru import logger
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,
                               QRadioButton, QCheckBox, QGroupBox, QButtonGroup)

class ModelSelect(QWidget):
    def __init__(self):
        super().__init__()

        self.model_funcs = {
            “型号1” : [“功能A”, “功能B”, “功能C”],
            “型号2” : [“功能C”, “功能D”]
        }

        self.model_radio_button = {}
        self.func_checkboxes = {}

        self.init_ui()

    def init_ui(self):

        # 型号水平布局,并集中到一个型号组中
        model_layout = QHBoxLayout()
        for i, model_name in enumerate(self.model_funcs.keys()):
            logger.info(f“i:{i}, model_name:{model_name}“)
            radio = QRadioButton(model_name)
            # 默认第0个型号被选中
            if i == 0:
                radio.setChecked(True)
            # 给每个型号的radio连接槽函数
            radio.clicked.connect(self.on_model_changed)
            # 将radio组件添加到布局
            model_layout.addWidget(radio)
            # 将radio组件及名称记录到self.model_radio_button[]中
            self.model_radio_button[model_name] = radio

        model_group = QGroupBox(“型号”)
        model_group.setLayout(model_layout)

        # 功能点垂直布局,并集中到一个功能组中
        self.funcs_layout = QVBoxLayout()
        funcs_group = QGroupBox(“功能”)
        funcs_group.setLayout(self.funcs_layout)

        # 根据self.model_funcs中的定义,提取出非重复的所有功能点
        all_funcs = set()
        for func in self.model_funcs.values():
            all_funcs.update(func)

        # 创建所有功能点的checkbox
        for func in sorted(all_funcs):
            logger.info(f“func:{func}“)
            checkbox = QCheckBox(func)
            # 将checkbox组件及名称暂存到self.func_checkboxes[]中
            self.func_checkboxes[func] = checkbox

        # 初始化显示默认型号对应的功能
        logger.info(f“list(self.model_funcs.keys())[0]:{list(self.model_funcs.keys())[0]}“)
        self.update_funcs_show(list(self.model_funcs.keys())[0])

        # 主布局
        main_layout = QVBoxLayout(self)
        main_layout.addWidget(model_group)
        main_layout.addWidget(funcs_group)

    # 切换型号
    def on_model_changed(self):
        # 遍历model_radio_button
        for model_name, radio in self.model_radio_button.items():
            logger.debug(f“judge model_name:{model_name} …“)
            if radio.isChecked():
                logger.debug(f“model_name:{model_name} isChecked“)
                self.update_funcs_show(model_name)
                break

    # 根据型号和更新显示对应的功能
    def update_funcs_show(self, model_name):
        logger.debug(f“model_name:{model_name}“)

        # 先清除
        logger.debug(f“funcs_layout.count:{self.funcs_layout.count()}“)
        while self.funcs_layout.count():
            child = self.funcs_layout.takeAt(0)
            if child.widget():
                logger.debug(f“remove child:{child}“)
                child.widget().setParent(None)

        # 再添加
        for func in self.model_funcs[model_name]:
            logger.debug(f“add func:{func}“)
            # 将checkbox组件添加到布局
            self.funcs_layout.addWidget(self.func_checkboxes[func])

if __name__ == “__main__”:
    app = QApplication(sys.argv)
    window = ModelSelect()
    window.show()
    sys.exit(app.exec())

运行程序,控制台会打印出初始化及切换型号时的详细日志,清晰地展示了组件创建、移除和添加的过程。对应的界面效果即文章开头所示的对比图。

PyQt动态复选框功能调试日志

总结

本文详细介绍了如何使用PyQt(PySide6)框架实现一个经典的前端交互逻辑:通过单选按钮控制关联的复选框列表动态更新。我们首先明确了功能需求,然后逐步拆解了实现思路,涵盖了数据结构的定义、界面组件的创建与布局、信号与槽的连接,以及核心的“先清除后添加”的动态更新算法,并提供了完整的可运行代码。这种模式在配置工具、参数化设计等桌面应用场景中非常实用。

如果你在实现类似功能或学习PyQt/PySide6的过程中遇到问题,欢迎在云栈社区与其他开发者交流讨论。




上一篇:i.MXRT600 SPI从设备DMA链式传输优化,突破50Mbps速率瓶颈
下一篇:Kafka与RocketMQ吞吐量对比及选型分析:为何业务场景常选后者
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-12 01:28 , Processed in 0.196949 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表