QT(5)
本文详细介绍了Qt框架中的多窗口编程技术,主要包括: QMessageBox模态对话框的四种类型及使用方法 QWidget窗口基类的特性和属性控制 parent参数在对象树和内存管理中的关键作用 QStackedWidget堆叠窗口的实现原理 QMainWindow主窗口的标准组件和结构 自定义窗口类的创建步骤和实现方法 跨窗口通信的两种实现方式 Qt事件机制和常见事件处理方法 通过代码示例展示了
六、多窗口编程详解(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_OBJECT
public:
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=1
btnGroup->addButton(ui->btnInfo, 2); // 按钮ID=2
btnGroup->addButton(ui->btnWarning, 3); // 按钮ID=3
btnGroup->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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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: // 上箭头:进度条+10
ui->progressBar->setValue(ui->progressBar->value() + 10);
break;
case Qt::Key_Down: // 下箭头:进度条-10
ui->progressBar->setValue(ui->progressBar->value() - 10);
break;
case Qt::Key_Space: // 空格:重置进度条
ui->progressBar->setValue(0);
break;
}
QDialog::keyPressEvent(event); // 传递事件给父类处理
}
Dialog::~Dialog() {
delete ui;
}
更多推荐
所有评论(0)