Qt常用的按钮控件编程(四)-- QCheckBox 按钮

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文介绍QT常用控件的第四个按钮,QCheckBox 按钮编程。通过这个例子,进一步巩固QT管理资源机制,学习QCheckBox 复选框的三态功能和如何分组管理QCheckBox 复选框 。项目演示如何使用默认的分组和 QButtonGroup 进行多选设置。项目使用样式表文件进行外观设置。
文章中使用的例程和内容都是在chatgpt的帮助下完成的,例程经过测试通过。

感谢朋友提供的chatgpt软件,特别是其中的gpt-box桌面工具,更是我离不开的工具。感兴趣的同仁可前往一观(apsuai.com)。

我们的调试环境仍然是双架构Kits,编译调试在当前的ubuntu(qt5)中进行,重新编译后下载到目标arm设备(qt4)中运行。
我们的编程环境为:Ubuntu64位系统(22.04),目标架构:(1)qt5 x86_64 架构,(2)qt4 32位arm架构。
环境配置请参见《Qt常用的按钮控件编程(一)》第1节。


6、QCheckBox 按钮

QCheckBox是Qt框架中的一个控件类,它代表了一个复选框,用于允许用户对一组选项进行多项选择。QCheckBox通常出现在界面上的选项列表或设置界面中。
QCheckBox继承自QAbstractButton类,因此它具有与其他按钮控件相同的属性和方法。例如,可以使用setChecked()方法设置QCheckBox的选中状态,并使用text()方法获取显示文本。

QCheckBox还提供了一些额外的功能,例如支持三态状态(即“选中”、“未选中”和“半选中”)和部分透明度。可以通过setTristate()方法启用三态状态,或通过setCheckState()方法设置其状态。另外,可以使用setOpacity()方法设置QCheckBox的不透明度。
下面是几个常用的QCheckBox方法:

  • setText(const QString &text):设置QCheckBox的显示文本。
    
  • setChecked(bool checked):设置QCheckBox的选中状态。
    
  • isChecked():返回QCheckBox的选中状态。
    
  • setTristate(bool y):启用/禁用QCheckBox的三态状态。
    
  • setCheckState(Qt::CheckState state):设置QCheckBox的选中状态,包括Qt::Checked、Qt::Unchecked和Qt::PartiallyChecked。
    
  • checkState():返回QCheckBox的选中状态,包括Qt::Checked、Qt::Unchecked和Qt::PartiallyChecked。

6.1 例程功能和程序执行效果

创建一个基于 Qt QCheckBox 按钮c++例程,项目名称"_qcheckbox" ,不使用拖取控件,控件全部采用编程。主窗口上放置三个QCheckBox 按钮分为两组:

  • 第一组:一个按钮,是一个三态复选框,三种状态为选中,未选中,半选中;
  • 第二组:两个按钮,放在QButtonGroup 控件中,可以多选,有选中、未选中两种状态;
  • 程序包括三个控件的响应函数(两个槽函数)。
  • 编译完成后生成两个同名可执行程序_qcheckbox,一个使用使用Qt4库,运行在arm架构设备,另一个使用Qt5库,运行在当前ubuntu系统。
    程序执行效果:
    (1)程序启动后效果:
    在这里插入图片描述(2)点击后执行效果(其中之一):

在这里插入图片描述

6.2 生成项目

打开 Qt Creator 并创建一个新的 应用程序项目_qcheckbox,选择Widget作为基类,不要勾选“Generate form”,,不使用拖取控件,控件全部采用编程,将两个配置好的Kits同时选上,项目新建完成如下图。(详细的项目新建过程参见:《Qt常用的按钮控件编程(一)》)。

在这里插入图片描述

6.3 添加资源文件

在本例程的项目目录的images 文件夹中准备了3张图片(如下图),下面的步骤演示了如何将资源添加到项目中。
在这里插入图片描述

6.3.1 添加图片资源

  • 在项目目录中右键点击 Resources 目录,选择 Add New… ,并选择 Qt -> Qt Resource File。
    在这里插入图片描述在这里插入图片描述- 输入资源文件的名称(自行定义)和位置,然后点击“下一步”。
    在这里插入图片描述

在 Qt Creator 中新建资源文件后,默认会进入 res.qrc 文件编辑模式(如果关闭了,可以右键这个文件点击选择“Open in Editor”),为了方便分类管理文件,我们可以使用 Add Prefix 功能为资源文件添加前缀,前缀的格式应该为类似文件系统中的路径格式,例如 /images。

