【Qt常用控件】控件概述和QWidget 核心属性

文章目录

  • [1. 控件概述](#1. 控件概述)
  • [2. QWidget 核心属性](#2. QWidget 核心属性)
    • [2.1 enabled](#2.1 enabled)
    • [2.2 geometry](#2.2 geometry)
    • [2.3 windowTitle](#2.3 windowTitle)
    • [2.4 windowIcon](#2.4 windowIcon)
    • [2.5 windowOpacity](#2.5 windowOpacity)
    • [2.6 cursor](#2.6 cursor)
    • [2.7 font](#2.7 font)
    • [2.8 toolTip](#2.8 toolTip)
    • [2.9 focusPolicy](#2.9 focusPolicy)
    • [2.10 styleSheet](#2.10 styleSheet)

1. 控件概述

Widget 是 Qt 中的核心概念,英文原义是 "小部件/小组件",我们此处也把它翻译为 "控件" .

控件是构成一个图形化界面的基本要素.

像上述示例中的,按钮, 列表视图, 树形视图, 单行输入框, 多行输入框, 滚动条, 下拉框等, 都可以称为 "控件".

Qt 作为一个成熟的 GUI 开发框架, 内置了大量的常用控件. 这一点在 Qt Designer 中就可以看到端倪,并且 Qt 也提供了 "自定义控件" 的能力, 可以让程序猿在现有控件不能满足需求的时候, 对现有控件做出扩展, 或者手搓出新的控件.

综上, 学习 Qt, 其中一个很重要的任务就是熟悉并掌握 Qt 内置的常用控件,这些控件对于我们快速开发出符合需求的界面, 是至关重要的.

关于控件体系的发展

控件是 GUI 开发中的通用概念,不仅仅局限在 Qt 中.

第一阶段:

完全没有控件,此时需要通过一些绘图 API 手动的绘制出按钮或者输入框等内容, 代码编写繁琐.

例如文曲星的 Lava 平台开发

第二阶段:

只包含粗略的控件. 只是提供了按钮, 输入框, 单选框, 复选框等最常用的控件.

例如 html 的原生控件.

第三阶段:

更完整的控件体系, 基本可以覆盖到 GUI 开发中的大部分场景.

例如早期的 MFC, VB, C++ Builder, Qt, Delphi, 后来的 Android SDK, Java FX, 前端的各种 UI 库等.

上图是 前端中 的 Element-ui 中的控件概览, 无论是丰富程度还是颜值, 都比 Qt 自带的控件更胜一筹.


2. QWidget 核心属性

在 Qt 中, 使用 QWidget 类表示 "控件". 像按钮, 视图, 输入框, 滚动条等具体的控件类, 都是继承自QWidget.

可以说, QWidget 中就包含了 Qt 整个控件体系中, 通用的部分

在 Qt Designer 中, 随便拖一个控件过来, 选中该控件, 即可在右下方看到 QWidget 中的属性

这些属性既可以通过 QtDesigner 会直接修改, 也可以通过代码的方式修改.

这些属性的具体含义, 在 Qt Assistant 中均有详细介绍.

在 Qt Assistant 中搜索 QWidget, 即可找到对应的文档说明. (或者在 Qt Creator 代码中, 选中 QWidget, 按 F1 也可).

这些属性不需要大家每个都去了解,只需要认识其中的一些常用的,重要的属性即可.


2.1 enabled

enabled 描述了一个控件是否处于 "可用" 状态

API 说明
isEnabled() 获取到控件的可用状态.
setEnabled() 设置控件是否可使用,true 表示可用, false 表示禁用.
  • 所谓 "禁用" 指的是该控件不能接收任何用户的输入事件,并且外观上往往是灰色的.
  • 如果一个 widget 被禁用,则该 widget 的子元素也被禁用.

代码示例: 使用代码创建一个禁用状态的按钮

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QPushButton* button = new QPushButton(this);
    button->setText("按钮");
    // 按钮就处于禁用状态了.
    button->setEnabled(false);

    connect(button, &QPushButton::clicked, this, &Widget::handle);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handle()
{
    qDebug() << "handle";
}

运行结果:


2.2 geometry

位置和尺寸,其实是四个属性的统称:

  • x 横坐标
  • y 纵坐标
  • width 宽度
  • height 高度

但是实际开发中, 我们并不会直接使用这几个属性, 而是通过一系列封装的方法来获取/修改.

对于 Qt 的坐标系, 不要忘记是一个 "左手坐标系". 其中坐标系的原点是当前元素的父元素的左上角.

API 说明
geometry() 获取到控件的位置和尺寸. 返回结果是一个 QRect, 包含了 x, y, width, height. 其中 x, y 是左上角的坐标.
setGeometry(QRect) setGeometry(int x, int y, int width, int height) 设置控件的位置和尺寸,可以直接设置一个 QRect, 也可以分四个属性单独设置.

Qt 中针对一些几何上的概念也进行了封装~~

  • QPoint 表示一个点
  • QRect 表示一个矩形

属于是小对象,里面的属性非常少,占用空间也小.

C++中使用上述对象,通常就会按照值的方式来传递参数了

move 只是修改位置,setGeometry 既可以修改位置,又可以修改尺寸~~

代码示例: 控制按钮的位置

在界面中拖五个按钮,五个按钮的 objectName 分别为 pushButton_target , pushButton_up , pushButton_down , pushButton_left , pushButton_right ,五个按钮的初始位置和大小都随意.

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_up_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
    rect.setY(rect.y() - 5);
    ui->pushButton_target->setGeometry(rect);
}

void Widget::on_pushButton_left_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
    rect.setX(rect.x() - 5);
    ui->pushButton_target->setGeometry(rect);
}

void Widget::on_pushButton_down_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
    rect.setY(rect.y() + 5);
    ui->pushButton_target->setGeometry(rect);
}

void Widget::on_pushButton_right_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
    rect.setX(rect.x() + 5);
    ui->pushButton_target->setGeometry(rect);
}

运行结果:

当前代码实际执行的效果,是在调整左上角位置,左上角位置改变的同时,高度和宽度也同时发生了改变~~

如果想要让这个按钮能够平移. (宽度高度不变,整个按钮的位置都发生改变)怎么做

刚才的代码,修改的是 QRect 对象的 x 和 y,这样的修改就会使 QRect 宽度高度发生改变~~

如何才能实现"平移"的效果,保持尺寸不变,整个按钮位置变化?

不再修改QRect,而是通过QRect 基于setGeometry第二个版本的函数重新设置位置即可.

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_up_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
//    rect.setY(rect.y() - 5);
//    ui->pushButton_target->setGeometry(rect);
    ui->pushButton_target->setGeometry(rect.x(), rect.y()-5, rect.width(), rect.height());
}

void Widget::on_pushButton_left_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
//    rect.setX(rect.x() - 5);
//    ui->pushButton_target->setGeometry(rect);
    ui->pushButton_target->setGeometry(rect.x()-5, rect.y(), rect.width(), rect.height());
}

void Widget::on_pushButton_down_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
//    rect.setY(rect.y() + 5);
//    ui->pushButton_target->setGeometry(rect);
    ui->pushButton_target->setGeometry(rect.x(), rect.y()+5, rect.width(), rect.height());
}

void Widget::on_pushButton_right_clicked()
{
    QRect rect = ui->pushButton_target->geometry();
//    rect.setX(rect.x() + 5);
//    ui->pushButton_target->setGeometry(rect);
    ui->pushButton_target->setGeometry(rect.x()+5, rect.y(), rect.width(), rect.height());
}

运行结果:

window frame 的影响

如果 widget 作为一个窗口 (带有标题栏,最小化,最大化, 关闭按钮), 那么在计算尺寸和坐标的时候就有两种算法. 包含 window frame 和 不包含 window frame.

其中 x(), y(), frameGeometry(), pos(), move() 都是按照包含 window frame 的方式来计算的.

其中 geometry(), width(), height(), rect(), size() 则是按照不包含 window frame 的方式来计算的.

当然, 如果一个不是作为窗口的 widget , 上述两类方式得到的结果是一致的.

代码示例:感受 geometry 和 frameGeometry 的区别.

  1. 在界面上放置一个按钮.
  1. 在按钮的 slot 函数中, 编写代码
cpp 复制代码
void Widget::on_pushButton_clicked()
{
    QRect rect1 = this->geometry();
    QRect rect2 = this->frameGeometry();
    qDebug() << rect1;
    qDebug() << rect2;
}
  1. 在构造函数中, 也添加同样的代码
cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
    QRect rect1 = this->geometry();
    QRect rect2 = this->frameGeometry();
    
    qDebug() << rect1;
    qDebug() << rect2;
}

执行程序, 可以看到, 构造函数中, 打印出的 geometry 和 frameGeometry 是相同的,但是在点击按钮时, 打印的 geometry 和 frameGeometry 则存在差异

注意:

在构造方法中, Widget 刚刚创建出来, 还没有加入到对象树中. 此时也就不具备 Window frame.

在按钮的 slot 函数中, 由于用户点击的时候, 对象树已经构造好了, 此时 Widget 已经具备了 Window frame, 因此在位置和尺寸上均出现了差异.

如果把上述代码修改成打印 pushButton 的 geometry 和 frameGeometry , 结果就是完全相同的. 因为 pushButton 并非是一个窗口


2.3 windowTitle

API 说明
windowTitle() 获取到控件的窗口标题.
setWindowTitle(const QString& title) 设置控件的窗口标题.

注意! 上述设置操作针对不同的 widget 可能会有不同的行为.

如果是顶层 widget (独立窗口),这个操作才会有效;如果是子 widget, 这个操作无任何效果

代码示例: 设置窗口标题

修改 widget.cpp

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 设置窗⼝标题
    this->setWindowTitle("这是标题");
}

运行结果:


2.4 windowIcon

windowIcon 表示窗口的图标

API 说明
windowIcon() 获取到控件的窗口图标. 返回 QIcon 对象.
setWindowIcon(const QIcon& icon) 设置控件的窗口图标.

同 windowTitle, 上述操作仅针对顶层 widget 有效

Qt 把各种涉及到的相关概念都封装成了类,Qlcon 就表示一个图标.

代码示例:设置窗口图标

首先准备一张图片放在D盘

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QIcon>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QIcon icon("D:/Qt.jpeg");
    setWindowIcon(icon);
}

Widget::~Widget()
{
    delete ui;
}

运行结果:

在任务栏中也能看到

之前推荐使用堆来创建对象,主要是因为要确保当前的控件的生命周期是足够的,要通过 Qt 对象树来释放对象,Qlcon 自身是一个比较小的对象,创建出来之后就是要设置到某个 QWidget 里面,Qlcon 对象本身释放不释放,不影响图标最终的显示.

Qlcon 也不支持对象树,无法给他执行父对象.

通过绝对路径的方式引入图片是不科学的,你写的程序,最终是要发布到用户的电脑上的,你无法确保,你开发机上图片的路径和用户电脑上图片的路径完全一致

因此,相比于使用绝对路径的方式,使用相对路径是更好的~~相对路径,是以给定目录为基准,以.或者 ... 的方式开头

假设基准目录是 D:/

  • 给定相对路径 ./Qt.jpeg => 在基准目录(D:/) 直接找 Qt.jpeg
  • 给定的相对路径是./image/Qt.jpeg => 在基准目录中,先找到 image 目录, 再在里面找到 Qt.jpeg

如果,咱们这个电脑是把 图片放到 D:上,有可能人家用户电脑上只有一个C盘,没有D盘

这个时候就需要提到 qrc 机制.

这个机制就是从根本上解决上述的两个问题:

  1. 确保你的图片所在的路径在目标用户机器上存在
  2. 确保你的图片不会被用户搞没了~~

给 Qt 项目引入一个额外的 xml 文件(后缀名使用 .qrc 表示),在这个xml中把要使用的图片资源给导入进来,并且在xml中进行记录.

Qt 在编译项目的时候,就会根据 qrc 中描述的图片信息,找到图片内容,并且提取出图片的二进制数据,把这些二进制数据转成C++代码.最终编译到exe 里.

qrc 缺点:无法导入太大的资源文件,比如搞几个 GB 这种视频文件,qrc 无能为力了~~

Android 中也有类似的机制~~

qrc 使用的方式

  1. 在项目中创建一个 qrc 文件,文件名不要带中文和特殊符号.

输入名称,不要带中文和特殊符号

  1. 把图片导入到 qrc 文件中.
  • 先创建一个"前缀"(Prefix)

所谓的"前缀"可以理解成虚拟的目录,这个目录没有在你的电脑上真实存在,是 Qt 自己抽象出来的,qrc 机制本质上就是把 图片 的二进制数据转成 C++ 代码.(最终就会在代码中看到很大的 char 数组,里面就是图片的二进制数据)

为了方便 Qt 代码中访问到这个图片,Qt 就自己抽象出了 虚拟的目录~~

把 prefix 的名字就改成 /即可~~

  • 把刚才使用 rose.jpg 这个图片给导入到 资源文件 中.

这个按钮在创建 prefix 之前是禁用的,创建好 prefix 之后就可以使用了,添加的文件就是添加到 prefix 下面的,点击 add Files 得到的目录就是当前代码所在的目录~~

导入图片的时候,需要确保你导入的图片必须在 resource.qrc 文件的同级目录,或者同级目录中的子目录里~~

因此,就可以把 Qt.jpeg 拷贝到当前项目目录中即可~~

看到上图这个效果,说明导入成功了!!!

创建的前缀叫啥名字,代码中就写啥名字,前缀+ 文件名

当代码中需要访问 qrc 中管理的文件时,就需要在路径上带有 : 前缀~~

运行结果:

打开所在目录,进入build-xxx目录中,进入debug目录,qrc 中导入的图片资源,就会被转成这个 qrc_resource.cpp 这个 c++ 代码.

这里的字节内容就是Qt.jpeg里的每个字节的数据~

当 Qt 项目进行编译的时候,这个 cpp 文件就被一起编译到了 exe 中,当 exe 程序运行的时候,上述图片的数据也就被加载到内存中了。


2.5 windowOpacity

API 说明
windowOpacity() 获取到控件的不透明数值。返回 float, 取值为 0.0 -> 1.0,其中 0.0 表示全透明, 1.0 表示完全不透明.
setWindowOpacity(float n) 设置控件的不透明数值.

代码示例: 调整窗口透明度

在界面上拖放两个按钮,分别用来增加不透明度和减少不透明度,objectName 分别为 pushButton_add 和 pushButton_sub

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_add_clicked()
{
    float opacity = this->windowOpacity();
    if(opacity >= 1.0)
    {
        return;
    }
    opacity += 0.1;
    qDebug() << opacity;
    this->setWindowOpacity(opacity);
}



void Widget::on_pushButton_sub_clicked()
{
    float opacity = this->windowOpacity();
    if(opacity <= 0.0)
    {
        return;
    }
    opacity -= 0.1;
    qDebug() << opacity;
    this->setWindowOpacity(opacity);
}

运行结果:

两个问题:

  1. 窗口的不透明度,变化并非是精确的!

这就要提到浮点数在内存中的存储了

IEEE 754 标准规定了浮点数要使用二进制科学计数法 的方式来表示~~

把一个浮点数分成三个部分:

1)符号位

2)有效数字

  1. 指数部分

