Qt对话框与窗口的关闭和隐藏(QCloseEvent、Qt::WA_DeleteOnClose属性、Qt::WA_QuitOnClose属性)

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

1、为方便讲解,本文对以下概念作一区别
 删除:是指窗口被销毁,也就是说窗口不存在了。比如窗口使用new创建的,则表示窗口被delete了,被销毁的窗口不能被再次使用,否则会发生内存错误。
 隐藏:是指窗口不可见,但窗口并未被销毁,使用show()等函数,可以让该窗口再次可见。
 关闭:是指窗口不可见,但窗口有可能是被删除了,也有可能是被隐藏了,这要视情况而定。
 窗口被删除时,会同时删除其子对象,而隐藏则不会。
2、关闭窗口与终止程序
一个(应用)程序通常拥有多个窗口,关闭(或删除)一个窗口,并不一定会使程序终止,Qt中关闭窗口使用QWidget::close()槽函数,终止程序使用的是QCoreApplication::quit()静态槽函数或QCoreApplication::exit()静态函数
3、与关闭部件和终止程序有关的属性
注:以下属性其实是Qt::WidgetAttribute枚举的成员,可使用QWidget::setAttribute()函数进行设置和清除。
①、Qt::WA_DeleteOnClose属性:表示当部件接受到QCloseEvent事件时,是否让Qt删除部件。若该属性为true,则删除部件,否则部件只是隐藏。注意:设置了该属性的部件需要使用new创建,否则会产生内存错误。
②、Qt::WA_QuitOnClose属性:表示当拥有该属性的最后一个部件接受到QCloseEvent事件时,让Qt终止应用程序。默认情况下,所有Qt::Window类型的部件都具有该属性。
4、QWidget类中与关闭窗口有关的函数如下:

①、bool QWidget::close();    //槽
   关闭(即删除或隐藏)部件,若部件关闭成功,则返回true,否则返回false。②、virtual void QWidget::closeEvent(QCloseEvent* e);     //虚拟的,受保护的
   这是QCloseEvent事件的处理函数,默认情况下,该函数接受QCloseEvent事件。该函数通常被重新实现,以确定用户是否需要关闭窗口。

5、下面为用于终止程序的函数原型

   ①、static void QCoreApplication::quit();       //静态的,槽
   退出程序,并返回代码0(成功),此函数与调用QCoreApplication::exit(0)等同。该槽函数通常与信号连接使用,比如QPushButton *p = new QPushButton("quit"); QObject::connect( p ,& QPushButton::clicked, &app, &QCoreApplication::quit);②、static void QCoreApplication::exit( int returnCode = 0);   //静态的
   使用returnCode退出程序,通常returnCode为0,表示成功,任何非零值都表示错误。该函数会使程序离开主事件循环,并返回到调用QCoreApplication::exec()处,exec()函数会返回returnCode的值,若事件循环未运行,则该函数什么都不做。

6、close()函数的执行过程如下:
①、首先,向该部件发送QCloseEvent事件(不管部件是否可见)
②、然后判断部件是否接受QCloseEvent事件
 若部件接受该事件(默认值),则继续下一步操作。
 若部件忽略该事件,则取消关闭操作,结束后续的操作。其中最重要的是,不会对Qt::WA_DeleteOnClose属性进行判断,此时该属性不起作用。