在这里插入图片描述为了确保路径正确,前缀中的 / 是必需的,它在资源文件引用时是路径分隔符,起到类似 Linux 下根节点的作用,我们现在第⑪处添加了前缀/。

在这里插入图片描述添加了前缀后,我们添加资源图片,放在/images 前缀的下面。这里我们导入在本项目路径 images 文件夹中的3张图片,添加完成需要按“Ctrl + S”保存 res.qrc 才会看到左边的结果。添加完成如下图。

在这里插入图片描述

6.3.2 添加 qss 文件

QSS 文件是使用 Qt 程序相关联的样式表文件。它由 GUI 元素的外观和感觉,包括布局,颜色,鼠标的行为,大小和字体。它的风格,一个可以合并到一个 UI(用户界面)。与 HTML 的 CSS 类似,Qt 的样式表是纯文本的格式定义,在应用程序运行时可以载入和解析这些样式定义,从而使应用程序的界面呈现不同的效果。
在这里插入图片描述如上图加入一个空白文件,新建的文件名 style.qss 文件,如下图,默认添加到项目的路径下,后面步骤采用默认,直至完成。
在这里插入图片描述编辑style.qss,保存,最后完成的项目如下图所示:

在这里插入图片描述第 10 行、第 13 行,第16行,设置 QCheckBox 的 indicator 的背景图片。这样当它们点击切换时就
会看到 QCheckBox 的三种选择状态了。

style.qss文件内容(方便拷贝):

QCheckBox{
spacing: 5px;
color: white;
}
QCheckBox::indicator {
width: 50px;
height: 50px;
}
QCheckBox::indicator:enabled:unchecked {
image: url(:/images/unchecked.png);
}
QCheckBox::indicator:enabled:checked {
image: url(:/images/checked.png);
}
QCheckBox::indicator:enabled:indeterminate {
image: url(:/images/indeterminate.png);
}

6.4 完成代码编辑

6.4.1 修改项目文件 _radiobutton.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

# 根据使用的 Qt 版本设置编译条件
greaterThan(QT_MAJOR_VERSION, 4) {
    # 如果使用的是 Qt 5 或者更新版本
    message("使用的是 Qt 5版本")

} else {
    # 如果使用的是 Qt 4 或者更早的版本
    message("使用的是 Qt 4版本")
    DEFINES += QT_ARM_PLATFORM
    QMAKE_CXXFLAGS += -std=c++11
    QMAKE_CXXFLAGS += -Wno-psabi -Wno-deprecated-declarations

    LIBS += -lts
}

上面的代码后半段,在系统生成的项目文件中使用条件编译增加目标为qt4-arm时的代码。

6.4.2 修改 main.cpp

1 	#include "widget.h"
2 
3 	#include <QApplication>
4 
5 	#ifdef QT_ARM_PLATFORM
6 	#include <QTextCodec>
7 	#endif
8 
9 	/* 引入 QFile */
10	#include <QFile>
11
12	int main(int argc, char *argv[])
13	{
14		QApplication a(argc, argv);
15
16	#ifdef QT_ARM_PLATFORM
17		//解决Qt4中文乱码
18		QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
19		QTextCodec::setCodecForTr(QTextCodec::codecForName("system"));    //若英文系统,则用GBK
20		QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
21		QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
22	#endif
23
24		/* 指定文件 */
25	   QFile file(":/style.qss");
26
27		/* 判断文件是否存在 */
28		if (file.exists() ) {
29		/* 以只读的方式打开 */
30		file.open(QFile::ReadOnly);
31		/* 以字符串的方式保存读出的结果 */
32		QString styleSheet = QLatin1String(file.readAll());
33		/* 设置全局样式 */
34		qApp->setStyleSheet(styleSheet);
35		/* 关闭文件 */
36		file.close();
37		}
38
39		Widget w;
40		w.show();
41		return a.exec();
42	}
  • 为了解决当程序运行在arm架构系统时,中文显示文乱码问题,根据从.pro获得的宏QT_ARM_PLATFORM作为编译条件,判断如果系统运行在arm架构,则程序包含文本字符串转换,解决Qt4中文乱码问题。

  • 第 24 行至 37 行,读取 style.qss 的内容。并设置全局样式。