使用二进制表示的有效数字~~而且这里是小于0的小数部分(默认整数部分是 1)

第一个有效数字位表示0.5

第二个有效数字位表示0.25

第三个表示 0.125

...

101 => 0.625

由于 float 和 double 有效数字部分长度都是有限的~~导致无法凑出一个非常非常接近0.1 这样的数字~

很多编程语言.C/C++, Java, Python, Go...都是这套体系~~

优点:运算速度快,占用空间小(CPU制造的时候针对这种运算专门优化的)

缺点:对于有些小数无法精确表示~~

  1. 上述代码中,在进行设置之前,先判定了 opacity 的范围,然后再决定是否要设置,这个判定其实可以不写.为啥我们仍然要写上??

这里加了判定条件,实际上如果不加这样的条件,代码也是ok的,超过 1.0的数字设置不进去 (setWindowOpacity内部也进行了判定),不过最好还是加上,养成防御性编程的习惯


2.6 cursor

API 说明
cursor() 获取到当前 widget 的 cursor 属性,返回 QCursor 对象。当鼠标悬停在该 widget 上时, 就会显示出对应的形状.
setCursor(const QCursor& cursor) 设置该 widget 光标的形状,仅在鼠标停留在该 widget 上时生效.
QGuiApplication::setOverrideCursor(const QCursor& cursor) 设置全局光标的形状. 对整个程序中的所有 widget 都会生效. 覆盖上面的 setCursor 设置的内容.

