多窗口编程

六、多窗口编程

  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参数的依赖关系,并非继承关系(后文同)。

需求\]:转动主窗口球,子窗口跟着转。 ![](https://file.jishuzhan.net/article/1761298483676975105/d6d0feaeb0dc4c6db572c02a31884a76.webp) ![](https://file.jishuzhan.net/article/1761298483676975105/565f7e7c4aac1d762774eab2456e35de.webp) 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 子对象→父对象** 【需求】:转动子对象球,父对象球跟着转。 这种情况最佳的解决方案信号槽传参,子对象发射带参数的信号函数,父对象使用带参数的槽函数接收。 ![](https://file.jishuzhan.net/article/1761298483676975105/84ac87470f74204f62103d2ded686bc1.webp) 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的一种底层机制,经过层层传递,用户输出可以得到处理。程序员也可以使用对应的消息处理函数,来处理当前发生的事件。 ![](https://file.jishuzhan.net/article/1761298483676975105/149b5368b1376fa84c52ad8c8836ad32.webp) 本次学习主要在窗口类中实现事件函数,从而检测到事件的传递,利用事件的触发机制,从而实现一些特定的效果。 ``` // 绘制事件` `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` `{` `}` `}` ` ```

相关推荐
青牛科技-Allen1 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森3 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白3 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D3 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术6 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt7 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘7 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang7 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
Mr_Xuhhh9 小时前
网络基础(1)
c语言·开发语言·网络·c++·qt·算法
几个几个n9 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件