以一个长方形计算器为案例。
Ui_Widget (容器/蓝图)
├── 控件指针 (QPushButton*, QLabel*, ...)
├── setupUi() - 创建控件、设置参数、布局
└── retranslateUi() - 设置文本翻译
::Widget (窗口)
├── 继承 QWidget (真正的窗口)
├── ui 指针 (指向 Ui::Widget)
├── 构造函数中调用 ui->setupUi(this) 来构建界面
└── 实现信号槽,处理业务逻辑
Widget (this) ← QWidget 对象
├── ui (Ui::Widget) ← 普通 C++ 对象,不是 QObject
│ ├── commitPushButton (QPushButton*) ← 指向下面按钮的指针
│ ├── label (QLabel*) ← 指向下面标签的指针
│ └── lineEdit (QLineEdit*) ← 指向下面输入框的指针
│
├── commitPushButton (QPushButton) ← 真实的按钮,父对象是 Widget
├── label (QLabel) ← 真实的标签,父对象是 Widget
└── lineEdit (QLineEdit) ← 真实的输入框,父对象是 Widget
// main.cpp
#include "widget.h" // widget.h
#include <QApplication> // Qt应用程序类
int main(int argc, char *argv[])
{
QApplication a(argc, argv); // 创建Qt应用程序对象
Widget w; // 创建主窗口,来自::Widget类
w.show(); // 显示窗口
return a.exec(); // 进入事件循环
}
// main.cpp 负责创建 a对象来循环运行窗口,监听事件等等
// 同时创建w对象,即程序的窗口,并将其显示出来。
// widget.h
#ifndef WIDGET_H // 头文件保护符,避免被编辑器多次包含
#define WIDGET_H // 宏规范要求把头文件字母转换成大写,'.'号转换成'_'
#include <QWidget> // Qt窗口类,提供了窗口的基本功能:显示、隐藏、大小、位置、事件处理等
QT_BEGIN_NAMESPACE // QT_BEGIN_NAMESPACE 是Qt的宏,用于处理不同编译器对命名空间的支持
namespace Ui { // Qt自动生成UI命名空间
class Widget; // 前置声明UI类 Ui::Widget
} // 此类的正式声明位置在ui_widget.h中
QT_END_NAMESPACE
class Widget : public QWidget // 创建一个继承自QWidget的::Widget类,窗口类
{
Q_OBJECT // Qt元对象系统宏,启用信号槽等功能
public:
Widget(QWidget *parent = nullptr); // 构造函数,parent:父窗口指针,默认nullptr
~Widget(); // 析构函数
private slots: // 私有槽函数部分,自动连接命名规则:on_对象名_信号名()
void on_commitPushButton_clicked(); // 提交按钮点击事件处理
private:
Ui::Widget *ui; // 私有成员变量,指向UI类的指针
};
#endif // WIDGET_H
// widget.cpp
#include "widget.h"
#include "./ui_widget.h"
Widget::Widget(QWidget *parent) //parent 参数传递给基类,建立对象树关系
//如果 parent 为 nullptr,则窗口为顶层窗口
: QWidget(parent) // :后跟初始化列表,各项用,分开。此项为调用基类构造函数
, ui(new Ui::Widget) // 此项为将ui指针初始化为新创建的UI对象
{
ui->setupUi(this); // 初始化UI界面:把::Widget类的对象的地址,即this指针,
// 放入ui指向的Ui::Widget类的对象的setupUi()方法中
// 设置样式属性,允许背景样式
this->setAttribute(Qt::WA_StyledBackground, true);
//创建所有真实控件
//设置控件的属性、布局
//填充 ui 对象中的指针,指向这些控件
//将 this(你的窗口)作为控件的父对象
// 设置样式表
this->setStyleSheet(
"Widget {"
"background-image: url(:/1.jpg);" // 设置背景图片
"background-repeat: no-repeat;" // 不平铺
"background-position: center;" // 居中显示
"}"
);
}
Widget::~Widget() //析构函数
{
delete ui; // 释放UI对象内存
}
// 手动连接(需要在构造函数中写代码)
//connect(ui->commitPushButton, &QPushButton::clicked,
// this, &Widget::onCommitButtonClicked);
void Widget::on_commitPushButton_clicked() // ::Widget的函数,写在类外面,更清晰
{
// 读取输入内容(QString)
QString lenStr = ui->lengthLineEdit->text();
QString widStr = ui->widthLineEdit->text();
// 转成 double
double length = lenStr.toDouble();
double width = widStr.toDouble();
// 计算面积与周长
double area = length * width;
double perimeter = 2 * (length + width);
// 拼接显示字符串
QString result = QString("周长:%1 面积:%2")
.arg(perimeter)
.arg(area);
// 显示
ui->resultLineEdit->setText(result);
}
//ui_widget.h
/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 6.10.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_WIDGET_H
#define UI_WIDGET_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Widget // 全局作用域 ::Ui_Widget
{ // 只是一个指针容器,存储指向这些控件的指针
public:
QLineEdit *lengthLineEdit;
QLineEdit *widthLineEdit;
QLineEdit *resultLineEdit;
QPushButton *commitPushButton;
QLabel *label;
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName("Widget");
Widget->resize(264, 364);
lengthLineEdit = new QLineEdit(Widget);
lengthLineEdit->setObjectName("lengthLineEdit");
lengthLineEdit->setEnabled(true);
lengthLineEdit->setGeometry(QRect(30, 90, 200, 30));
lengthLineEdit->setMinimumSize(QSize(200, 30));
lengthLineEdit->setMaximumSize(QSize(200, 30));
lengthLineEdit->setCursor(QCursor(Qt::CursorShape::IBeamCursor));
lengthLineEdit->setCursorPosition(3);
widthLineEdit = new QLineEdit(Widget);
widthLineEdit->setObjectName("widthLineEdit");
widthLineEdit->setGeometry(QRect(30, 150, 200, 30));
widthLineEdit->setMinimumSize(QSize(200, 30));
widthLineEdit->setMaximumSize(QSize(200, 30));
resultLineEdit = new QLineEdit(Widget);
resultLineEdit->setObjectName("resultLineEdit");
resultLineEdit->setGeometry(QRect(30, 210, 200, 30));
resultLineEdit->setMinimumSize(QSize(200, 30));
resultLineEdit->setMaximumSize(QSize(200, 30));
commitPushButton = new QPushButton(Widget);
commitPushButton->setObjectName("commitPushButton");
commitPushButton->setGeometry(QRect(150, 270, 80, 30));
commitPushButton->setMinimumSize(QSize(80, 30));
commitPushButton->setMaximumSize(QSize(80, 30));
label = new QLabel(Widget);
label->setObjectName("label");
label->setGeometry(QRect(90, 40, 101, 31));
retranslateUi(Widget);
QMetaObject::connectSlotsByName(Widget);
} // setupUi
void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));
lengthLineEdit->setText(QCoreApplication::translate("Widget", "\350\276\223\345\205\245\351\225\277", nullptr));
widthLineEdit->setText(QCoreApplication::translate("Widget", "\350\276\223\345\205\245\345\256\275", nullptr));
resultLineEdit->setText(QCoreApplication::translate("Widget", "\346\230\276\347\244\272\347\273\223\346\236\234", nullptr));
commitPushButton->setText(QCoreApplication::translate("Widget", "\350\256\241\347\256\227", nullptr));
label->setText(QCoreApplication::translate("Widget", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt;\">\347\237\251\345\275\242\350\256\241\347\256\227</span></p></body></html>", nullptr));
} // retranslateUi
};
namespace Ui {
class Widget: public Ui_Widget {}; // Ui::Widget 是Ui_Widget子类
} // namespace Ui // Ui::Widget 是Ui_Widget的套壳封装
QT_END_NAMESPACE
#endif // UI_WIDGET_H
1. 程序启动,创建 Widget 对象
↓
2. Widget 构造函数执行
├── 调用 QWidget 构造函数
├── new Ui::Widget 创建 ui 容器
├── ui->setupUi(this) 创建所有控件
└── 设置样式表
↓
3. 窗口显示,用户输入长和宽
↓
4. 用户点击"计算"按钮
↓
5. Qt 自动调用 on_commitPushButton_clicked()
↓
6. 槽函数执行
├── 读取输入值
├── 计算面积和周长
└── 显示结果
↓
7. 关闭窗口
↓
8. ~Widget() 析构函数执行
├── delete ui
└── 基类析构,自动删除所有控件