代码示例:在 Qt Designer 中设置按钮的光标

在界面中创建一个按钮.

直接在右侧属性编辑区修改 cursor 属性为 "等待"

运行结果:

我们也可以通过代码的方式来实现

其中 Qt::WaitCursor 就是自带的"等待"形状的光标.

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QCursor cursor(Qt::WaitCursor);
    ui->pushButton->setCursor(cursor);
}

Widget::~Widget()
{
    delete ui;
}

运行结果:

系统内置的光标形状如下:

Ctrl + 左键 点击 Qt::WaitCursor 跳转到源码即可看到.

这些都是Qt 中内置的光标形状~~

Qt 也允许我们通过自定义的图片来设置光标~~

先准备一个图片,把图导入到项目中 (qrc 管理)

在代码中访问到这个图片,基于这个图片构造出光标对象并设置~~

编写 widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 访问到图片文件
    QPixmap pixmap(":/huaji.jpg");
    // 还可以对光标进行缩放
    pixmap = pixmap.scaled(100, 100);
    // 构造光标对象
    QCursor cursor(pixmap, 10, 10);
    // 把光标设置进去
    setCursor(cursor);
}

Widget::~Widget()
{
    delete ui;
}

QPixmap 通过这个对象就表示一个图片

QCursor cursor(pixmap);