③、接着判断部件是否被隐藏了,若未被隐藏,则隐藏,若已被隐藏,则什么也不做。然后继续下一步。
④、再接着判断部件的Qt::_WA_QuitOnClose属性,当具有Qt::WA_QuitOnClose属性的最后一个可见主窗口(即没有父窗口的窗口)被关闭时,会发送QApplication::lastWindowClosed()信号。
⑤、最后判断部件的Qt::WA_DeleteOnClose属性,若该属性为true,则删除该部件,否则什么也不做。至此整个过程结束。
⑥、总结:从以上过程可见,若部件接受QCloseEvent事件,且设置了Qt::WA_DeleteOnClose属性,则会删除该部件,若未设置该属性则只会隐藏该部件。若部件忽略QCloseEvent事件,则直接取消对该部件的关闭操作,该部件既不会被隐藏也不会被删除。由此可见对QCloseEvent事件接受还是忽略决定着对窗口关闭的处理方式,同时对该事件的处理方式与其他事件也是不同的,QCloseEvent::ignore()表示取消关闭操作(也就是说QCloseEvent事件不会被传递给父对象),而QCloseEvent::accept()则表示让Qt继续关闭操作。
7、QCloseEvent事件的发送时机如下:
从窗口菜单选择“关闭”,单击标题栏上的X按钮,调用QWidget::close()函数时。
8、可使用以下方式终止程序
 直接调用quit()或exit()函数
 最后一个具有Qt::WA_QuitOnClose属性的主窗口关闭时,终止程序,若没有这样的主窗口,即使所有的窗口都关闭了程序也不会结束。
9、对话框的关闭过程
对话框的reject()、accept()、done()函数,与QWidget::close()函数相同,唯一的区别是对话框不会发送QCloseEvent事件,因此不能通过QCloseEvent事件来阻止对话框的关闭。注意:此规则仅限于上述3个函数,比如点击对话框窗口的X按钮或右击标题栏选择“关闭”时,仍会发送QCloseEvent事件。若用户在对话框中按下Esc键,会调用QDialog::reject()。为了修改对话框的关闭行为,可以重新实现accept()、reject()或done()函数。
10、删除QObject对象时,会发送destroyed()信号,该信号原型如下:

      void QObject::destroyed(QObject* obj = Q_NULLPTR);    //信号。
   当对象obj被销毁之前发送,且不能被阻止,发送该信号后,对象obj的孩子都会被立即销毁。该信号需配合Qt::WA_DeleteOnClose属性使用,当Qt::WA_DeleteOnClose属性为true的对象被删除时,会发送该信号。直接终止程序的运行,是不会发送该信号的。

示例6.6:关闭一个窗口就结束程序(理解Qt::WA_QuitOnClose属性)

#include<QtWidgets>
int main(int argc, char *argv[]){    QApplication aa(argc,argv);
QWidget w,w1;    QDialog pd;    QDialog pd1;    QDialog pd2;QPushButton *pb=new QPushButton("AAA",&w); w.setWindowTitle("w");    w1.setWindowTitle("w1");
//除窗口w1外,窗口w和对话框的Qt::WA_QuitOnCLose属性都设置为0。w.setAttribute(Qt::WA_QuitOnClose,0);     pd.setAttribute(Qt::WA_QuitOnClose,0);pd1.setAttribute(Qt::WA_QuitOnClose,0);       pd2.setAttribute(Qt::WA_QuitOnClose,0);QObject::connect(pb,&QPushButton::clicked,&pd,&QDialog::show);//点击按钮pb,弹出3个对话框。QObject::connect(pb,&QPushButton::clicked,&pd1,&QDialog::show);QObject::connect(pb,&QPushButton::clicked,&pd2,&QDialog::show);w.resize(300,200);    w.show();   w1.resize(300,200);    w1.show();  return aa.exec();}

运行结果及说明见图6-8

示例6.7:理解Qt::WA_DeleteOnClose属性和destroyed信号

//m.h文件的内容
#ifndef M_H
#define M_H
#include<QtWidgets>
#include<QDebug>
class A:public QObject{Q_OBJECT
public slots:   void f(QObject *p){ qDebug()<<"del="<<p->objectName();} };//输出被删除对象的名称
#endif // M_H//m.cpp文件的内容
#include "m.h"
int main(int argc, char *argv[]){    QApplication aa(argc,argv);QWidget w;    QDialog pd;    QDialog *pd1=new QDialog;    QDialog *pd2=new QDialog;QPushButton *pb=new QPushButton("show",&w);QPushButton *pb1=new QPushButton("quit",&w); pb1->move(77,0);
w.setWindowTitle("w");            pd.setWindowTitle("pd");      //设置窗口标题
pd1->setWindowTitle("pd1");        pd2->setWindowTitle("pd2");
//设置Qt::WA_DeleteOnClose属性pd.setAttribute(Qt::WA_DeleteOnClose,1);  pd1->setAttribute(Qt::WA_DeleteOnClose,1);
w.setObjectName("W");     pd.setObjectName("pd");   //设置对象名pd1->setObjectName("pd1");  pd2->setObjectName("pd2");
A ma;QObject::connect(pb,&QPushButton::clicked,&pd,&QDialog::show);//单击按钮pb弹出3个对话框QObject::connect(pb,&QPushButton::clicked,pd1,&QDialog::show);
QObject::connect(pb,&QPushButton::clicked,pd2,&QDialog::show);
//单击按钮pb1直接终止程序
QObject::connect(pb1,&QPushButton::clicked,&aa,&QApplication::quit);
QObject::connect(&pd,&QDialog::destroyed,&ma,&A::f);//把destroyed信号连接到槽f
QObject::connect(pd1,&QDialog::destroyed,&ma,&A::f);QObject::connect(pd2,&QDialog::destroyed,&ma,&A::f);
w.resize(300,200);    w.show();    return aa.exec();  }

运行结果见图6-9,测试步骤如下

1)、点击show弹出对话框之后,若关闭pd(点击右上角的X按钮),则程序可能会崩溃(因为pd未使用new创建),关闭pd1则会销毁pd1,程序此时输出"del=pd1",关闭pd2,则只会隐藏pd2,因为各窗口之间不存在父子关系,因此本例需点击quit才能正常结束程序(因为最终在关闭窗口pd时,可能会崩溃)。
2)、重新运行程序,点击show按钮,然后关闭pd1和pd2(注意,不要关闭pd),然后再次点击show按钮,对话框pd2会被再次显示,但pd1未被显示(因为被销毁了)。
3)、再次重新运行程序,点击show,弹出3个对话框,然后点击quit直接退出程序,程序无任何输出,可见,信号destroyed未被发射。

