当前位置: 首页 > news >正文

QT-常用控件

目录

QWIDGET

QWIDGET-enable属性

window frame的影响

QWIDGET-windowtitle属性

QWIDGET-windowlcon属性(图标)

qrc的使用

QWIDGET-windowOpacity属性

QWIDGET-cursor属性

QWIDGET-font属性(字体)

QWIDGET-toolTip属性

QWIDGET-focusPolicy属性(焦点)

QWIDGET-styleSheet属性

按钮类

QWIDGET-QPush Button控件属性(按钮)

QWIDGET-QradioButton控件属性(单选按钮)

QWIDGET-QChaekBox控件属性(复选按钮)

显示类

QLCDNunber的属性(计算器)

QProgressBar的属性(进度条)

 QCalendarWidget(日历)

输入类

QLineEdit(单行输入框)

QTextEdit(多行输入框)

核心功能与信号

QCombo Box(下拉框)

核心方法

QSpin Box(数目微调框)

属性

信号

QDateTimeEdit(日期/时间微调框)

一、跨时区场景下的 “日期边界” 计算偏差

二、对 “无效日期” 的容错性不足

三、历史日期(历法变更前)的计算偏差

四、与 “时间戳” 计算的一致性问题

规避方案

QDial(旋钮)

QSlider(滑动条)

多元素类

QListWidget(纵向列表)

QTableWidget(表格)

QTreeWidget

容器类

QGroupBox

QTabWidget

布局类

QVBoxLayout(垂直)

QHBoxLayout(水平)

QGridBoxLayout(网格)

QFromLayout(表单)

QSpaceItem(空白段)


QWIDGET

QWIDGET-enable属性

表示一个控件是否处于可用状态,相对概念为禁用,所谓"禁用"指的是该控件不能接收任何用户的输入事件,并且外观上往往是灰色的,如果一个 widget 被禁用,则该 widget 的子元素也被禁用。

禁用效果:

QWIDGET-geometry属性(几何)

粗浅的理解为(x,y,width,height)四个属性的统称;

Qt 中针对一些几何上的概念也进行了封装。
QPoint 表示一个点,QRect 表示一个矩形,他们都属于是小对象, 里面的属性非常少,占用空间也小.C++中使用上述对象, 通常就会按照值的方式来传递参数了。

样例:我们期望点击对应的按钮来修改target对应的geometry。

控件函数操作操作:

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

平移效果代码:

window frame的影响

Qt 中存在多种用于处理窗口位置和尺寸的 API,且不同 API 基于的坐标系原点有所不同,同时在特定阶段调用这些 API 会有特殊表现:

  • 从坐标系和 API 本身来看,geometry() 与 setGeometry() 以 Widget 本体左上角为原点,不考虑窗口框架(Window frame);frameGeometry() 和 setFrameGeometry() 以窗口框架左上角为原点,会考虑窗口框架。
  • Widget::Widget(Qwidget*parent):OWidget(parent),ui(new Ui::widget)
    {ui->setupui(this);QRect rect1=this->geometry();ORect rect2=this->frameGeometry();qDebug()<< rect1;qDebug()<< rect2;}
    
  • 从代码运行阶段的情况来看,若在 Widget 类的构造函数中(此时 Widget 对象正在构造,还未被加入到窗口框架),直接针对 Widget 对象使用 geometry 和 frameGeometry 并通过 qDebug() 输出结果,能观察到二者返回的位置尺寸信息存在区别。
  • 进行链接并运行后,结果如下图所示:

QWIDGET-windowtitle属性

需要注意,下图使用方法并不正确。

关键问题:QPushButton 调用 setWindowTitle 无意义

setWindowTitle 是用于设置 ** 窗口(QWidget 及其顶层子类,如 QMainWindowQDialog 等)** 的标题,显示在窗口的标题栏上。

而 QPushButton 是 “按钮部件”,不是独立的窗口(它是依附于父窗口存在的子部件),调用 button->setWindowTitle("通过按钮设置窗口标题") 不会有任何效果 —— 按钮没有自己的 “标题栏” 来显示这个标题。

正确的逻辑(如果要通过按钮修改窗口标题)

应该在按钮的点击信号槽中,修改父窗口(或目标窗口)的标题。示例如下:

// 假设当前类是 QWidget 子类(如 MainWindow)
this->setWindowTitle("这是窗口标题");QPushButton* button = new QPushButton("按钮", this);
// 连接按钮的点击信号到自定义槽函数
connect(button, &QPushButton::clicked, this, [this]() {// 点击按钮时,修改“当前窗口”的标题this->setWindowTitle("通过按钮设置窗口标题");
});

这样,点击按钮时,整个窗口的标题栏才会更新为 “通过按钮设置窗口标题”。