这个默认情况下,鼠标点击时,相当于图片的左上角在进行点击~~

QCursor cursor(pixmap, 10, 10);

指定热点(10,10) 所在的位置

以图片左上角为 0,0原点,找到 10,10这个位置作为鼠标真正点击的位置.

运行结果:

注意:pixmap = pixmap.scaled(100, 100);

通过这个函数对图片进行缩放,注意缩放不是修改图片对象本身,而是返回一个新的图片对象副本~~

这里推荐一个网站------阿里巴巴矢量库,里面的图标都是可以免费下载的


2.7 font

API 说明
font() 获取当前 widget 的字体信息. 返回 QFont 对象.
setFont(const QFont& font) 设置当前 widget 的字体信息.

关于 QFont

属性 说明
family 字体家族. 比如 "楷体", "宋体", "微软雅黑" 等.
pointSize 字体大小
weight 字体粗细. 以数值方式表示粗细程度取值范围为 [0, 99], 数值越大, 字体越粗.
bold 是否加粗. 设置为 true, 相当于 weight 为 75. 设置为 false 相当于 weight 为 50.
italic 是否倾斜
underline 是否带有下划线
strikeOut 是否带有删除线

代码示例:在 Qt Designer 中设置字体属性

在界面上创建一个 label

在右侧的属性编辑区, 设置该 label 的 font 相关属性