示例6.8:关闭窗口时询问用户(QCloseEvent事件的应用)
#ifndef M_H
#define M_H
#include<QtWidgets>
class B:public QWidget{    Q_OBJECT
public:    QDialog *pd1;    QPushButton *pb,*pb1,*pb2,*pb3;B(QWidget* p=0):QWidget(p){pd1=new QDialog(this);    pd1->setWindowTitle("PD1");      pd1->resize(222,111);pb=new QPushButton("close",this); pb1=new QPushButton("exit",this); pb1->move(88,0);pb2=new QPushButton("Yes",pd1);   pb3=new QPushButton("No",pd1);     pb3->move(88,0);connect(pb,&QPushButton::clicked,this,&B::f);connect(pb1,&QPushButton::clicked,this,&B::f1);connect(pb2,&QPushButton::clicked,pd1,&QDialog::accept);connect(pb3,&QPushButton::clicked,pd1,&QDialog::reject);  }
void f(){       close();        }           //调用close()函数关闭窗口,该函数会发送QCloseEvent事件。
void f1(){    QApplication::quit();}    //注意:quit()函数不会产生QCloseEvent事件。
void closeEvent(QCloseEvent* e){    //重新实现closeEvent函数,以处理QCloseEvent事件int i = pd1->exec();          //弹出对话框pd1
//根据用户在对话框中选择的按钮,决定怎样关闭窗口if(i==1)e->accept();           //接受QCloseEvent事件,继续关闭窗口。if(i==0)e->ignore();  }};      //忽略QCloseEvent事件,阻止关闭窗口。
#endif // M_H//m.cpp文件的内容
#include "m.h"
int main(int argc, char *argv[]){    QApplication aa(argc,argv);B w;    w.resize(300,200);    w.show();    return aa.exec();  }

运行结果(见图6-10)及说明

当用户点击窗口qt右上角的X按钮或点击close按
钮时,会弹出对话框PD1,以确定用户是否需要关闭窗
口,当用户点击PD1中的Yes按钮时,会关闭窗口qt,
若点点No按钮,则qt不会被关闭。若用户直接点击qt
中的exit按钮,则程序直接终止,不会弹出对话框。

示例6.9:对话框与QCloseEvent事件
//m.h文件的内容
#ifndef M_H
#define M_H
#include<QtWidgets>
#include <iostream>
using namespace std;
class D:public QDialog{    Q_OBJECT
public:     D(QWidget* p=0):QDialog(p){  }void closeEvent(QCloseEvent* e){   cout<<"D"<<endl;   setResult(2);    }       };
class B:public QWidget{    Q_OBJECT
public:    D *pd1;    QPushButton *pb,*pb1,*pb2,*pb3,*pb4,*pb5;B(QWidget* p=0):QWidget(p){pd1=new D(this);    pd1->setWindowTitle("PD1");    pd1->resize(222,111);
pb=new QPushButton("exec",this); pb1=new QPushButton("show",this);  pb1->move(88,0);pb2=new QPushButton("Yes",pd1);  pb3=new QPushButton("No",pd1);     pb3->move(88,0);pb4=new QPushButton("result",pd1); pb4->move(0,33);connect(pb,&QPushButton::clicked,this,&B::f);connect(pb1,&QPushButton::clicked,this,&B::f1);connect(pb2,&QPushButton::clicked,pd1,&QDialog::accept);connect(pb3,&QPushButton::clicked,pd1,&QDialog::reject);connect(pb4,&QPushButton::clicked,this,&B::f2);  }
void f(){    int i=pd1->exec();    cout<<"exec="<<i<<endl; }
void f1(){  pd1->show();   cout<<"show="<<pd1->result()<<endl;   }
void f2(){    cout<<"result="<<pd1->result()<<endl; }               };
#endif // M_H//m.cpp文件的内容
#include "m.h"
int main(int argc, char *argv[]){    QApplication aa(argc,argv);B w;  w.resize(300,200);  w.show();  return aa.exec();}

运行结果(见图6-11)及说明

1)、验证QCloseEvent事件未触发:点击exec以使用exec()函数显示对话框PD1,点击Yes按钮,程序输出exec=1,可见QDialog::accept()槽函数未触发QCloseEvent事件。
2)、验证exec()函数重置结果代码为0:再次点击exec按钮,显示对话框PD1,然后点击result按钮,程序输出result=0,可见exec()函数把对话框的结果代码重置为0了。
3)、验证QCloseEvent事件被触发:然后点击PD1右上角的X关闭对话框,此时程序输出D,可见此时触发了QCloseEvent事件,此时PD1的结果代码为2。
4)、验证show()不会重置结果代码为0:然后点击show按钮,以使用show()函数显示对话框PD1,此时输出show=2(注意show()函数调用后会立即反回); 然后点击result,输出result=2;可见PD1的结果代码此时为2。然后点击yes按钮关闭对话框,再点击show按钮显示对话框,此时输出show=1;然后点击result,输出result=1;可见show()函数未把结果代码重置为0。

