QWidget类是所有窗口类和控件类的基类,它有以下特点:

  • 所有窗口类的基类

    Qt中有3个窗口的基类:QWidgetQMainWindowQDialog,其中QMainWindowQDialog都继承自QWidget

    在创建Qt工程时,通常需要选择三者之一作为当前窗口的基类

  • 所有控件类的基类

    Qt中的控件,比如按钮、输入框、单选框、表格控件等,都是直接或间接地继承自QWidget

  • 内嵌窗口、独立窗口

    可以内嵌到其他窗口的内部,此时需要给其指定父窗口

    可以作为独立的窗口显示,此时无需给其指定父窗口


1. 效果演示

本节演示QWidget作为内嵌窗口和独立窗口、窗口的大小和位置、窗口的标题和图标,如下:

动画22


2. 属性和方法

QWidget有很多属性,完整的可查看帮助文档,这里列出常用的属性和方法。

2.1 窗口位置

以下截图来自官方文档:

image-20251228211037299

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1、设置窗体的几何信息
// 获取相对于当前窗口父窗口的几何信息:宽高、坐标点信息
// 不包含标题栏
const QRect &geometry() const;
void setGeometry(int x, int y, int w, int h);
void setGeometry(const QRect &);

// 获取相对于当前窗口父窗口的几何信息:宽高、坐标点信息
// 包含标题栏
QRect frameGeometry() const

// 2、移动窗口。
// 重新设置窗口的位置
void move(int x, int y);
void move(const QPoint &);

2.2 窗口大小

通常,窗口可以拖动其右下角,进行放大和缩小。

可以设置窗口的最小大小和最大大小。另外,窗口可以设置为固定大小,这样窗口就不能放大和缩小

常用的设置大小的函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 1、设置窗口尺寸
QSize size() const
void resize(int w, int h);
void resize(const QSize &);

// 2、设置最大尺寸
QSize maximumSize() const;
void setMaximumSize(const QSize &);
void setMaximumSize(int maxw, int maxh);

// 3、设置最小尺寸
QSize minimumSize() const;
void setMinimumSize(const QSize &);
void setMinimumSize(int minw, int minh);

// 4、设置固定尺寸
void QWidget::setFixedSize(const QSize &s);
void QWidget::setFixedSize(int w, int h);

// 5、单独设置窗口的高度
int height() const;
int minimumHeight() const;
int maximumHeight() const;

void setFixedHeight(int h);
void setMaximumHeight(int maxh);
void setMinimumHeight(int minh);

// 6、单独设置窗口的宽度
int width() const;
int minimumWidth() const;
int maximumWidth() const;

void setFixedWidth(int w);
void setMaximumWidth(int maxw);
void setMinimumWidth(int minw);

2.3 窗口标题、图标、资源文件

设置和获取窗口的标题,直接使用如下两个函数即可:

1
2
3
// 获取和设置窗口的标题
QString windowTitle() const;
void setWindowTitle(const QString &);

设置窗口的图标,需要一个QIcon对象,如下:

1
2
3
4
5
6
7
8
// 获取和设置窗口的图标
QIcon windowIcon() const;
void setWindowIcon(const QIcon &icon);

// 构造 QIcon 图标对象
// 有 6 个重载的构造方法,通常我们使用最后一个
// 参数为图标文件的路径
QIcon::QIcon(const QString &fileName);

2.4 获取父控件/子控件

1
2
3
// 获取父控件、子控件列表
QWidget *QWidget::parentWidget() const
const QObjectList &QObject::children() const

2.5 信号槽

1
2
3
4
5
6
7
8
9
10
11
// 最大化显示
void showMaximized();

// 最小化显示
void showMinimized();

// 正常显示
void showNormal();

// 关闭窗口
bool close();

3. 从零实现

从零写代码实现整体效果,以演示标签的属性以及信号槽的用法

3.1 布局

在UI设计师界面,拖拽对应的控件,修改显示的文字、控件的名称,然后完成布局

  • 合理地使用了水平、垂直、栅格布局

  • 合理地使用弹簧

  • 合理地调整Layout的各种参数,来设置外边距、内边距

  • 合理地调整字体大小

即可完成以下效果,多操作自然就熟练了(完成后的代码,会一并共享给大家的~)

布局完成效果如下:

image-20251228211101361


3.2 添加资源文件

把用到的图标,作为资源文件添加到项目中,如下:

image-20251228211115685


3.3 代码实现

接下来,开始写代码实现以上效果。

3.3.1 内嵌窗口、独立窗口

首先,添加字体设置和颜色设置对应的布局

在项目名右击->【Add New…】->【Qt】->【Qt Widgets Designer Form Class】,创建出新的QWidget布局和源文件,如下:

image-20251228211129117

此时,新建的两个QWidget布局文件,如下:

image-20251228211147695

image-20251228211156645


然后,在fontform.h/.cpp文件中,实现对应的信号槽,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// fontform.h
class FontForm : public QWidget {

signals:
void fontChanged(bool bold, bool italic, bool underline);

private slots:
void onChkFontClicked();
};

// fontform.cpp
FontForm::FontForm(QWidget *parent) : QWidget(parent), ui(new Ui::FontForm)
{
ui->setupUi(this);

connect(ui->chkBold, &QCheckBox::clicked, this, &FontForm::onChkFontClicked);
connect(ui->chkItalic, &QCheckBox::clicked, this, &FontForm::onChkFontClicked);
connect(ui->chkUnderline, &QCheckBox::clicked, this, &FontForm::onChkFontClicked);
}

void FontForm::onChkFontClicked()
{
emit fontChanged(ui->chkBold->isChecked(), ui->chkItalic->isChecked(), ui->chkUnderline->isChecked());
}