在这里调整上述属性, 可以实时的看到文字的变化

运行结果:

通过属性编辑这样的方式,虽然能够快速方便的修改文字相关的属性,但是还不够灵活如果程序运行过程中,需要修改文字相关的属性~~就需要通过代码来操作了

代码示例:在代码中设置字体属性

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QLabel>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QLabel* label = new QLabel(this);
    label->setText("这是一段文本");
    
    // 创建字体对象
    QFont font;
    font.setFamily("仿宋");
    font.setPixelSize(20);
    font.setBold(true);
    font.setItalic(true);
    font.setUnderline(true);
    font.setStrikeOut(true);
    
    // 把 font 对象设置到 label 中
    label->setFont(font);
}

Widget::~Widget()
{
    delete ui;
}

运行结果:

实际开发中, 字体属性如何选择, 是一个 "审美问题", 而不是 "技术问题". 往往需要有一定的艺术细胞。幸运的是,公司中往往有专业的 "美工" / "设计" 这样的岗位, 去做这方面的工作. 咱们程序员只要按照人家给的设计稿, 把代码写出来即可. 不必过多考虑怎样搭配才好看的问题.


2.8 toolTip

一个 GUI程序,界面比较复杂,按钮啥的很多~当你把鼠标悬停到这个控件上的时候,就能弹出一个提示~