6.4.3 修改 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QCheckBox>
#include <QButtonGroup>
#include <QLabel>
#include <QHBoxLayout>
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    QCheckBox *tristateCheckbox;
    QCheckBox *multiSelectCheckbox1;
    QCheckBox *multiSelectCheckbox2;
    QButtonGroup *multiSelectButtonGroup;
    QLabel *label1;
    QLabel *label2;
    QHBoxLayout *layout1;
    QHBoxLayout *layout2;
    QVBoxLayout *layout;
    void createTristateCheckbox();
    void createMultiSelectCheckboxes();

private slots:
    void connectSignalsAndSlots();
    void tristateCheckboxChanged(int);
    void onButtonClicked(int id);
    void multiSelectCheckboxChanged(int id, bool checked);
};
#endif // WIDGET_H

6.4.4 修改 widget.cpp

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    /* 主窗体设置位置和显示的大小及背景颜色 */
    this->setGeometry(0, 0, 800, 480);
    /*将主窗口背景色设置为天蓝色(不透明度为 100%)*/
    this->setStyleSheet("Widget {background-color: rgba(135, 206, 235, 100%);}");
    /* 实例化对象 */
    createTristateCheckbox();
    createMultiSelectCheckboxes();
    layout1 = new QHBoxLayout;
    layout2 = new QHBoxLayout;
    layout = new QVBoxLayout;
    layout1->addWidget(label1);
    layout1->addWidget(tristateCheckbox);
    layout2->addWidget(label2);
    layout2->addWidget(multiSelectCheckbox1);
    layout2->addWidget(multiSelectCheckbox2);
    layout->addLayout(layout1);
    layout->addLayout(layout2);
    setLayout(layout);
    connectSignalsAndSlots();
    setWindowTitle("_qcheckbox Example");

}

Widget::~Widget()
{
}

void Widget::createTristateCheckbox()
{
    tristateCheckbox = new QCheckBox("三态复选框:半选中", this);
    tristateCheckbox->setTristate(true);
    tristateCheckbox->setCheckState(Qt::PartiallyChecked);
    tristateCheckbox->setTristate(true);
    label1 = new QLabel(this);
    label1->setText("          第一组:");

}

void Widget::createMultiSelectCheckboxes()
{
    multiSelectCheckbox1 = new QCheckBox("多选框1:选中", this);
    multiSelectCheckbox2 = new QCheckBox("多选框2:未选中", this);
    multiSelectCheckbox1->setCheckState(Qt::Checked);
    multiSelectCheckbox2->setCheckState(Qt::Unchecked);
    multiSelectButtonGroup = new QButtonGroup(this);
    multiSelectButtonGroup->addButton(multiSelectCheckbox1);
    multiSelectButtonGroup->addButton(multiSelectCheckbox2);
    multiSelectButtonGroup->setExclusive(false);//多选
    label2 = new QLabel(this);
    label2->setText("          第二组:");

}
void Widget::connectSignalsAndSlots()
{
    connect(tristateCheckbox, SIGNAL(stateChanged(int)), this, SLOT(tristateCheckboxChanged(int)));

#ifdef QT_ARM_PLATFORM
    connect(multiSelectButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(onButtonClicked(int)));//Qt4
#else
    connect(multiSelectButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(multiSelectCheckboxChanged(int,bool)));//Qt5

#endif

}

void Widget::tristateCheckboxChanged(int state)
{
    qDebug() << "三态复选框状态:" << state;

    /* 判断checkBox的state状态,设置checkBox的文本 */
    switch (state) {
    case Qt::Checked:
        /* 选中状态 */
        tristateCheckbox->setText("三态复选框:选中");
        break;
    case Qt::Unchecked:
        /* 未选中状态 */
        tristateCheckbox->setText("三态复选框:未选中");
        break;
    case Qt::PartiallyChecked:
        /* 半选状态 */
        tristateCheckbox->setText("三态复选框:半选中");
        break;
    default:
        break;
    }

}

void Widget::onButtonClicked(int id)//Qt4
{
    QCheckBox *checkbox = qobject_cast<QCheckBox *>(multiSelectButtonGroup->button(id));
    int checked = checkbox->isChecked();
    qDebug() << "多选框" << id + 1 << " 的状态是 " << checked;
    if(checkbox==multiSelectCheckbox1)
    {
        if (checked) {
            /* 选中状态 */
            multiSelectCheckbox1->setText("多选框1:选中");
            qDebug() << checkbox->text() << "is checked.";

        } else {
            multiSelectCheckbox1->setText("多选框1:未选中");
            qDebug() << checkbox->text() << "is unchecked.";
        }
    }
    else
    {
        if (checked) {
            /* 选中状态 */
            multiSelectCheckbox2->setText("多选框2:选中");
            qDebug() << checkbox->text() << "is checked.";

        } else {

            multiSelectCheckbox2->setText("多选框2:未选中");
            qDebug() << checkbox->text() << "is unchecked.";
        }
    }
}