总结

  • setWindowTitle 只对 “窗口级部件” 有效,子部件(如按钮、标签等)调用它不会生效。
  • 若要通过子部件(如按钮)修改窗口标题,需在子部件的交互逻辑中,操作目标窗口的 setWindowTitle

QWIDGET-windowlcon属性(图标)

Qt 把各种涉及到的相关概念,都封装成了 类,Qlcon 就表示一个图标,Qlcon 更推荐创建在栈上。

 // 写法一:使用双反斜杠QIcon icon("C:\\icons\\example.ico"); // 写法二:使用正斜杠// QIcon icon("C:/icons/example.ico"); 

假设图标文件 icon.png 和程序可执行文件在同一目录,直接写文件名即可:

QIcon icon("icon.png");

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

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

给 Qt 项目引入一个额外的 xml 文件(后缀名使用 .qrc 表示)在这个 xml 中把要使用的图片资源给导入进来,并自在 xml 中进行记录
Qt 在编译项目的时候,就会根据 qrc 中描述的图片信息, 找到图片内容, 并且提取出图片的二进制数据,把这些二进制数据转成 C++ 代码. 最终编译到 exe 里,

缺点:无法导入太大的文件。

qrc的使用

1.创建相应文件

2。导入文件资源

(1)创建虚拟目录-prefix;

(2)添加资源-点击add files;

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

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

QWIDGET-windowOpacity属性

上述代码可以充分体现该控件的功能。

在透明度变化过程中,变化并非是精确的。

C++浮点数运算不精确的核心原因是:二进制无法精确表示所有十进制小数,如同十进制无法精确表示1/3(0.333...),导致存储时就存在微小误差,运算后误差进一步累积。
 
这本质是“进制转换”和“有限存储”的双重限制:
 
- 二进制只能精确表示分母为2的幂的十进制小数(如0.5=1/2、0.25=1/4),像0.1(1/10)这类小数,在二进制中是无限循环小数,只能截取近似值存储。

- 浮点数(如float、double)在计算机中用固定字节存储,会对无限循环的二进制小数进行舍入,这就从根源上决定了它不是“精确值”,而是“近似值”。

QWIDGET-cursor属性

自定义的光标设置:图标网站推荐:阿里巴巴矢量图标库

光标尺寸的设计

QWIDGET-font属性(字体)

代码案例:

QWIDGET-toolTip属性

QWIDGET-focusPolicy属性(焦点)

QWIDGET-styleSheet属性

通过CSS设置widget的样式

1.qlabel设置文本

2.右下角属性栏,右键都可以跳转设置样式。

3.进行期望的属性编辑

设置日间模式,夜间模式:

按钮类

QWIDGET-QPush Button控件属性(按钮)

qpushbutton是一个按钮,继承自qabstractbutton,这是一个抽象类,是其他按钮控件的父类。qabstractbutton包含纯虚函数,无法创建出子类的示例,旧的创建子类,重写上述的纯虚函数,才能创建出子类的实例。

1.设置按钮图标

2.设置快捷键

准备工作

设置槽函数

快捷键设置-通过按键名-简单易出错

快捷键设置-通过枚举

键盘的连发是默认的。

QWIDGET-QradioButton控件属性(单选按钮)

示例:

还可以进行初始化,提供默认内容

该控件还可以将按钮进行分组,实现类似于点餐的一种效果

槽信号介绍

clicked(bool)中bool部分表示按钮是否被选中后触法。

pressed为点的动作后触发,鼠标没弹起来。

release是弹起后触发,鼠标要弹起来。

toggled是状态切换的时候触发。

QWIDGET-QChaekBox控件属性(复选按钮)

代码演示、

显示类

该属性常用于显示文本和图片。

格式:在设置文本的格式testformat后,不同文本之间语法是并不互通的,<b></b>用于html格式,#等用于markdowntest格式。

图片:

// 先把 QLabe1 设置成和窗口一样大,并且把这个 QLabel 左上角设置到窗口的左上角这里
// 让整个 QLabel 铺满整个窗口
ORect windowRect=this->geometry();
ui->label->setGeometry(0,0,windowRect.width(), windowRect.height());
QPixmap pixmap(":/huaji.png");
ui->label->setPixmap(pixmap);
//启动自动拉伸。此时图片就能够填充满整个窗口了.
ui->label->setscaledcontents(true);

仅仅只设置setGeometry是不能让图片填充满整个窗口的,因为图片本身可能有尺寸限制,需要用到ui->label->setscaledcontents(true);才行,但是拖拽边框后图片的样式 可能就不那么好看,会出现大量的空白。

解决方式:事件