API 说明
setToolTip 设置 toolTip。 鼠标悬停在该 widget 上时会有提示说明.
setToolTipDuring 设置 toolTip 提示的时间. 单位 ms。 时间到后 toolTip 自动消失.

toolTip 只是给用户看的. 在代码中一般不需要获取到 toolTip.

代码示例:设置按钮的 toolTip

在界面上拖放两个按钮. objectName 设置为 pushButton_yes 和 pushButton_no

编写 widget.cpp

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->pushButton_yes->setToolTip("这是一个 yes 按钮");
    ui->pushButton_yes->setToolTipDuration(3000);
    
    ui->pushButton_no->setToolTip("这是一个 no 按钮");
    ui->pushButton_no->setToolTipDuration(1000);
}

Widget::~Widget()
{
    delete ui;
}

运行结果:


2.9 focusPolicy

设置控件获取到焦点的策略,比如某个控件能否用鼠标选中或者能否通过 tab 键选中.

所谓 "焦点" , 指的就是能选中这个元素,接下来的操作 (比如键盘操作),就都是针对该焦点元素进行的了. 这个对于 输入框, 单选框, 复选框等控件非常有用的.

一般来说,一个控件获取到焦点,主要是两种方式

  1. 鼠标点击
  2. 键盘的 tab
API 说明
focusPolicy() 获取该 widget 的 focusPolicy, 返回 Qt::FocusPolicy
setFocusPolicy(Qt::FocusPolicy policy) 设置 widget 的 focusPolicy

Qt::FocusPolicy 是一个枚举类型. 取值如下

  • Qt::NoFocus :控件不会接收键盘焦点
  • Qt::TabFocus :控件可以通过Tab键接收焦点
  • Qt::ClickFocus :控件在鼠标点击时接收焦点
  • Qt::StrongFocus :控件可以通过Tab键和鼠标点击接收焦点 (默认值)
  • Qt::WheelFocus : 类似于 Qt::StrongFocus , 同时控件也通过鼠标滚轮获取到焦点 (新增的选项, 一般很少使用)

代码示例:理解不同的 focusPolicy

在界面上创建四个单行输入框 (Line Edit)

修改四个输入框的 focusPolicy 属性为 Qt::StrongFocus (默认取值, 一般不用额外修改)

运行结果:

修改第二个输入框的 focusPolicy 为 Qt::NoFocus , 则第二个输入框不会被 tab / 鼠标左键选中.

运行结果:

此时这个输入框也就无法输入内容了.

修改第二个输入框 focusPolicy 为 Qt::TabFocus , 则只能通过 tab 选中, 无法通过鼠标选中.

运行结果:

修改第二个输入框 focusPolicy 为 Qt::ClickFocus , 则只能通过 tab 选中, 无法通过鼠标选中.

运行结果:


2.10 styleSheet

通过 CSS 设置 widget 的样式.

CSS (Cascading Style Sheets 层叠样式表) 本身属于网页前端技术,主要就是用来描述界面的样式.

所谓 "样式", 包括不限于 大小, 位置, 颜色, 间距, 字体, 背景, 边框等.

我们平时看到的丰富多彩的网页, 就都会用到大量的 CSS.

Qt 虽然是做 GUI 开发, 但实际上和 网页前端 有很多异曲同工之处. 因此 Qt 也引入了对于 CSS 的支持.

