多窗口编程

六、多窗口编程

  1. QMessageBox消息对话框(掌握)

QMessageBox继承自QDialog,显示一个模态对话框。用于用户前台信息通知或询问用户问题,并接收问题答案。

QDialog的Qt源码中,派生类往往都是一些在特定场合下使用的预设好的对话框窗口,这些窗口无需创建对象,直接使用静态成员函数弹窗,使用函数的返回值作为这个窗口的结果。

复制代码
// 参数1:parent参数`
`// 参数2:窗口标题`
`// 参数3:信息内容,窗口展示的信息`
`// 返回值:用户点击的按钮类型`
`StandardButton	critical(QWidget * parent, const QString & title, const QString & text)`
`StandardButton	information(QWidget * parent, const QString & title, const QString & text)`
`StandardButton	question(QWidget * parent, const QString & title, const QString & text)`
`StandardButton	warning(QWidget * parent, const QString & title, const QString & text)`
`[static]`
`

dialog.cpp

复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

`Dialog::Dialog(QWidget *parent) :`
`    QDialog(parent),`
`    ui(new Ui::Dialog)`
`{`
`    ui->setupUi(this);`
`    btp = new QButtonGroup(this);`
`    btp->addButton(ui->pushButtonQ,1);`
`    btp->addButton(ui->pushButtonI,2);`
`    btp->addButton(ui->pushButtonW,3);`
`    btp->addButton(ui->pushButtonC,4);`

`    connect(btp,SIGNAL(buttonClicked(int)),`
`            this,SLOT(buttonClickedSlot(int)));`
`}`

`Dialog::~Dialog()`
`{`
`    delete ui;`
`}`

`void Dialog::buttonClickedSlot(int id)`
`{`
`    if(id == 1)`
`    {`
`        // 设置弹窗  question`
`       QMessageBox::StandardButton stdb = QMessageBox::question(this,"question","是否需要关闭?");`
`       if(stdb == QMessageBox::Yes)`
`       {`
`           close();`
`       }`
`       else if(stdb == QMessageBox::No)`
`       {`

`       }`
`    }`
`    else if(id == 2)`
`    {`
`        // 设置弹窗 Information`
`        QMessageBox::information(this,"information","已加载完成!");`
`    }`
`    else if(id == 3)`
`    {`
`        // 设置弹窗 warning`
`        QMessageBox::warning(this,"warning","您的输入有误!");`
`    }`
`    else if(id == 4)`
`    {`
`        QMessageBox::critical(this,"critical","程序异常404,缺少必要文件");`
`    }`
`    else`
`    {`

`    }`
`}`

`
  1. QWidget类(掌握)

QWidget类时所有窗口和组件的基类,之前认识此类更多的是站在组件的角度上,实际上QWidget本身身为所有窗口的基类,也具有很多窗口的特性。

新建一个项目,使自带窗口继承自QWidget

创建完成后运行时发现,与dialog的窗口并无太大区别,表面区别有。

复制代码
#include "widget.h"`
`#include <QApplication>`

`int main(int argc,` `char` `*argv[])`
`{`
    `QApplication` `a(argc, argv);`
    `// 当QWidget的构造函数parent参数使用默认值0时。表示创建的是独立窗口`
    `// 当QWidget的构造函数parent参数传递参数时,新创建的QWidget类对象会作为组件内嵌到父窗口中(内嵌窗口)`
    `Widget w;`
`    w.show();`

    `return a.exec();`
`}`

`

QWidget类作为所有窗口的基类,内部也规定了很多窗口的特性:

  • windowFlags : Qt::WindowFlags(窗口标记)

在使用seter函数设置多个标记时,使用 | 分割(多个窗口标记之间可能会存在冲突)。

实现窗口置于最上层,且没有边框。

复制代码
setWindowFlags(Qt::FramelessWindowHint |Qt::WindowStaysOnTopHint);`

`

setWindowState

复制代码
// 设置窗口状态`
`// 参数为要设置的状态`
`void QWidget::​setWindowState(Qt::WindowStates windowState)`
`
复制代码
#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参数(掌握)

目前对parent参数的理解有以下几点:

  • parent参数表示子组件位于那个窗口中。
  • parent参数决定了QWidget对象是独立的还是内嵌窗口。

实际上parent参数还表示Qt的内存回收机制,如果对象a作为对象b构造函数时的parent参数,表示对象a是对象b的父对象。这是一种内存回收机制的依赖关系,即对象b跟随对象a一并销毁。此时无需手动控制对象b的销毁过程(手动调用delete)。

如果堆内存对象创建时不传递parent参数,表示对象调用需要程序员手动delete。

绝大多数情况下,建议堆内存对象传递parent参数。

这样做也有缺点, 缺点就是内存占用,主窗口还存在时,子窗口内存不会被释放掉。

复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

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

`    connect(ui->pushButton0,SIGNAL(clicked()),this,`
`            SLOT(buttonClickedSlot()));`
`    connect(ui->pushButtonThis,SIGNAL(clicked()),this,`
`            SLOT(buttonThisClickedSlot()));`
`}`

`Dialog::~Dialog()`
`{`
`    qDebug() << "析构函数";`
`    delete ui;`
`}`

`void Dialog::buttonClickedSlot()`
`{`
`    Dialog *dlg = new Dialog;`
`    dlg->show();`
`}`

`void Dialog::buttonThisClickedSlot()`
`{`
`    Dialog * dlg = new Dialog(this);`
`    dlg->show();`
`}`

`

4、堆栈窗口(QStackedWidget)(熟悉)

通常作为独立的内嵌窗口(组件),并于QListWidget进行联动。

dialog.cpp

复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

`Dialog::Dialog(QWidget *parent) :`
`    QDialog(parent),`
`    ui(new Ui::Dialog)`
`{`
`    ui->setupUi(this);`
`    // 连接信号槽`
`    connect(ui->listWidget,SIGNAL(currentRowChanged(int)),`
`            ui->stackedWidget,SLOT(setCurrentIndex(int)));`
`}`

`Dialog::~Dialog()`
`{`
`    delete ui;`
`}`

`

5、QMainWindow主窗口类(重点)

QMainWindow是最适合作为主窗口的类型,因为包含多个组成部分。

5.1 QMenuBar菜单栏

菜单栏的组成如下所示:

相关函数如下:

复制代码
// 向菜单栏中添加一级菜单`
`// 参数为菜单的文字`
`// 返回值是添加的菜单对象`
`QMenu * QMenuBar::​addMenu(const QString & title)`
`
复制代码
// 向菜单栏中添加动作`
`// 参数为动作的文字`
`// 返回值是添加的动作对象`
`QAction * QMenu::​​addAction(const QString & text)`
`
复制代码
// 向菜单中添加菜单`
`// 参数为菜单显示的文字`
`// 返回值是新添加的菜单对象`
`QMenu * QMenu::​addMenu(const QString & title)`
`

dialog.cpp

复制代码
#include "mainwindow.h"`
`#include "ui_mainwindow.h"`

`MainWindow::MainWindow(QWidget *parent) :`
`    QMainWindow(parent),`
`    ui(new Ui::MainWindow)`
`{`
`    ui->setupUi(this);`
`    QMenu *menuFile = ui->menuBar->addMenu("文件");`
`    QMenu *menuEdit = ui->menuBar->addMenu("编辑");`
`    QMenu *menuHelp = ui->menuBar->addMenu("帮助");`

`    // 向一级菜单中添加动作`
`    QAction *actionNew = menuFile->addAction("新建");`
`    QAction *actionOpen = menuFile->addAction("打开");`
`    QAction *actionClose = menuFile->addAction("关闭");`

`    // 向一级菜单中添加二级菜单`
`    QMenu *menuRecent = menuFile->addMenu("访问最近的文件");`

`    // 向二级菜单中添加动作`
`    QAction *actionCpp = menuRecent->addAction("hello.cpp");`
`    QAction *actionH = menuRecent->addAction("hello.h");`

`}`

`MainWindow::~MainWindow()`
`{`
`    delete ui;`
`}`

`

信号函数:

dialog.cpp

复制代码
#include "mainwindow.h"`
`#include "ui_mainwindow.h"`

`MainWindow::MainWindow(QWidget *parent)` `:`
    `QMainWindow(parent),`
    `ui(new Ui::MainWindow)`
`{`
`    ui->setupUi(this);`
`    QMenu *menuFile = ui->menuBar->addMenu("文件");`
`    QMenu *menuEdit = ui->menuBar->addMenu("编辑");`
`    QMenu *menuHelp = ui->menuBar->addMenu("帮助");`

    `// 向一级菜单中添加动作`
`    QAction *actionNew = menuFile->addAction("新建");`
`    QAction *actionOpen = menuFile->addAction("打开");`
`    QAction *actionClose = menuFile->addAction("关闭");`

    `// 向一级菜单中添加二级菜单`
`    QMenu *menuRecent = menuFile->addMenu("访问最近的文件");`

    `// 向二级菜单中添加动作`
`    QAction *actionCpp = menuRecent->addAction("hello.cpp");`
`    QAction *actionH = menuRecent->addAction("hello.h");`

    `connect(actionCpp,SIGNAL(triggered()),`
            `this,SLOT(triggeredCppSlot()));`
    `connect(actionH,SIGNAL(triggered()),`
            `this,SLOT(triggeredHSlot()));`

`}`

`MainWindow::~MainWindow()`
`{`
    `delete ui;`
`}`

`void` `MainWindow::triggeredHSlot()`
`{`
`    ui->textEdit->append("打开一个.h文件");`
`}`

`void` `MainWindow::triggeredCppSlot()`
`{`
`    ui->textEdit->append("打开一个.Cpp文件");`
`}`

`

5.2 QToolBar工具栏

工具栏往往是使用菜单栏中的QAction对象,但是需要给QAction设置图标。

dialog.cpp

复制代码
#include "mainwindow.h"`
`#include "ui_mainwindow.h"`

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

`    connect(ui->action_4,SIGNAL(triggered()),`
`            this,SLOT(triggeredSaveSlot()));`
`    // 在状态栏展示信息`
`    ui->mainToolBar->addAction(ui->action_5);`
`}`

`MainWindow::~MainWindow()`
`{`
`    delete ui;`
`}`

`void MainWindow::triggeredSaveSlot()`
`{`
`    ui->textEdit->append("保存了");`
`}`

`

5.3 QStatusBar 状态栏

复制代码
// 在状态栏中展示信息`
`// 参数1:展示的信息内容`
`// 参数2:信息显示的时间(单位毫秒),默认0表示持续显示`
`void QStatusBar::​showMessage(const QString & message, int timeout = 0)[slot]`
`
复制代码
// 清空显示`
`void QStatusBar::​clearMessage()[slot]`
`
复制代码
#include "mainwindow.h"`
`#include "ui_mainwindow.h"`

`MainWindow::MainWindow(QWidget *parent)` `:`
    `QMainWindow(parent),`
    `ui(new Ui::MainWindow)`
`{`
`    ui->setupUi(this);`
`    lab =` `new` `QLabel(this);`
`    QLabel *lab2 =` `new` `QLabel(this);`
`    lab->setText("显示的内容");`
`    lab2->setText("2222");`
`    ui->statusBar->addWidget(lab2);`
`    ui->statusBar->addWidget(lab);`


    `connect(ui->action_4,SIGNAL(triggered()),`
            `this,SLOT(triggeredSaveSlot()));`

    `connect(ui->action_5,SIGNAL(triggered()),`
            `this,SLOT(triggeredCloseSlot()));`

`}`

`MainWindow::~MainWindow()`
`{`
    `delete ui;`
`}`

`void` `MainWindow::triggeredSaveSlot()`
`{`
`//    ui->textEdit->append("保存了");`
`//    ui->statusBar->showMessage("保存成功",99999);`
`//    ui->statusBar->showMessage("保存111111",99999);`
`}`

`void` `MainWindow::triggeredCloseSlot()`
`{`
`//    ui->textEdit->append("清除成功");`
`//    ui->statusBar->clearMessage();`
`}`

`

6、新建自定义窗口类

在一个项目中创建一个Qt的窗口界面类,操作步骤如下:

  1. 在Qt Creator中选中项目名称,鼠标右键,点击"添加新文件"。
  2. 在弹出的窗口中,按照下图所示操作。
  1. 在弹出的窗口中选择界面模板后,点击"下一步"。
  1. 在弹窗的窗口中,输入类型(注意帕斯卡/大驼峰命名法),然后点击下一步。
  1. 在项目管理界面中,点击完成,可以看到新的窗口类文件已经添加到项目中了。

dialog.cpp

复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

`Dialog::Dialog(QWidget *parent) :`
`    QDialog(parent),`
`    ui(new Ui::Dialog)`
`{`
`    ui->setupUi(this);`
`    connect(ui->pushButton,SIGNAL(clicked()),`
`            this,SLOT(btnClickedSlot()));`
`}`

`Dialog::~Dialog()`
`{`
`    delete ui;`
`}`

`void Dialog::btnClickedSlot()`
`{`
`    MyDialog *mydlg = new MyDialog(this);`
`    mydlg->show();`
`}`

`
  1. 对象传值(重点)

7.1 父对象→子对象

此处指的是Qt的parent参数的依赖关系,并非继承关系(后文同)。

[需求]:转动主窗口球,子窗口跟着转。

dialog.cpp

复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

`Dialog::Dialog(QWidget *parent) :`
`    QDialog(parent),`
`    ui(new Ui::Dialog)`
`{`
`    ui->setupUi(this);`
`    mydlg = new MyDialog(this);`
`    connect(ui->pushButton,SIGNAL(clicked()),`
`            this,SLOT(btnClickedSlot()));`
`    connect(ui->dial,SIGNAL(valueChanged(int)),`
`            this,SLOT(valueChangedSlot(int)));`

`}`

`Dialog::~Dialog()`
`{`
`    delete ui;`
`}`

`void Dialog::btnClickedSlot()`
`{`
`    mydlg->show();`
`}`

`void Dialog::valueChangedSlot(int value)`
`{`
`   mydlg->setValue(value);`
`}`

`

7.2 子对象→父对象

【需求】:转动子对象球,父对象球跟着转。

这种情况最佳的解决方案信号槽传参,子对象发射带参数的信号函数,父对象使用带参数的槽函数接收。

mydilog.cpp

复制代码
#include "mydialog.h"`
`#include "ui_mydialog.h"`

`MyDialog::MyDialog(QWidget *parent)` `:`
    `QDialog(parent),`
    `ui(new Ui::MyDialog)`
`{`
`    ui->setupUi(this);`
    `connect(ui->dial,SIGNAL(valueChanged(int)),`
            `this,SLOT(valueChangeSlot(int)));`
`}`

`MyDialog::~MyDialog()`
`{`
    `delete ui;`
`}`

`void` `MyDialog::setValue(int value)`
`{`
`    ui->dial->setValue(value);`
`}`

`void` `MyDialog::valueChangeSlot(int value)`
`{`
    `// 发射带参数的自定义信号给父对象`
`    emit valueSignal(value);`
`}`

`

dialog.cpp

复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

`Dialog::Dialog(QWidget *parent)` `:`
    `QDialog(parent),`
    `ui(new Ui::Dialog)`
`{`
`    ui->setupUi(this);`
`    mydlg =` `new` `MyDialog(this);`
    `connect(ui->pushButton,SIGNAL(clicked()),`
            `this,SLOT(btnClickedSlot()));`

    `connect(ui->dial,SIGNAL(valueChanged(int)),`
            `this,SLOT(valueChangedSlot(int)));`

    `connect(mydlg,SIGNAL(valueSignal(int)),`
            `this,SLOT(valueSlot(int)));`

`}`

`Dialog::~Dialog()`
`{`
    `delete ui;`
`}`

`void` `Dialog::btnClickedSlot()`
`{`
`    mydlg->show();`
`}`

`void` `Dialog::valueChangedSlot(int value)`
`{`
`    mydlg->setValue(value);`
`}`

`void` `Dialog::valueSlot(int value)`
`{`
`    ui->dial->setValue(value);`
`}`

`

8、事件机制(掌握)

事件时Qt的一种底层机制,经过层层传递,用户输出可以得到处理。程序员也可以使用对应的消息处理函数,来处理当前发生的事件。

本次学习主要在窗口类中实现事件函数,从而检测到事件的传递,利用事件的触发机制,从而实现一些特定的效果。

复制代码
// 绘制事件`
`void QWidget::paintEvent(QPaintEvent * event) [virtual protected] `

`// 大小改变事件`
`void QWidget::resizeEvent(QResizeEvent * event) [virtual protected] `

`// 鼠标按压事件`
`void QWidget::mousePressEvent(QMouseEvent * event) [virtual protected]`
`// 鼠标释放事件`
`void QWidget::mouseReleaseEvent(QMouseEvent * event) [virtual protected]`
`// 鼠标双击事件`
`void QWidget::mouseDoubleClickEvent(QMouseEvent * event) [virtual protected]`
`// 鼠标移动事件`
`void QWidget::mouseMoveEvent(QMouseEvent * event) [virtual protected]`

`// 移动事件`
`void QWidget::moveEvent(QMoveEvent * event) [virtual protected]`

`// 按键按压事件`
`void QWidget::keyPressEvent(QKeyEvent * event) [virtual protected]`
`// 按键释放事件`
`void QWidget::keyReleaseEvent(QKeyEvent * event) [virtual protected]`

`// 获取焦点事件`
`void QWidget::focusInEvent(QFocusEvent * event) [virtual protected]`
`// 失去焦点事件`
`void QWidget::focusOutEvent(QFocusEvent * event) [virtual protected]`

`// 关闭事件`
`void QWidget::closeEvent(QCloseEvent * event) [virtual protected]`

`// 鼠标进入事件`
`void QWidget::enterEvent(QEvent * event) [virtual protected]`
`// 鼠标离开事件`
`void QWidget::leaveEvent(QEvent * event) [virtual protected]`

`

事件函数的基础使用只需要在对应的类中覆盖基类的事件函数即可。事件函数的参数就是包含当前事件数据的对象。

复制代码
// 绘制图片`
`// 参数1:横坐标`
`// 参数2:纵坐标`
`// 参数3:绘制宽度`
`// 参数4:绘制高度`
`// 参数5:绘制`
`void QPainter::​drawPixmap(int x, int y, int width, int height, const QPixmap & pixmap)`
`
复制代码
#include "dialog.h"`
`#include "ui_dialog.h"`

`Dialog::Dialog(QWidget *parent)` `:`
    `QDialog(parent),`
    `ui(new Ui::Dialog)`
`{`
`    ui->setupUi(this);`
`}`

`Dialog::~Dialog()`
`{`
    `delete ui;`
`}`

`void` `Dialog::paintEvent(QPaintEvent *event)`
`{`
    `// 创建一个画家对象`
    `// 参数为QPaintDevice * 表示可绘制对象`
`    QPainter painter(this);`
`    QPixmap map(":/new/prefix1/fengjing.png");`
`    painter.drawPixmap(0,0,this->width(),this->height(),map);`

    `qDebug()` `<<` `this->width()` `<<` `this->height();`
`}`

`void` `Dialog::keyPressEvent(QKeyEvent *event)`
`{`
    `if(event->key()` `== Qt::Key_A)`
    `{`
        `int value = ui->progressBar->value();`
`        ui->progressBar->setValue(--value);`
    `}`
    `else` `if(event->key()` `== Qt::Key_D)`
    `{`
        `int value = ui->progressBar->value();`
`        ui->progressBar->setValue(++value);`
    `}`
    `else` `if(event->key()` `== Qt::Key_W)`
    `{`
`        ui->progressBar->setValue(100);`
    `}`
    `else` `if(event->key()` `== Qt::Key_S)`
    `{`
`        ui->progressBar->setValue(0);`
    `}`
    `else`
    `{`

    `}`
`}`
`
相关推荐
fanged19 分钟前
裸机编一个Hello World!(TODO)
嵌入式
FreakStudio8 小时前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
python·嵌入式·面向对象·电子diy
锦亦之22339 小时前
QT+OSG+OSG-earth如何在窗口显示一个地球
开发语言·qt
柳鲲鹏12 小时前
编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MinGW版)
开发语言·qt·mysql
三玖诶12 小时前
如何在 Qt 的 QListWidget 中逐行添加和显示数据
开发语言·qt
辰哥单片机设计12 小时前
门磁模块详解(防盗感应开关 STM32)
stm32·单片机·嵌入式硬件·传感器
weixin_6320776312 小时前
udp聊天室
udp·网络编程·嵌入式·编程·聊天室
yrx02030713 小时前
stm32 IIC总线busy解决方法
stm32·单片机·嵌入式硬件
YHPsophie14 小时前
ATGM331C-5T杭州中科微BDS/GNSS全星座定位授时模块应用领域
经验分享·笔记·单片机·信息与通信·交通物流