然后,在colorform.h/.cpp文件中,实现对应的信号槽,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// colorform.h
#include <QButtonGroup>

class ColorForm : public QWidget {

signals:
void colorChanged(int id);

private slots:
void onBtnGroupColorClicked(int id);

private:
QButtonGroup *btnGroupColor;
};

// colorform.cpp
ColorForm::ColorForm(QWidget *parent) : QWidget(parent), ui(new Ui::ColorForm)
{
ui->setupUi(this);

btnGroupColor = new QButtonGroup(this);
btnGroupColor->addButton(ui->radioRed, 0);
btnGroupColor->addButton(ui->radioGreen, 1);
btnGroupColor->addButton(ui->radioBlue, 2);

connect(btnGroupColor, &QButtonGroup::idClicked, this, &ColorForm::onBtnGroupColorClicked);
ui->radioRed->click();
}

void ColorForm::onBtnGroupColorClicked(int id)
{
emit colorChanged(id);
}


最后,在widget.h/.cpp文件中,实现对应的信号槽,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// widget.h
#include <QButtonGroup>
#include "colorform.h"

class Widget : public QWidget {
private slots:
// 1. 内嵌窗口、独立窗口
void onBtnGroupAlignmentClicked(int id);
void onFontChanged(bool bold, bool italic, bool underline);
void onColorChanged(int id);

private:
QButtonGroup *btnGroupAlignment;
ColorForm *colorForm;
};

// widget.cpp
#include <QPushButton>
#include "fontform.h"

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

// 1. 内嵌窗口、独立窗口
// 对齐设置
ui->lineEditTime->setText("2024-12-12 12:10:00");

btnGroupAlignment = new QButtonGroup(this);
btnGroupAlignment->addButton(ui->radioAlignLeft, 0);
btnGroupAlignment->addButton(ui->radioAlignCenter, 1);
btnGroupAlignment->addButton(ui->radioAlignRight, 2);

connect(btnGroupAlignment, &QButtonGroup::idClicked, this, &Widget::onBtnGroupAlignmentClicked);
ui->radioAlignCenter->click();

// 字体设置
FontForm* fontForm = new FontForm();
ui->widgetSet->layout()->addWidget(fontForm);
fontForm->setWindowTitle("字体设置");

connect(fontForm, &FontForm::fontChanged, this, &Widget::onFontChanged);

// 颜色设置
QPushButton* btnColor = new QPushButton("颜色设置");
btnColor->setStyleSheet("QPushButton { font-size: 14px; }");
ui->widgetSet->layout()->addWidget(btnColor);
connect(btnColor, &QPushButton::clicked, this, [=] { colorForm->show(); });

colorForm = new ColorForm();
colorForm->setWindowTitle("颜色设置");
colorForm->setFixedWidth(300);
connect(colorForm, &ColorForm::colorChanged, this, &Widget::onColorChanged);

ui->lineEditTime->setStyleSheet("QLineEdit {color: red};");
}

void Widget::onBtnGroupAlignmentClicked(int id)
{
if (id == 0) {
ui->lineEditTime->setAlignment(Qt::AlignLeft);
} else if (id == 1) {
ui->lineEditTime->setAlignment(Qt::AlignCenter);
} else if (id == 2) {
ui->lineEditTime->setAlignment(Qt::AlignRight);
}
}

void Widget::onFontChanged(bool bold, bool italic, bool underline)
{
QFont font = ui->lineEditTime->font();

font.setBold(bold);
font.setItalic(italic);
font.setUnderline(underline);

ui->lineEditTime->setFont(font);
}

void Widget::onColorChanged(int id)
{
if (id == 0) {
ui->lineEditTime->setStyleSheet("QLineEdit {color: red};");
} else if (id == 1) {
ui->lineEditTime->setStyleSheet("QLineEdit {color: green};");
} else if (id == 2) {
ui->lineEditTime->setStyleSheet("QLineEdit {color: blue};");
}
}

3.3.2 窗口位置、大小

首先,在widget.h文件中,声明槽函数,如下:

1
2
3
4
5
6
7
class Widget : public QWidget {
private slots:
// 2. 窗口大小和位置
void on_btnGetWindowGeometry_clicked();
void on_btnResize_clicked();
void on_btnMoveWindow_clicked();
};

然后,在widget.cpp文件中,实现槽函数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Widget::on_btnGetWindowGeometry_clicked()
{
// QRect rect = this->frameGeometry();
QRect rect = this->geometry();
QPoint topLeft = rect.topLeft();
int width = rect.width();
int height = rect.height();
ui->lineEditWindowGeometry->setText(QString("左上角(%1,%2), 宽高(%3*%4)").arg(topLeft.x()).arg(topLeft.y()).arg(width).arg(height));
}

void Widget::on_btnResize_clicked()
{
this->resize(400, 400);
}

void Widget::on_btnMoveWindow_clicked()
{
this->move(100, 100);
}

3.3.3 窗口标题、图标

首先,在widget.h文件中,声明槽函数,如下:

1
2
3
4
5
6
class Widget : public QWidget {
private slots:
// 3. 设置窗口标题和图标
void on_btnSetWindowTitle_clicked();
void on_btnUpdateWindowIcon_clicked();
};

然后,在widget.cpp文件中,实现槽函数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
QStringList icons = {":/res/star1.png", ":/res/star2.png", ":/res/star3.png", ":/res/star4.png"};
int index = 0;

void Widget::on_btnSetWindowTitle_clicked()
{
this->setWindowTitle(ui->lineEditWindowTitle->text().trimmed());
}

void Widget::on_btnUpdateWindowIcon_clicked()
{
this->setWindowIcon(QIcon(icons[index++ % 4]));
}