用户的操作,会对应一些信号,Qt 中,表示用户的操作,有两类概念一个是信号,另一个是事件。
当用户拖拽修改窗口大小的时候,就会触发 resize 事件(resizeEvent)像 resize 这样的事件,是连续变化的.把窗口尺寸从 A拖到 B这个过程中,会触发出一系列的 resizeEvent此时就可以借resizeEvent 来完成上述的功能.,可以让 Widget 窗囗类, 重写父类(QWidget) 的 resizeEvent 虚函数
在鼠标拖动窗口尺寸的 过程中 这个函数就会被反复调用执行,每次触发一个 resizeEvent 事件都会调用一次对应的虚函数。

由于此处进行了函数重写,调用父类的虚函数就会实际调用到子类的对应的函数(多态)。

设置文本对齐:

设置伙伴:

Qt 中, QLabel 中写的文本,是可以指定"快捷键”此处快捷键的规则功能上要比 QPushButton 弱很多
是在文本中使用 & 跟上一个字符来表示快捷键。
比如 &A =>通过键盘上的 alt +a来触发这个快捷键.&B =>通过键盘上的 alt +b 来触发,绑定了伙伴关系之后,通过快捷键就可以选中对应的单选按钮/复选按钮。

QLCDNunber的属性(计算器)

定时器的设定:

方式一:

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置初始值ui->lcdNumber->display(10);// 创建一个 QTimer 实例timer = new QTimer(this);// 把 QTimer 的 timeout 信号和咱们自己的槽函数进行连接connect(timer,&QTimer::timeout, this,&Widget::handle);// 启动定时器,参数是触发 timeout 的周期,单位是 mstimer->start(1000);
}Widget::~Widget()
{delete ui;
}void Widget::handle()
{//先拿到 LCDNumber 中的数字int value =ui->lcdNumber->intValue();if(value<=0){// 数字减到 0 了,停止定时器.timer->stop();return;}ui->lcdNumber->display(value -1);
}

屏幕录制 2025-10-12 165432

方式二:

现象:是10s后弹出结果为0的显示框。

原因:

方式三;多线程

结果依然是失败的,Qt 里,(main 函数所在的线程)界面有一个专门的线程去负责维护更新的(主线程),对于 GU 来说,内部包含了很多的隐藏状态,Qt 为了保证修改界面的过程中,线程安全是不会受到影响的,Qt禁止了其他线程直接修改界面。

QProgressBar的属性(进度条)

进度条

下面我们来创建一份进度条,让他随时间增长而增长,每个0.1秒+1;

进度条:

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);timer=new QTimer(this);connect(timer,&QTimer::timeout,this,&Widget::handle);timer->start(100);
}
void Widget::handle()
{int value=ui->progressBar->value();if(value>=100){timer->stop();return;}ui->progressBar->setValue(++value);
}
Widget::~Widget()
{delete ui;
}

进度条样式的设计:

QProgressBar {border: 2px solid #ffb6c1; /* 粉色边框*/border-radius: 10px; /* 圆角,让进度条更柔和 */background-color: #fff0f5; /* 背景为浅粉色 */
}QProgressBar::chunk {border-radius: 8px; /* 进度块的圆角,和外框呼应 */background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #ff69b4, stop:1 #ff1493); /* 进度块用亮粉色渐变,很活泼 */
}

Qt 中利用类前置声明减少头文件包含,从而优化编译速度的知识:

