QT(5)
六、多窗口编程详解(Qt框架)
1. QMessageBox消息对话框(模态交互核心)
QMessageBox是Qt中用于模态交互的基础对话框,继承自QDialog,主要用于向用户传递信息或获取简单反馈(如确认、警告等)。其核心特点是阻塞式交互——用户必须响应对话框(点击按钮)后,程序才会继续执行后续代码。
1.1 核心特性与常用接口
QMessageBox通过静态成员函数直接调用,无需手动创建对象,函数返回值为用户点击的按钮类型(QMessageBox::StandardButton
)。常用接口包括:
-
critical()
:显示严重错误信息(红色标题); -
information()
:显示提示信息(蓝色标题); -
question()
:显示询问信息(问号图标); -
warning()
:显示警告信息(黄色标题)。
1.2 代码示例:消息对话框的使用
// dialog.h
#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QMessageBox>
#include <QButtonGroup>namespace Ui {
class Dialog;
}class Dialog : public QDialog {Q_OBJECTpublic:explicit Dialog(QWidget *parent = nullptr);~Dialog();private:Ui::Dialog *ui;QButtonGroup *btnGroup; // 按钮组管理多个按钮private slots:void onButtonClicked(int id); // 按钮点击槽函数
};#endif // DIALOG_H
// dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {ui->setupUi(this);// 初始化按钮组并关联按钮btnGroup = new QButtonGroup(this);btnGroup->addButton(ui->btnQuestion, 1); // 按钮ID=1btnGroup->addButton(ui->btnInfo, 2); // 按钮ID=2btnGroup->addButton(ui->btnWarning, 3); // 按钮ID=3btnGroup->addButton(ui->btnCritical, 4); // 按钮ID=4// 连接按钮组点击信号到槽函数connect(btnGroup, &QButtonGroup::buttonClicked, this, &Dialog::onButtonClicked);
}Dialog::~Dialog() {delete btnGroup;delete ui;
}void Dialog::onButtonClicked(int id) {switch (id) {case 1: { // 询问对话框QMessageBox::StandardButton reply = QMessageBox::question(this, "确认", "是否关闭窗口?",QMessageBox::Yes | QMessageBox::No);if (reply == QMessageBox::Yes) close();break;}case 2: { // 信息对话框QMessageBox::information(this, "提示", "数据加载完成!");break;}case 3: { // 警告对话框QMessageBox::warning(this, "警告", "输入内容格式错误!");break;}case 4: { // 错误对话框QMessageBox::critical(this, "错误", "程序异常:缺少必要文件 ***.dll");break;}}
}
2. QWidget类(窗口基类)
QWidget是Qt中所有窗口和组件的基类,既是窗口容器(如主窗口),也是基础组件(如按钮、文本框)的父类。作为窗口时,它具备窗口的基本特性(标题、边框、状态等)。
2.1 窗口特性控制
通过成员函数可灵活控制窗口行为:
-
setWindowTitle(const QString&)
:设置窗口标题; -
setWindowFlags(Qt::WindowFlags)
:设置窗口标志(如无边框、置顶); -
setWindowState(Qt::WindowState)
:设置窗口状态(最大化、最小化、全屏)。
2.2 代码示例:自定义窗口属性
// widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>namespace Ui {
class Widget;
}class Widget : public QWidget {Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;
};#endif // WIDGET_H
// widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 设置窗口标题setWindowTitle("自定义窗口");// 设置窗口标志:无边框 + 置顶setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);// 设置窗口状态:最大化setWindowState(Qt::WindowMaximized);
}Widget::~Widget() {delete ui;
}
3. parent参数(内存管理与窗口关系)
在Qt中,parent
参数是对象树机制的核心,用于管理内存生命周期和窗口层级关系:
3.1 核心作用
-
内存管理:若对象A的
parent
设为对象B,则对象B销毁时,对象A会被自动销毁(无需手动delete
); -
窗口层级:
parent
为nullptr
时,对象是独立窗口;否则是父窗口的子窗口(内嵌显示)。
3.2 代码示例:parent参数的两种场景
// 场景1:独立窗口(无parent)
Widget *w = new Widget(); // 主窗口,需手动delete
w->show();// 场景2:子窗口(parent指向主窗口)
Dialog *dlg = new Dialog(w); // dlg是w的子窗口,w销毁时dlg自动销毁
dlg->show();
4. QStackedWidget(堆栈窗口)
QStackedWidget是层叠窗口容器,用于管理多个子窗口(页面),同一时间仅显示一个页面,常与QListWidget联动实现“选项卡”效果。
4.1 核心特性
-
通过
addWidget()
添加子窗口; -
通过
setCurrentIndex(int)
切换显示的页面; -
与QListWidget联动时,通过
currentRowChanged(int)
信号触发页面切换。
4.2 代码示例:堆栈窗口与列表联动
// dialog.h
#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QStackedWidget>
#include <QListWidget>namespace Ui {
class Dialog;
}class Dialog : public QDialog {Q_OBJECTpublic:explicit Dialog(QWidget *parent = nullptr);~Dialog();private:Ui::Dialog *ui;
};#endif // DIALOG_H
// dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {ui->setupUi(this);// 初始化堆栈窗口和列表QStringList pages = {"页面1", "页面2", "页面3"};ui->listWidget->addItems(pages);// 添加子窗口到堆栈(假设ui->stackedWidget已设计3个页面)for (int i = 0; i < 3; ++i) {QWidget *page = new QWidget();ui->stackedWidget->addWidget(page);}// 列表选择变化时切换页面connect(ui->listWidget, &QListWidget::currentRowChanged,ui->stackedWidget, &QStackedWidget::setCurrentIndex);
}Dialog::~Dialog() {delete ui;
}
5. QMainWindow(主窗口类)
QMainWindow是Qt中最适合做主窗口的类,内置菜单栏(QMenuBar)、工具栏(QToolBar)、状态栏(QStatusBar)等标准组件,适合开发复杂桌面应用。
5.1 核心组件
-
菜单栏(QMenuBar):通过
addMenu()
添加一级菜单,addAction()
添加菜单项; -
工具栏(QToolBar):通过
addWidget()
或addAction()
添加按钮(通常关联菜单项的QAction); -
状态栏(QStatusBar):通过
showMessage()
显示临时信息,addWidget()
添加固定组件。
5.2 代码示例:主窗口基础结构
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void onNewTriggered(); // 新建文件槽函数void onOpenCppTriggered();// 打开C++文件槽函数private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// 构建菜单栏QMenu *fileMenu = ui->menuBar->addMenu("文件");QAction *newAction = fileMenu->addAction("新建");QAction *openCppAction = fileMenu->addAction("打开C++文件");// 构建工具栏(关联菜单项的QAction)ui->toolBar->addAction(newAction);ui->toolBar->addAction(openCppAction);// 连接信号槽connect(newAction, &QAction::triggered, this, &MainWindow::onNewTriggered);connect(openCppAction, &QAction::triggered, this, &MainWindow::onOpenCppTriggered);
}MainWindow::~MainWindow() {delete ui;
}void MainWindow::onNewTriggered() {ui->textEdit->append("新建文件");ui->statusBar->showMessage("新建文件成功", 2000); // 显示2秒
}void MainWindow::onOpenCppTriggered() {ui->textEdit->append("打开hello.cpp");ui->statusBar->showMessage("已打开hello.cpp");
}
6. 自定义窗口类
通过继承QWidget或QDialog,可创建自定义窗口类,封装特定功能(如绘图、数据展示)。
6.1 创建步骤
-
在Qt Creator中右键项目 → “添加新文件” → 选择“Qt设计师界面类”;
-
设计界面(.ui文件)并生成对应的头文件(.h)和源文件(.cpp);
-
在自定义类中实现业务逻辑(如事件处理、数据交互)。
6.2 代码示例:自定义绘图窗口
// mydialog.h
#ifndef MYDIALOG_H
#define MYDIALOG_H#include <QDialog>
#include <QPainter>namespace Ui {
class MyDialog;
}class MyDialog : public QDialog {Q_OBJECTpublic:explicit MyDialog(QWidget *parent = nullptr);~MyDialog();protected:void paintEvent(QPaintEvent *event) override; // 覆盖绘制事件
};#endif // MYDIALOG_H
// mydialog.cpp
#include "mydialog.h"
#include "ui_mydialog.h"MyDialog::MyDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MyDialog) {ui->setupUi(this);
}MyDialog::~MyDialog() {delete ui;
}void MyDialog::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿// 绘制背景painter.fillRect(rect(), Qt::lightGray);// 绘制圆形painter.setBrush(Qt::blue);painter.drawEllipse(50, 50, 200, 200); // (x,y)为左上角,宽高200
}
7. 对象传值(跨窗口通信)
Qt中跨窗口传值需通过信号槽机制或成员变量共享实现,核心是建立窗口间的关联。
7.1 父→子传值(成员变量共享)
父窗口创建子窗口时,通过成员变量保存子窗口指针,直接调用子窗口的公有方法传值。
7.2 子→父传值(信号槽机制)
子窗口定义带参数的信号,父窗口连接该信号到自己的槽函数,实现子窗口数据传递到父窗口。
7.3 代码示例:双向传值
// dialog.h(父窗口)
#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include "mydialog.h"namespace Ui {
class Dialog;
}class Dialog : public QDialog {Q_OBJECTpublic:explicit Dialog(QWidget *parent = nullptr);~Dialog();private slots:void onOpenChildClicked(); // 打开子窗口按钮点击void onChildValueChanged(int); // 子窗口值变化槽函数private:Ui::Dialog *ui;MyDialog *childDlg; // 子窗口指针
};#endif // DIALOG_H
// dialog.cpp(父窗口)
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {ui->setupUi(this);childDlg = nullptr;
}void Dialog::onOpenChildClicked() {if (!childDlg) {childDlg = new MyDialog(this); // 父窗口为当前窗口connect(childDlg, &MyDialog::valueChanged, this, &Dialog::onChildValueChanged);}childDlg->show();
}void Dialog::onChildValueChanged(int value) {ui->progressBar->setValue(value); // 父窗口进度条同步更新
}
// mydialog.h(子窗口)
#ifndef MYDIALOG_H
#define MYDIALOG_H#include <QDialog>
#include <QSlider>namespace Ui {
class MyDialog;
}class MyDialog : public QDialog {Q_OBJECTpublic:explicit MyDialog(QWidget *parent = nullptr);~MyDialog();signals:void valueChanged(int); // 值变化信号private slots:void onSliderMoved(int); // 滑块移动槽函数private:Ui::MyDialog *ui;
};#endif // MYDIALOG_H
// mydialog.cpp(子窗口)
#include "mydialog.h"
#include "ui_mydialog.h"MyDialog::MyDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MyDialog) {ui->setupUi(this);connect(ui->slider, &QSlider::valueChanged, this, &MyDialog::onSliderMoved);
}void MyDialog::onSliderMoved(int value) {emit valueChanged(value); // 发射信号传递值
}MyDialog::~MyDialog() {delete ui;
}
8. 事件机制(底层交互)
Qt的事件机制是窗口响应用户操作(如点击、键盘输入)的核心,通过事件循环传递事件,开发者可通过覆盖基类事件函数实现自定义行为。
8.1 常见事件类型
-
鼠标事件:
mousePressEvent()
(按下)、mouseReleaseEvent()
(释放)、mouseMoveEvent()
(移动); -
键盘事件:
keyPressEvent()
(按键按下)、keyReleaseEvent()
(按键释放); -
绘制事件:
paintEvent()
(窗口重绘); -
焦点事件:
focusInEvent()
(获得焦点)、focusOutEvent()
(失去焦点); -
关闭事件:
closeEvent()
(窗口关闭前触发)。
8.2 代码示例:键盘控制进度条
// dialog.h
#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QKeyEvent>namespace Ui {
class Dialog;
}class Dialog : public QDialog {Q_OBJECTpublic:explicit Dialog(QWidget *parent = nullptr);~Dialog();protected:void keyPressEvent(QKeyEvent *event) override; // 覆盖键盘按下事件
};#endif // DIALOG_H
// dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) {ui->setupUi(this);
}void Dialog::keyPressEvent(QKeyEvent *event) {switch (event->key()) {case Qt::Key_Up: // 上箭头:进度条+10ui->progressBar->setValue(ui->progressBar->value() + 10);break;case Qt::Key_Down: // 下箭头:进度条-10ui->progressBar->setValue(ui->progressBar->value() - 10);break;case Qt::Key_Space: // 空格:重置进度条ui->progressBar->setValue(0);break;}QDialog::keyPressEvent(event); // 传递事件给父类处理
}Dialog::~Dialog() {delete ui;
}