void Widget::multiSelectCheckboxChanged(int id, bool checked)//Qt5
{
    QCheckBox *checkbox = qobject_cast<QCheckBox *>(multiSelectButtonGroup->button(id));
    qDebug() << "多选框 " << id + 1 << " 的状态是 " << checked;
    if(checkbox==multiSelectCheckbox1)
    {
        if (checked) {
            /* 选中状态 */
            multiSelectCheckbox1->setText("多选框1:选中");
            qDebug() << checkbox->text() << "is checked.";

        } else {

            multiSelectCheckbox1->setText("多选框1:未选中");
            qDebug() << checkbox->text() << "is unchecked.";
        }
    }
    else
    {
        if (checked) {
            /* 选中状态 */
            multiSelectCheckbox2->setText("多选框2:选中");
            qDebug() << checkbox->text() << "is checked.";

        } else {

            multiSelectCheckbox2->setText("多选框2:未选中");
            qDebug() << checkbox->text() << "is unchecked.";
        }
    }

}

6.5 切换Kit,获得运行在不同系统中的运行的执行文件

点击窗口左边的Debug,可以选择编译运行在不同平台上的可执行文件,arm-v7为arm架构的设备,使用Qt4库,而桌面则是当前ubuntu系统,使用Qt5。
Qt5编译完成的可执行程序_qcheckbox,存放在项目目录的build-_qcheckbox-unknown-Debug/文件夹下,Qt4编译完成的可执行程序_qcheckbox,存放在项目目录的build-_qcheckbox-arm_v7-Debug/文件夹下。

6.6 程序中的qt机制

6.6.1 QButtonGroupbuttonToggledbuttonClicked信号

QButtonGroup 是一个辅助类,主要用于创建互斥或多选的逻辑按钮组。可以将一组单选按钮或复选框等逻辑相关的按钮放在同一个 QButtonGroup 对象中,并设置该组为互斥或多选。当该组中选择某个按钮时,其他按钮会自动按照设置改变或不改变。
buttonToggled信号是 Qt5 为QButtonGroup 类增加的一个信号,以便更好地支持多选按钮组(multi-selection button group)。在Qt5中,buttonToggled 信号会返回两个参数:选中的按钮对应的QAbstractButton*指针和其新的选中状态checked。这使基于多状态(如三态复选框)或分组(多个单选按钮)的动作变得更加简单。
在 Qt4 中,QButtonGroup 没有 buttonToggled 信号,只能使用buttonClicked信号来检测组中按钮的状态更改。
在我们上面的程序中,使用条件编译体现了Qt4和Qt5编程的不同:

#ifdef QT_ARM_PLATFORM
    connect(multiSelectButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(onButtonClicked(int)));
#else
    connect(multiSelectButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(multiSelectCheckboxChanged(int,bool)));

#endif

6.6.2 QAbstractButton 类

QAbstractButton 类是 Qt 按钮相关类的基类,它是一个抽象类,也就是说无法直接实例化。QAbstractButton 提供了一些共性的概念和方法,具有以下作用:

  • 按钮状态控制:维护按钮的不同状态,如正常、选中和按下等状态。
  • 选中控制:用于实现单选和多选等功能。
  • 内置图像控制:按钮可以包含或显示图像、标签。
  • 信号和槽机制:发射信号以响应用户输入或响应代码变化等。
  • 焦点控制:按钮可以接受键盘输入的焦点,并根据用户输入的快捷键来激活信号。
    如果我们需要自定义一种新的按钮,一般可以继承 QAbstractButton 类,并实现一些虚函数,以便根据实际需要提供更丰富的功能。
    QAbstractButton 类在 Qt5 中相比 Qt4,最主要的改进就是引入了一组新的虚函数用于事件处理和样式表适配等方面的扩展。

总结

本文介绍QT常用控件的第四个按钮,QCheckBox 按钮编程。通过这个例子,进一步巩固QT管理资源机制知识和使用样式表进行外观设置;学习QCheckBox 复选框的三态功能和如何使用 QButtonGroup分组管理QCheckBox 复选框 ,演示了如何在一个组内实现按钮的多选。文章中使用的例程和内容都是在chatgpt的帮助下完成的,并分别在ubuntu22.04系统(Qt5)和 ARM架构设备中亲测有效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值