核心要点

  1. 前置声明的作用:在 Qt 中,若只需使用类的指针 / 引用类型成员(如 QTimer* timer;),可通过类前置声明(如 class QTimer;),无需在头文件中直接包含 QTimer 的头文件(#include <QTimer>)。因为指针 / 引用的声明不需要知道类的完整定义,只需知道类的存在即可。

  2. 编译速度优化:C/C++ 编译速度慢,与 #include 头文件的复杂依赖关系直接相关。减少头文件包含能有效缩短编译时间。Qt 利用 “前置声明 + 仅在需要时包含头文件” 的方式,降低头文件间的依赖,从而优化编译效率。

  3. 实际开发的权衡:虽然前置声明能优化编译,但实际项目中,若为了开发便捷(避免手动管理头文件依赖),或项目有足够硬件资源(如大厂的 “编译集群”),也可直接包含所需头文件,优先保证开发效率。

简单来说:Qt 用 “类前置声明” 减少头文件包含来加速编译,但实际开发中,也可根据情况灵活选择是否直接包含头文件。

 QCalendarWidget(日历)

目的:期望日期改变时,Qlabel进行显示;

代码:

#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_calendarWidget_selectionChanged()
{QDate date=ui->calendarWidget->selectedDate();qDebug()<<date;ui->label->setText(date.toString());
}

输入类

QLineEdit(单行输入框)

代码目的:让用户输入个人信息,并进行获取。

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 初始化第一个输入框,用来输入姓名ui->lineEdit_name->setPlaceholderText("请输入姓名");ui->lineEdit_name->setClearButtonEnabled(true);// 初始化第二个输入框,用来输入密码ui->lineEdit_password->setPlaceholderText("请输入密码");ui->lineEdit_password->setClearButtonEnabled(true);// 把显示模式设置成显示密码的模式.ui->lineEdit_password->setEchoMode(QLineEdit::Password);// 初始化第三个输入框ui->lineEdit_phone->setPlaceholderText("请输入手机号码");ui->lineEdit_phone->setClearButtonEnabled(true);// 手机号码是有固定格式的. 此处的 0 代表 "数字"ui->lineEdit_phone->setInputMask("000-0000-0000");
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_submit_clicked()
{QString gender = ui->radioButton_male->isChecked() ? "男" : "女";qDebug() << "姓名: " << ui->lineEdit_name->text()<< "密码: " << ui->lineEdit_password->text()<< "性别: " << gender<< "电话: " << ui->lineEdit_phone->text();
}

ui->lineEdit_phone->setInputMask大的限制能力比较弱,如果不满足需求可以考虑使用正则表达式。

使用样例1:

//创建正则表达式

QRegExp regExp("^1\\d{10}$");

用户输入内容符合要求则可提交,否则eable=flase;

^n:表示以n开始

\\d{10}:表示必须重复10次出现数字,\d表示数字,\\进行转义,{10}表示进行重复10次操作;

$:结尾;

//创建验证器(验证正则表达式是否正确)

ui->lineEdit->setValidator(new QRegExpValidator(regExp));

我们期望的是内容发生改变时,时刻进行验证,看用户输入的内容是否符合要求,符合要求按钮可用,否则不可用。

因此我们需要用到行文本框的textChanged或者textEdited属性。

void Widget::on_lineEdit_textEdited(const QString &text)
{int pos=0;QString content=text;//调用验证器,并验证,返回值是枚举类型(通过/不通过)//验证通过if(ui->lineEdit->validator()->validate(content,pos)==QValidator::Acceptable){ui->pushButton->setEnabled((true));}else{ui->pushButton->setEnabled((false));}
}

在调用是需要注意传参,第一个参数是要验证的字符串第二个参数是错误出现时错误位置(int)

在函数传参是参数是const的,而调用传参是非const,因此不能直接调用待检测字符串,可以进行拷贝,我们也可以自定义进行重写,也可以调用QT封装的QRegExpValidator;

正则表达式的运用

仔细观察发现:

当数字串长度不满足11位时,按钮不可用,等于11时可用,且不可以超过11位。

使用样例2:验证两次输入密码一致:

使用样例3:复选框实现密码显示与隐式的切换

#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lineEdit->setEchoMode(QLineEdit::Password);
}Widget::~Widget()
{delete ui;
}void Widget::on_checkBox_toggled(bool checked)
{if(checked){ui->lineEdit->setEchoMode(QLineEdit::Normal);}else{ui->lineEdit->setEchoMode(QLineEdit::Password);}
}

QTextEdit(多行输入框)

QTextEdit 支持多行文本输入,还可进行富文本编辑,适用于备注、文章内容等大量文本输入场景

核心功能与信号

  • 多行输入:天然支持多行文本,用户可自由换行输入。
  • 富文本支持:能设置文本的字体、颜色、字号等样式,例如 ui->textEdit->setFontWeight(QFont::Bold) 可将文本设为粗体。
  • 文本变化信号textChanged 信号在文本内容发生改变时触发,可用于实时监控文本变化,如自动保存草稿等功能。
  • 内容获取与设置:通过 toPlainText() 获取纯文本内容,setPlainText(const QString &text) 设置纯文本内容;若需富文本操作,可使用 toHtml() 和 setHtml(const QString &html)

核心信号:

QCombo Box(下拉框)

核心方法

  • 添加选项addItem(const QString &text) 可添加单个选项,addItems(const QStringList &texts) 可批量添加多个选项。
  • 插入选项insertItem(int index, const QString &text) 能在指定索引位置插入选项。
  • 设置当前选项setCurrentIndex(int index) 或 setCurrentText(const QString &text) 可设置当前选中的选项。
  • 获取当前选项currentIndex() 获取当前选项的索引,currentText() 获取当前选项的文本内容。

核心信号:

样例:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <fstream>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 需要读取文件内容,把文件中的每一行读取出来,作为一个 ComboBox 的选项std::ifstream file("C:/Users/1/Desktop/config.txt");if (!file.is_open()) {qDebug() << "文件打开失败";return;}// 按行来读取文本内容.// getline 函数完成.std::string line;while (std::getline(file, line)) {// 取到的每一行内容,设置到下拉框中.ui->comboBox->addItem(QString::fromStdString(line));}file.close();
}Widget::~Widget()
{delete ui;
}

QSpin Box(数目微调框)

