QDialog多窗口使用
QDialog 用于弹出对话框,支持模态和非模态。多个对话框可嵌套使用,通过信号槽传递数据,管理用户交互。
QDialog多窗口使用
QDialog 多窗口使用
QDialog
QDialog
是 Qt 框架中用于创建对话框窗口(Dialog)的类,是 GUI 应用开发中非常常用的组件之一。它继承自 QWidget
,意味着它本质上是一个窗口部件,但被专门设计用来创建“模态”或“非模态”的对话框。
模态 vs 非模态
模态对话框(Modal Dialog)
- 会阻塞父窗口的交互。
- 使用
.exec()
启动。 - 常见场景:确认、保存、设置。
1
2
3
4
MyDialog dlg;
if (dlg.exec() == QDialog::Accepted) {
// 用户点击了“确定”
}
非模态对话框(Modeless Dialog)
不阻塞父窗口,用户可以切换回主窗口。
使用
.show()
启动。通常用于辅助工具窗口等。
1
2
MyDialog *dlg = new MyDialog(this);
dlg->show(); // 不阻塞主窗口
类型 | 特点 | 常用方法 |
---|---|---|
模态(Modal) | 阻止用户与其他窗口交互必须先关闭它才能继续操作 | .exec() |
非模态(Modeless) | 不会阻止主窗口,可以自由切换交互 | .show() |
常用成员函数
函数名 | 说明 |
---|---|
exec() | 启动模态对话框,并阻塞直到关闭 |
show() | 启动非模态对话框 |
accept() | 设置返回值为 Accepted 并关闭 |
reject() | 设置返回值为 Rejected 并关闭 |
done(int r) | 设置任意返回码并关闭 |
result() | 获取 .exec() 的返回结果 |
setModal(bool) | 设置是否为模态 |
setWindowTitle() | 设置窗口标题 |
使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 自定义对话框类,继承自 QDialog
class MyDialog : public QDialog {
Q_OBJECT // Qt 元对象系统宏,支持信号与槽机制
public:
// 构造函数,parent 默认为空指针
MyDialog(QWidget *parent = nullptr) : QDialog(parent) {
// 创建一个垂直布局管理器,并设置为该对话框的布局器
QVBoxLayout *layout = new QVBoxLayout(this);
// 创建一个名为 "OK" 的按钮
QPushButton *okBtn = new QPushButton("OK");
// 将按钮点击信号与 QDialog 的 accept() 槽函数连接
// 点击按钮后对话框会以“接受”状态关闭(即 exec() 返回 QDialog::Accepted)
connect(okBtn, &QPushButton::clicked, this, &QDialog::accept);
// 将按钮添加到布局中
layout->addWidget(okBtn);
// 设置布局到当前对话框
setLayout(layout);
}
};
调用方式示例:
1
2
3
4
5
MyDialog dlg; // 创建对话框对象
if (dlg.exec() == QDialog::Accepted) // 启动模态对话框,等待用户操作
{
// 如果用户点击了 OK(即触发 accept),则进入这个分支
}
衍生类(常见)
QFileDialog
:文件选择对话框QColorDialog
:颜色选择器QFontDialog
:字体选择器QMessageBox
:信息提示框
这些都是从 QDialog
派生的封装类。
示例:QDialog 多窗口
resizeimagedialog.ui
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
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ResizeImageDialog</class>
<widget class="QDialog" name="ResizeImageDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>200</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>当前尺寸</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditOldSize"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>宽度×高度</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxWidthNew">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxHeightNew">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonSetNewSize">
<property name="text">
<string>设置新尺寸</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
resizeimagedialog.h
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
#ifndef RESIZEIMAGEDIALOG_H
#define RESIZEIMAGEDIALOG_H
#include <QDialog> // 引入 QDialog 基类
// Qt Designer 生成的命名空间,前向声明 UI 类(界面元素封装)
namespace Ui {
class ResizeImageDialog;
}
// 缩放图片的对话框类,继承自 QDialog
class ResizeImageDialog : public QDialog {
Q_OBJECT // 启用 Qt 的信号槽机制
public :
// 构造函数,parent 可选,默认无父对象
explicit ResizeImageDialog(QWidget* parent = nullptr);
// 析构函数,释放资源
~ResizeImageDialog();
signals:
// 发送新尺寸信号(宽度和高度),由主窗口接收并完成缩放操作
void sendNewSize(int nNewWidth, int nNewHeight);
public slots:
// 接收旧尺寸(来自主窗口),用于初始化输入框显示等
void recvOldSize(int nOldWidth, int nOldHeight);
private slots:
// 点击“设置新尺寸”按钮的槽函数,读取输入并发出 sendNewSize 信号
void on_pushButtonSetNewSize_clicked();
private:
Ui::ResizeImageDialog* ui; // Qt UI 界面指针(由 Designer 自动生成)
void init(); // 初始化函数,用于设置界面默认状态、信号槽连接等
};
#endif // RESIZEIMAGEDIALOG_H
resizeimagedialog.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
#include "resizeimagedialog.h"
#include "ui_resizeimagedialog.h"
// 构造函数:初始化 UI,并调用自定义初始化函数
ResizeImageDialog::ResizeImageDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ResizeImageDialog) {
ui->setupUi(this); // 绑定 UI 组件
init(); // 执行自定义初始化
}
// 析构函数:释放 UI 对象资源
ResizeImageDialog::~ResizeImageDialog() {
delete ui;
}
// 初始化函数:设置界面控件属性
void ResizeImageDialog::init() {
// 设置旧尺寸输入框为只读,不允许用户修改
ui->lineEditOldSize->setReadOnly(true);
ui->lineEditOldSize->setStyleSheet("background-color: lightgray;");
// 设置新的宽度和高度输入范围,防止用户输入非法值
ui->spinBoxWidthNew->setRange(1, 10000);
ui->spinBoxHeightNew->setRange(1, 10000);
// 设置窗口标题
setWindowTitle(tr("缩放图片尺寸"));
}
// 接收来自主窗口的旧图片尺寸并显示,同时设置默认新尺寸
void ResizeImageDialog::recvOldSize(int nOldWidth, int nOldHeight) {
// 构造旧尺寸字符串,如 "800 X 600"
QString strOldSize = tr("%1 X %2").arg(nOldWidth).arg(nOldHeight);
ui->lineEditOldSize->setText(strOldSize); // 显示旧尺寸
// 将新尺寸的 spinBox 默认值设置为当前尺寸
ui->spinBoxWidthNew->setValue(nOldWidth);
ui->spinBoxHeightNew->setValue(nOldHeight);
}
// 点击“确定设置新尺寸”按钮时的槽函数
void ResizeImageDialog::on_pushButtonSetNewSize_clicked() {
// 获取用户输入的新宽度和高度
int nNewWidth = ui->spinBoxWidthNew->value();
int nNewHeight = ui->spinBoxHeightNew->value();
// 发射信号,将新尺寸传回主窗口进行图片缩放
emit sendNewSize(nNewWidth, nNewHeight);
// 更新旧尺寸框显示为新的尺寸值,供用户参考
QString strSize = tr("%1 X %2").arg(nNewWidth).arg(nNewHeight);
ui->lineEditOldSize->setText(strSize);
}
rotateimagedialog.ui
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
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RotateImageDialog</class>
<widget class="QDialog" name="RotateImageDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>100</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>顺时针旋转角度</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBoxAngle">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonRotating">
<property name="text">
<string>执行旋转</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
rotateimagedialog.h
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
#ifndef ROTATEIMAGEDIALOG_H
#define ROTATEIMAGEDIALOG_H
#include <QDialog> // Qt 提供的对话框基类
// Qt Designer 自动生成的命名空间,前向声明 UI 类
namespace Ui {
class RotateImageDialog;
}
// 旋转图片的对话框类,继承自 QDialog
class RotateImageDialog : public QDialog {
Q_OBJECT // 启用 Qt 的信号与槽功能
public :
// 构造函数,parent 默认为空指针(无父窗口)
explicit RotateImageDialog(QWidget* parent = nullptr);
// 析构函数,自动释放资源
~RotateImageDialog();
private slots:
// 当点击“确认旋转”按钮时触发的槽函数
void on_pushButtonRotating_clicked();
private:
Ui::RotateImageDialog* ui; // UI 界面指针,用于访问 Designer 中定义的控件
void init(); // 初始化函数,用于设置控件状态、连接信号槽等
};
#endif // ROTATEIMAGEDIALOG_H
rotateimagedialog.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
#include "rotateimagedialog.h"
#include "ui_rotateimagedialog.h"
// 构造函数:初始化 UI 并进行控件设置
RotateImageDialog::RotateImageDialog(QWidget* parent) : QDialog(parent), ui(new Ui::RotateImageDialog) {
ui->setupUi(this); // 加载 UI 布局
init(); // 自定义初始化
}
// 析构函数:释放 UI 对象资源
RotateImageDialog::~RotateImageDialog() {
delete ui;
}
// 初始化函数:设置角度选择框和窗口标题
void RotateImageDialog::init() {
// 设置旋转角度选择框的数值范围为 0~360 度
ui->spinBoxAngle->setRange(0, 360);
// 设置 spinBox 的后缀为“°”,表示单位为度
ui->spinBoxAngle->setSuffix(tr("°"));
// 设置窗口标题
setWindowTitle(tr("旋转图片"));
}
// “确定旋转”按钮点击事件处理函数
void RotateImageDialog::on_pushButtonRotating_clicked() {
// 获取用户设置的角度值
int nAngle = ui->spinBoxAngle->value();
// 调用 done() 结束对话框并返回角度值,供主窗口通过 exec() 获取
done(nAngle);
}
imagetransformwidget.ui
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
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImageTransformWidget</class>
<widget class="QWidget" name="ImageTransformWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>ImageTransformWidget</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>297</width>
<height>280</height>
</rect>
</property>
</widget>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButtonOpen">
<property name="text">
<string>打开图片</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonResize">
<property name="text">
<string>缩放图片</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonRotate">
<property name="text">
<string>旋转图片</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
imagetransformwidget.h
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
#ifndef IMAGETRANSFORMWIDGET_H
#define IMAGETRANSFORMWIDGET_H
// 引入自定义对话框头文件:缩放尺寸对话框和旋转对话框
#include "resizeimagedialog.h"
#include "rotateimagedialog.h"
// 引入 Qt 的标准组件
#include <QFileDialog> // 用于文件选择对话框
#include <QLabel> // 图片显示控件
#include <QPixmap> // 用于加载和操作图片
#include <QTransform> // 用于图片的矩阵变换(缩放、旋转等)
#include <QWidget> // 基类 QWidget
QT_BEGIN_NAMESPACE
namespace Ui {
class ImageTransformWidget; // 前向声明 UI 类
}
QT_END_NAMESPACE
// ImageTransformWidget 继承自 QWidget,是图片缩放与旋转的主界面类
class ImageTransformWidget : public QWidget {
Q_OBJECT // Qt 元对象宏,支持信号槽机制
public :
// 构造函数与析构函数
ImageTransformWidget(QWidget* parent = nullptr);
~ImageTransformWidget();
signals:
// 向 resizeImageDialog 发出旧的图片尺寸(宽、高)
void sendOldSize(int nOldWidth, int nOldHeight);
public slots:
// 接收 resizeImageDialog 返回的新尺寸,并执行缩放操作
void recvNewSizeAndResize(int nNewWidth, int nNewHeight);
private slots:
// “打开图片”按钮的槽函数
void on_pushButtonOpen_clicked();
// “缩放图片”按钮的槽函数
void on_pushButtonResize_clicked();
// “旋转图片”按钮的槽函数
void on_pushButtonRotate_clicked();
private:
Ui::ImageTransformWidget* ui; // UI 指针,界面布局对象
QLabel* m_pLabelImage; // 用于显示图片的 QLabel
QPixmap m_image; // 当前加载的图片对象
QString m_strFileName; // 当前图片的文件路径
ResizeImageDialog* m_pResizeDlg; // 缩放尺寸对话框指针
RotateImageDialog* m_pRotateDlg; // 旋转图片对话框指针
void init(); // 初始化函数,设置界面控件、信号槽等
};
#endif // IMAGETRANSFORMWIDGET_H
imagetransformwidget.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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "imagetransformwidget.h"
#include "./ui_imagetransformwidget.h"
#include <QDebug>
#include <QMessageBox>
// 构造函数,初始化 UI 和控件
ImageTransformWidget::ImageTransformWidget(QWidget* parent) : QWidget(parent), ui(new Ui::ImageTransformWidget) {
ui->setupUi(this); // 加载 UI 组件
init(); // 初始化界面元素和逻辑
}
// 析构函数,释放资源
ImageTransformWidget::~ImageTransformWidget() {
delete m_pResizeDlg;
m_pResizeDlg = nullptr;
delete m_pRotateDlg;
m_pRotateDlg = nullptr;
delete ui;
}
// 初始化函数,设置标签、滚动区、对话框及信号槽
void ImageTransformWidget::init() {
// 创建用于显示图片的标签
m_pLabelImage = new QLabel();
m_pLabelImage->setAlignment(Qt::AlignLeft | Qt::AlignTop); // 左上对齐
m_pLabelImage->setStyleSheet("background-color: lightgray;"); // 设置背景色
// 将标签设置为滚动区域内容
ui->scrollArea->setWidget(m_pLabelImage);
// 创建缩放尺寸对话框,并设置为当前窗口的子窗口
m_pResizeDlg = new ResizeImageDialog(this);
// 连接信号槽:主窗口发送旧尺寸 → 子对话框接收
connect(this, &ImageTransformWidget::sendOldSize, m_pResizeDlg, &ResizeImageDialog::recvOldSize);
// 连接信号槽:子对话框发送新尺寸 → 主窗口执行缩放
connect(m_pResizeDlg, &ResizeImageDialog::sendNewSize, this, &ImageTransformWidget::recvNewSizeAndResize);
// 创建旋转图片对话框
m_pRotateDlg = new RotateImageDialog(this);
// 旋转使用模态对话框 + exec() 获取角度,不需额外信号槽
}
// 点击“打开图片”按钮的槽函数
void ImageTransformWidget::on_pushButtonOpen_clicked() {
// 弹出文件选择对话框,选择图片文件
QString strFile = QFileDialog::getOpenFileName(this, tr("打开图片文件"), tr(""), tr("Image files(*.png *.jpg *.bmp)"));
if (strFile.isEmpty()) return; // 没选文件
// 尝试加载图片
bool bLoadOK = m_image.load(strFile);
if (!bLoadOK) {
QMessageBox::warning(this, tr("加载图片文件"), tr("加载图片文件失败,请检查文件格式。"));
return;
}
// 保存文件路径
m_strFileName = strFile;
// 显示图片到标签
m_pLabelImage->setPixmap(m_image);
// 设置窗口标题为文件名
setWindowTitle(tr("预览文件为 %1").arg(m_strFileName));
}
// 点击“缩放图片”按钮的槽函数
void ImageTransformWidget::on_pushButtonResize_clicked() {
if (m_image.isNull()) return; // 图片未加载
// 将当前图片的宽高发送给缩放对话框
emit sendOldSize(m_image.width(), m_image.height());
// 显示对话框
m_pResizeDlg->show();
m_pResizeDlg->raise(); // 置顶显示
}
// 点击“旋转图片”按钮的槽函数
void ImageTransformWidget::on_pushButtonRotate_clicked() {
if (m_image.isNull()) return; // 图片未加载
// 显示模态旋转对话框,等待用户输入角度
int nAngle = m_pRotateDlg->exec();
if (nAngle == 0) return; // 用户没有输入有效角度
// 构造旋转变换矩阵
QTransform mxRotate;
mxRotate.rotate(nAngle);
// 执行旋转操作,得到新图片
QPixmap imgNew = m_image.transformed(mxRotate);
// 更新成员变量并刷新显示
m_image = imgNew;
m_pLabelImage->setPixmap(m_image);
}
// 接收新尺寸并执行缩放的槽函数
void ImageTransformWidget::recvNewSizeAndResize(int nNewWidth, int nNewHeight) {
// 如果尺寸没变化,直接返回
if ((m_image.width() == nNewWidth) && (m_image.height() == nNewHeight)) return;
// 缩放图片
QPixmap imgNew = m_image.scaled(nNewWidth, nNewHeight);
// 更新成员变量并刷新显示
m_image = imgNew;
m_pLabelImage->setPixmap(m_image);
}
本文由作者按照 CC BY 4.0 进行授权