六、多窗口编程详解(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);

  •  

    ​窗口层级​​:parentnullptr时,对象是独立窗口;否则是父窗口的子窗口(内嵌显示)。

​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 创建步骤​
  1.  

    在Qt Creator中右键项目 → “添加新文件” → 选择“Qt设计师界面类”;

  2.  

    设计界面(.ui文件)并生成对应的头文件(.h)和源文件(.cpp);

  3.  

    在自定义类中实现业务逻辑(如事件处理、数据交互)。

​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;
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