QSpinBox 用于输入整数,带有上下调节按钮,方便用户微调数值;若需输入浮点数,可使用 QDoubleSpinBox。

属性

  • 数值范围setRange(int min, int max) 设置数值的最小和最大值,限制输入范围。
  • 步长setSingleStep(int step) 设置点击上下按钮时数值的变化步长。
  • 初始值setValue(int val) 设置初始显示的数值。

信号

  • 数值变化信号valueChanged(int i) 在数值发生改变时触发,可用于联动其他控件或执行相应逻辑。

样例:选餐

// 初始化下拉菜单
ui->comboBox->addItem("麦辣鸡腿堡");
ui->comboBox->addItem("巨无霸");
ui->comboBox->addItem("培根蔬粹双层牛堡");ui->comboBox_2->addItem("中薯条");
ui->comboBox_2->addItem("麦乐鸡块");
ui->comboBox_2->addItem("麦辣鸡翅");ui->comboBox_3->addItem("雪碧");
ui->comboBox_3->addItem("可乐");// 针对 QSpinBox 的范围进行设置
ui->spinBox->setRange(1, 5);
ui->spinBox_2->setRange(1, 5);
ui->spinBox_3->setRange(1, 5);ui->spinBox->setValue(1);
ui->spinBox_2->setValue(1);
ui->spinBox_3->setValue(1);

QDateTimeEdit(日期/时间微调框)

样例:时间计算器(两份时间的间隔:多少天/多少小时)

void Widget::on_pushButton_clicked(bool checked)
{QDateTime days1=ui->dateTimeEdit->dateTime();QDateTime days2=ui->dateTimeEdit_2->dateTime();int days=days1.daysTo(days2);int secs=((days1.secsTo(days2))/3600)%24;qDebug()<<"相差"<<days<<"天"<<secs<<"时";
}

daysTo函数存在缺陷:

QT 中 QDate::daysTo() 方法用于计算两个日期之间的天数差,虽然在多数场景下表现正常,但存在以下几类缺陷或需要注意的局限性,在实际开发中需规避:

一、跨时区场景下的 “日期边界” 计算偏差

QDate 是纯日期类,不包含时区信息,仅基于 “年 - 月 - 日” 的数字逻辑计算天数差。若涉及跨时区的日期转换(如将 UTC 时间转为本地时间后计算),可能出现与预期不符的结果。

  • 示例:假设本地时区为东八区(UTC+8),若将 2024-05-01 00:00:00 UTC 转为本地时间是 2024-05-01 08:00:00再与本地时间 2024-05-01 07:00:00 对应的 QDate(均为 2024-05-01)计算 daysTo(),结果为 0,但实际时间差仅 23 小时(不足 1 天)。
  • 本质原因QDate 忽略时间戳的 “小时 - 分钟 - 秒” 部分,仅按日期字面量比较,跨时区场景下易因 “日期切换时刻” 的差异导致偏差。

二、对 “无效日期” 的容错性不足

若调用 daysTo() 的两个 QDate 对象中存在无效日期(如 2024-02-302024-13-01),方法不会报错,而是返回未定义的错误结果(可能为随机整数或固定值),且无法通过返回值判断计算是否有效。

  • 示例
    QDate invalidDate(2024, 2, 30); // 无效日期(2月无30日)
    QDate validDate(2024, 3, 1);
    int days = invalidDate.daysTo(validDate); // 结果未定义(可能为1或其他值,无意义)
    
  • 对比:QT 中 QDate::isValid() 可提前判断日期有效性,但 daysTo() 本身不做校验,需开发者手动前置处理,否则易引入隐性 Bug。

三、历史日期(历法变更前)的计算偏差

QDate 内部基于公历(格里高利历) 计算,但格里高利历并非全球同步启用(如中国 1912 年才正式采用,俄罗斯 1918 年启用)。若计算 “历法变更前的历史日期”(如 1900 年中国的日期),daysTo() 仍按格里高利历逻辑计算,与实际历史日期的天数差存在偏差。

  • 示例:1900 年中国实际使用农历 + 公历(清历),若用 QDate(1900, 1, 1).daysTo(QDate(1900, 1, 10)) 得到结果 9(格里高利历的 9 天),但实际历史中该时间段的 “天数统计方式” 可能不同,导致计算结果与历史事实不符。
  • 适用范围daysTo() 仅适用于 “格里高利历覆盖的时期和地区”,对历史研究、古日期计算等场景不适用,且无任何接口支持其他历法。

四、与 “时间戳” 计算的一致性问题