CSS 中可以设置的样式属性非常多. 基于这些属性 Qt 只能支持其中一部分, 称为 QSS (Qt Style Sheet),具体的支持情况可以参考 Qt 文档中 "Qt Style Sheets Reference" 章节.

此处只是进行一个简单的演示.

代码示例:设置文本样式

在界面上创建 label

编辑右侧的 styleSheet 属性, 设置样式

此处的语法格式同 CSS, 使用键值对的方式设置样式. 其中键和值之间使用 : 分割,键值对之间使用 ; 分割.

另外, Qt Designer 只能对样式的基本格式进行校验, 不能检测出哪些样式不被 Qt 支持. 比如 text-align: center 这样的文本居中操作, 就无法支持.

运行结果:

代码示例:实现切换夜间模式.

在界面上创建一个多行输入框 (Text Edit) 和两个按钮,objectName 分别为 pushButton_light 和 pushButton_dark

编写按钮的 slot 函数.

  • #333 是深色, 但是没那么黑.
  • #fff 是纯白色.
  • #000 是纯黑色.

使用在线调色板或者画图板, 都可以看到数字对应的颜色. 参考:在线调色板,调色板工具---在线工具

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_light_clicked()
{
    this->setStyleSheet("background-color: #f3f3f3");
    ui->textEdit->setStyleSheet("background-color: #fff; color: #000");
    ui->pushButton_light->setStyleSheet("color: #000");
    ui->pushButton_dark->setStyleSheet("color: #000");
}

void Widget::on_pushButton_dark_clicked()
{
    this->setStyleSheet("background-color: #333");
    ui->textEdit->setStyleSheet("background-color: #333; color: #fff");
    ui->pushButton_light->setStyleSheet("color: #fff");
    ui->pushButton_dark->setStyleSheet("color: #fff");
}

关于计算机中的颜色表示

计算机中使用 "像素" 表示屏幕上的一个基本单位(也就是一个发亮的光点).

每个光点都使用三个字节表示颜色, 分别是 R (red), G (green), B (blue) 一个字节表示 (取值范围是 0-255, 或者 0x00-0xFF),混合三种不同颜色的数值比例, 就能搭配出千千万万的颜色出来.

  • rgb(255, 0, 0) 或者 #FF0000 或者 #F00 表示纯红色.
  • rgb(0, 255, 0) 或者 #00FF00 或者 #0F0 表示纯绿色.
  • rgb(0, 0, 255) 或者 #0000FF 或者 #00F 表示纯蓝色.
  • rgb(255, 255, 255) 或者 #FFFFFF 或者 #FFF 表示纯白色.
  • rgb(0, 0, 0) 或者 #000000 或者 #000 表示纯黑色.

当然, 上述规则只是针对一般的程序而言是这么设定的. 实际的显示器, 可能有 8bit 色深或者 10bit 色深等, 实际情况会更加复杂.

运行结果:

以上就是一些主要的属性,当然除了我们上述介绍的这些属性还会有一些其他的属性,这里就不一一介绍了,我们可以在需要的时候去查看文档

相关推荐
故事和你912 小时前
sdut-程序设计基础Ⅰ-实验二选择结构(1-8)
大数据·开发语言·数据结构·c++·算法·优化·编译原理
温柔一只鬼.2 小时前
GUI学习——day2
java·开发语言·学习
yongui478342 小时前
离散偶极子近似(DDA)求解颗粒散射的MATLAB实现
开发语言·matlab
花哥码天下2 小时前
安装/卸载claude code和codex
开发语言·javascript·ecmascript
AsDuang2 小时前
Python 3.12 MagicMethods - 28 - __rsub__
开发语言·python
饕餮争锋3 小时前
Java泛型介绍
java·开发语言
飞Link3 小时前
告别复杂调参:Prophet 加法模型深度解析与实战
开发语言·python·数据挖掘
zh_xuan3 小时前
测试go语言函数和结构体
开发语言·golang
小龙报3 小时前
【算法通关指南:算法基础篇】二分算法: 1.A-B 数对 2.烦恼的高考志愿
c语言·开发语言·数据结构·c++·vscode·算法·二分