Qt对话框与窗口的关闭和隐藏

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。

猜你喜欢

转载自blog.csdn.net/weixin_41882459/article/details/113729496