若需结合时间戳(QDateTime::toSecsSinceEpoch())计算天数差,daysTo() 的结果可能与 “时间戳差值换算的天数” 不一致,原因是前者忽略时间部分,后者基于 “24 小时 / 天” 的绝对时间差。

  • 示例

    cpp

    运行

    QDateTime dt1(2024, 5, 1, 23, 0, 0); // 5月1日23点
    QDateTime dt2(2024, 5, 2, 1, 0, 0);  // 5月2日1点
    // 1. QDate::daysTo() 结果
    int daysDate = dt1.date().daysTo(dt2.date()); // 1(日期差1天)
    // 2. 时间戳换算天数
    qint64 secDiff = dt2.toSecsSinceEpoch() - dt1.toSecsSinceEpoch();
    int daysTs = secDiff / (24 * 3600); // 0(仅2小时,不足1天)
    
  • 冲突场景:需精确按 “24 小时周期” 计算天数(如日志统计、计费周期)时,daysTo() 的 “日期字面量差” 会与实际时间差冲突,需改用 QDateTime::secsTo() 换算。

规避方案

  1. 跨时区 / 时间敏感场景:改用 QDateTime 并指定时区(如 QTimeZone::utc()),通过 secsTo() 计算秒差后换算天数(secDiff / 86400),确保基于绝对时间差计算。
  2. 无效日期校验:调用 daysTo() 前,必须用 QDate::isValid() 检查两个日期,无效时抛出异常或返回错误标识。
  3. 历史日期场景:若需支持非格里高利历,需集成第三方历法库(如 ICU),或自定义历法计算逻辑,避免直接使用 daysTo()
  4. 结果一致性验证:当同时使用 QDate 和 QDateTime 时,需明确计算逻辑(按日期字面量 vs 按绝对时间),避免混用导致数据矛盾。

解决方案:

void Widget::on_pushButton_clicked(bool checked)
{QDateTime days1=ui->dateTimeEdit->dateTime();QDateTime days2=ui->dateTimeEdit_2->dateTime();int secs=((days1.secsTo(days2))/3600)%24;int days=secs/86400;qDebug()<<"相差"<<days<<"天"<<secs<<"时";
}

QDial(旋钮)

样例:通过旋钮控制;窗口的不透明度

void Widget::on_dial_valueChanged(int value)
{qDebug()<<value;this->setWindowOpacity(value/100);
}

QSlider(滑动条)

样例:改变窗口大小(水平+垂直)

#include "widget.h"
#include "ui_widget.h"// Widget类的构造函数,用于初始化界面组件
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)  // 初始化UI对象
{ui->setupUi(this);  // 设置UI界面// 配置水平滑块:最小值100、最大值2000、初始值800、步长50ui->horizontalSlider->setMinimum(100);ui->horizontalSlider->setMaximum(2000);ui->horizontalSlider->setValue(800);ui->horizontalSlider->setSingleStep(50);// 配置垂直滑块:最小值100、最大值1500、初始值600、步长50ui->verticalSlider->setMinimum(100);ui->verticalSlider->setMaximum(1500);ui->verticalSlider->setValue(600);ui->verticalSlider->setSingleStep(50);
}// Widget类的析构函数,用于释放UI对象内存
Widget::~Widget()
{delete ui;
}// 水平滑块值改变时的槽函数:根据滑块值调整窗口宽度
void Widget::on_horizontalSlider_valueChanged(int value)
{const QRect& rect = this->geometry();  // 获取当前窗口的几何信息(位置、宽高)// 设置窗口新的几何信息,宽度为滑块值,其他属性(x、y、高度)保持不变this->setGeometry(rect.x(), rect.y(), value, rect.height());
}// 垂直滑块值改变时的槽函数:根据滑块值调整窗口高度
void Widget::on_verticalSlider_valueChanged(int value)
{const QRect& rect = this->geometry();  // 获取当前窗口的几何信息// 设置窗口新的几何信息,高度为滑块值,其他属性(x、y、宽度)保持不变this->setGeometry(rect.x(), rect.y(), rect.width(), value);
}

多元素类

QListWidget--------->列表

QListView

QTableWidget-------->表格

QTableView

QTreeWidget---------->树状结构

QTreeView

widget与view的区别在于,view是更加底层的,而widget是基于view进行封装实现的。

  1. MVC 是软件开发中经典的软件结构组织形式,包含:

    • M model 数据
    • V view 视图 (界面)
    • C controller 控制器,处理数据和视图之间的业务流程
  2. xxView 仅负责实现视图,不处理数据存储表示和数据视图交互

  3. 使用 xxView 需要程序员自己实现 model 和 controller 部分,比较麻烦

  4. xxWidget 基于 xxView,同时实现了 model 和 controller,提供了方便的 API,使用简单

QListWidget(纵向列表)

核心方法:

样例:

#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->listWidget->addItem("C++");ui->listWidget->addItem("Java");ui->listWidget->addItem("Python");
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{QString text=ui->lineEdit->text();if(text!=nullptr)ui->listWidget->addItem(text);
}void Widget::on_pushButton_2_clicked(bool checked)
{int row=ui->listWidget->currentRow();if(row<0)return;ui->listWidget->takeItem(row);
}void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{if(current!=nullptr)qDebug()<<"cur"<<current->text();if(previous!=nullptr)qDebug()<<"pre"<<previous->text();
}