本文作者:黄邦勇帅(原名:黄勇)

Qt对话框与窗口的关闭和隐藏(QCloseEvent、Qt::WA_DeleteOnClose属性、Qt::WA_QuitOnClose属性)相关推荐

  1. js弹出页面窗口和关闭

    原文地址为: js弹出页面窗口和关闭 JS定时自动关闭窗口  <script language="javascript">  <!--  function clo ...

  2. Qt: 窗口的显示和隐藏

    Qt: 窗口的显示和隐藏 隐藏窗口 1. hide() 2. setVisible(false) 3. lower() 4. close() 5. hideEvent() 显示窗口 1. show() ...

  3. qt 对话框关闭以及自动释放内存

    关于窗口关闭的操作,在这里指出常用的三个槽,即quit(),exit()以及close(). 首先说明窗口退出时,系统提示对话框的代码编辑.对主程序的退出,可以调用成员函数exit(),同时也可以调用 ...

  4. Qt的对话框与窗口--Qt中主要的窗体类及其用途

    Qt中主要的窗体类及其用途     常用的窗体基类是QWidget.QDialog和QMainWindow,在创建GUI应用程序时选择窗体基类就是从这3个类中选择.QWidget直接继承于QObjec ...

  5. Qt的对话框与窗口--标准的对话框

    Qt的对话框与窗口--标准的对话框 标准的对话框 QFileDialog对话框 1.选择打开一个文件 2.选择打开多个文件 3.选择已有目录 4.选择保存文件名 QColorDialog对话框 QFo ...

  6. QT怎么设置字体轮廓、字体位置、字体样式、字体间距、窗口背景色大小、隐藏鼠标图标

    QT怎么设置字体轮廓.字体位置.字体样式.字体间距.窗口背景色大小.隐藏鼠标图标 原创 2017年12月14日 19:05:21 标签: qt / ui 277 在qt中经常会对字体设置一些属性字体轮 ...

  7. 【技术】Qt对话框讲解

    前言 Qt中对话框QDialog是几乎每个项目都会用到的GUI窗口对象.本文通过讲解QDialog及其子类在项目中经常被用到的功能点,帮助小伙伴们理解和掌握其使用方法. QDialog QDialog ...

  8. Qt对话框的事件循环分析(子线程中不能创建UI窗体分析)

    重要: GUI线程和辅助线程 如前所述,每个程序在启动时都有一个线程.这个线程被称为"主线程"(在Qt应用程序中也称为"GUI线程").Qt GUI必须在这个线 ...

  9. Qt对话框的事件循环分析(子线程中不能创建UI窗体分析2)

    Qt事件机制 QT-UI 后端 重要: GUI线程和辅助线程 如前所述,每个程序在启动时都有一个线程.这个线程被称为"主线程"(在Qt应用程序中也称为"GUI线程&quo ...

  10. Hello Qt(十九)——QT对话框

    一.对话框简介 对话框是与用户进行简短交互的顶层窗口 QDialog是QT中所有对话框窗口的基类,QDialog继承于QWidget,是一种容器型的组件,是定制了窗口样式的特殊QWidget. QDi ...

最新文章

  1. 面向对象编程概念_如何向6岁的孩子解释面向对象的编程概念
  2. 学习junit和hamcrest的使用
  3. Linux-PAM PAM-MySQL的总结
  4. 【毕业求职季】-听说你想去大厂看学妹,带你看看腾讯微信产品岗面经(已offer)
  5. 1008 Elevator (20 分)【难度: 简单 / 知识点: 模拟】
  6. boost::io::quoted用法的测试程序
  7. go路由httprouter中的压缩字典树算法图解及c++实现
  8. 把块存放在页高速缓存中
  9. 孔浩老师的java视频
  10. 网页传奇服务器端,拍拍科技武易传奇神鸟归来商业版+网站
  11. iOS 下载和播放 M3U8
  12. 单词首字母大写 (5分)
  13. 慎用!wordpress的额外css功能会浪费id资源!
  14. Redis之EXPIRE
  15. 康奈尔大学计算机科学人工智能,康奈尔大学计算机科学系
  16. 华硕ROG冰刃5和枪神5有什么区别 哪个好
  17. 利用SOP激活沉默用户
  18. MFC自用小工具源码
  19. 云原生(二十七) | Kubernetes篇之自建高可用k8s集群前置概念与操作
  20. 实名报名超5000人!RTE2022即将开幕,声网发布RTE行业首本专业书《实时万象》

热门文章

  1. 分享ASP.NET视频系列教程——第十九讲 ASP.NET内置的AJAX
  2. “开会” 引发的思考
  3. word文档怎么到下一页去写_word文档怎么插入下一页
  4. 拟物化设计与扁平化设计
  5. linux中,ls -l命令显示的total的含义。
  6. wps-doc文件输出为pdf文件时目录报错“错误!未定义书签”解决方法
  7. 图像颜色与强度分离(intensity and color decouple)方法 matlab代码
  8. acs代表什么_思科的ACS是什么?
  9. Python dataframe绘制饼图_Python可视化29|matplotlib-饼图(pie)
  10. matlab输出相反数,在MATLAB将等于某一数列相反数的数据都赋值为0