样例

QTableWidget(表格)

表格每一行是一个QTableWidget Item对象

表格的创建操作:

ui->setupUi(this);// 创建 3 行
ui->tableWidget->insertRow(0);
ui->tableWidget->insertRow(1);
ui->tableWidget->insertRow(2);// 创建 3 个列
ui->tableWidget->insertColumn(0);
ui->tableWidget->insertColumn(1);
ui->tableWidget->insertColumn(2);// 给 3 个列设定列名(设置水平方向的表头)
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号"));
ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("姓名"));
ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("年龄"));// 给表格中添加数据
ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));
ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));
ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20"));ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
ui->tableWidget->setItem(1, 2, new QTableWidgetItem("19"));ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
ui->tableWidget->setItem(2, 2, new QTableWidgetItem("23"));

通过按钮进行行的增删

void Widget::on_pushButton_insertRow_clicked()
{// 需要知道当前一共有多少行int rowCount = ui->tableWidget->rowCount();// 在最后一行之后新增行// 注意此处的参数是“下标”,表示你新增之后的这一行是第几行ui->tableWidget->insertRow(rowCount);
}
void Widget::on_pushButton_deleteRow_clicked()
{// 获取到选中的行号int curRow = ui->tableWidget->currentRow();// 删除这一行ui->tableWidget->removeRow(curRow);
}

按钮进行列的增删

void Widget::on_pushButton_insertColumn_clicked()
{// 先获取到一共有几列int colCount = ui->tableWidget->columnCount();// 在对应的位置新增一列.ui->tableWidget->insertColumn(colCount);// 设置列名(从输入框中获取到)const QString& text = ui->lineEdit->text();ui->tableWidget->setHorizontalHeaderItem(colCount, new QTableWidgetItem(text));
}
void Widget::on_pushButton_deleteColumn_clicked()
{// 获取到选中的列号int curCol = ui->tableWidget->currentColumn();// 删除这一列ui->tableWidget->removeColumn(curCol);
}

QTreeWidget

使用 `QTreeWidget` 表示一个树形控件。里面的每个元素,都是一个 `QTreeWidgetItem`,每个 `QTreeWidgetItem` 可以包含多个文本和图标,每个文本/图标为一个列。 可以给 `QTreeWidget` 设置顶层节点(顶层节点可以有多个),然后再给顶层节点添加子节点,从而构成树形结构。

顶层节点的添加

ui->setupUi(this);
// 设置根节点的名字
ui->treeWidget->setHeaderLabel("动物");// 新增顶层节点
QTreeWidgetItem* item1 = new QTreeWidgetItem();
// 每个节点都可以设置多个列。此处为了简单就只设置一列了。
item1->setText(0, "猫");
// 添加到顶层节点中。
ui->treeWidget->addTopLevelItem(item1);// 新增顶层节点
QTreeWidgetItem* item2 = new QTreeWidgetItem();
// 每个节点都可以设置多个列。此处为了简单就只设置一列了。
item2->setText(0, "狗");
// 添加到顶层节点中。
ui->treeWidget->addTopLevelItem(item2);// 新增顶层节点
QTreeWidgetItem* item3 = new QTreeWidgetItem();
// 每个节点都可以设置多个列。此处为了简单就只设置一列了。
item3->setText(0, "鸟");
// 添加到顶层节点中。
ui->treeWidget->addTopLevelItem(item3);

子节点的添加

// 添加一些子节点
QTreeWidgetItem* item4 = new QTreeWidgetItem();
item4->setText(0, "中华田园猫");
item1->addChild(item4);QTreeWidgetItem* item5 = new QTreeWidgetItem();
item5->setText(0, "布偶猫");
item1->addChild(item5);QTreeWidgetItem* item6 = new QTreeWidgetItem();
item6->setText(0, "暹罗猫");
item1->addChild(item6);

通过按钮实现节点的添加

void Widget::on_pushButton_insertItem_clicked()
{// 获取到当前选中的节点QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();if (currentItem == nullptr) {return;}// 获取到输入框的内容const QString& text = ui->lineEdit->text();// 构造一个 QTreeWidgetItemQTreeWidgetItem* item = new QTreeWidgetItem();item->setText(0, text);// 插入到选中节点的子节点中currentItem->addChild(item);
}

通过按钮实现节点的删除

void Widget::on_pushButton_deleteItem_clicked()
{// 获取到选中的元素QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();if (currentItem == nullptr) {return;}// 删除选中的元素,需要先获取到父元素,通过父元素进行删除QTreeWidgetItem* parent = currentItem->parent();if (parent == nullptr) {// 顶层元素int index = ui->treeWidget->indexOfTopLevelItem(currentItem);ui->treeWidget->takeTopLevelItem(index);} else {// 普通元素parent->removeChild(currentItem);}
}

容器类

QGroupBox

使用 QGroupBox 实现一个带有标题的分组框,可以把其他的控件放到里面作为一组.这样看起来能更好看一点。
注意不要把 QGroupBox 和 QButtonGroup 混淆,(之前在介绍 QRadionButton 的时候提到 QButtonGroup ).

QTabWidget

使用 QTabwidget 实现一个带有标签页的控件,可以往里面添加一些 widget.进一步的就可以通过标签页来切换。

通过按钮实现标签的增删

void Widget::on_pushButton_clicked()
{// 使用 addTab 方法来创建新的标签页.// 参数1 要指定一个 QWidget.// 参数2 指定这个标签页的 text(标题), 此处标题就叫做 Tab + 数字int count = ui->tabWidget->count();  // 获取到标签页的数量QWidget* w = new QWidget();ui->tabWidget->addTab(w, QString("Tab ") + QString::number(count + 1));// 添加一个 QLabel 显示内容QLabel* label = new QLabel(w);label->setText(QString("标签页 ") + QString::number(count + 1));label->resize(100, 50);// 设置新标签页被选中ui->tabWidget->setCurrentIndex(count);
}
void Widget::on_pushButton_2_clicked()
{// 获取到当前选中的标签页的下标int index = ui->tabWidget->currentIndex();// 删除标签页ui->tabWidget->removeTab(index);
}

布局类

QVBoxLayout(垂直)

Qt 中手动布局控件的方式存在复杂不精确、无法自适应窗口大小等问题,因此提供了垂直布局、水平布局、网格布局、表单布局等多种布局管理器来解决这些问题,以更科学地对界面控件进行布局。

使用样例

ui->setupUi(this);// 创建三个按钮,使用垂直布局管理器管理起来.
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");// 创建布局管理器
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);// 把布局管理器添加到窗口中.
this->setLayout(layout);

QHBoxLayout(水平)

QGridBoxLayout(网格)

QFromLayout(表单)

使用样例

ui->setupUi(this);// 设置成 3 行 2 列.
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);// 创建 3 个 label 作为第一列
QLabel* label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel* label3 = new QLabel("电话");// 创建 3 个输入框作为第二列
QLineEdit* edit1 = new QLineEdit();
QLineEdit* edit2 = new QLineEdit();
QLineEdit* edit3 = new QLineEdit();// 把上述控件添加到表单布局中
layout->addRow(label1, edit1);
layout->addRow(label2, edit2);
layout->addRow(label3, edit3);

QSpaceItem(空白段)

http://www.dtcms.com/a/500276.html

相关文章:

  • 安顺北京网站建设wordpress 模板标签
  • 好用的西安IBMS数字孪生集成系统机构
  • Photoshop - Photoshop 工具栏(11)缩放工具
  • 梁平网站2022做网站还能赚钱吗
  • 做公司网站的公司有哪些网站建设工
  • 营销型网站建设的原则做网站的技术要求高吗
  • 【JavaWeb学习】myabtis.xml一次性加载mapper相关的文件
  • 电子商务网站开发课程教案网站制作网站价格
  • 网站备案与所在地好的做淘宝详情页的网站有哪些
  • 深度学习4-PyTorch安装-张量创建-张量转换-张量数值计算
  • 如何快速将多个txt文档合并成一个txt文档?操作简单高效
  • 免费网站模板下载网站网站建设分为哪几个阶段
  • 网站维护提示做网站挣钱吗
  • 怎么找做网站的人关于做情侣的网站的图片大全
  • 可以用自己的电脑做网站主机成全视频免费观看在线看小说原著叫什么
  • 网站loading什么意思怎么把在微企点做响应式网站
  • Altium Designer(AD24)Edit编辑功能总结
  • 建设银行网站怎么登陆不了网站模板 英文
  • 魔搭社区与 Python Notebook:Ubuntu虚拟机+Python+机器学习
  • 外贸自建站模板企业推广策略
  • 深度学习——基于ResNet18迁移学习的图像分类模型
  • 网站培训班有哪些课程紫金保险车险官方网站
  • 抗体药物偶联物(ADCs):从研发突破到临床变革,解码疗效与毒性的核心机制
  • 建邺区建设局网站重庆市特种作业证报名
  • 9861云南网站建设北京建设投标网站
  • 【OS笔记10】:进程和线程8-进程通信
  • 给会所做网站室内装潢设计师
  • 长春建站塔山双喜网络广告营销案例有哪些
  • Linux防火墙利器:iptables详解
  • 网站建设mrd文档模板公众号开发运营方案