QT中的模态对话框及非模态对话框
- [1] QT中的模态对话框及非模态对话框
- [2] Qt工作笔记-主界面往模式对话框emit信号,有注意的问题
- 正常情况下:
- 不正常情况下:
- 下面给出正常情况下的代码:
[1] QT中的模态对话框及非模态对话框
原文链接:https://blog.csdn.net/u011555996/article/details/108110925
模态对话框(Modal Dialog)与非模态对话框(Modeless Dialog)的概念不是Qt所独有的,在各种不同的平台下都存在。又有叫法是称为模式对话框,无模式对话框等。所谓模态对话框就是在其没有被关闭之前,用户不能与同一个应用程序的其他窗口进行交互,直到该对话框关闭。对于非模态对话框,当被打开时,用户既可选择和该对话框进行交互,也可以选择同应用程序的其他窗口交互。
在Qt中,显示一个对话框一般有两种方式,一种是使用exec()方法,它总是以模态来显示对话框;另一种是使用show()方法,它使得对话框既可以模态显示,也可以非模态显示,决定它是模态还是非模态的是对话框的modal属性。
在Qt中,Qt的模态与非模态对话框选择是通过其属性modal来确定的。我们来看看modal属性,其定义如下:
modal : bool默认情况下,对话框的该属性值是false,这时通过show()方法显示的对话框就是非模态的。而如果将该属性值设置为true,就设置成了模态对话框,其作用于把QWidget::windowModality属性设置为Qt::ApplicationModal。
而使用exec()方法显示对话框的话,将忽略modal属性值的设置并把对话框设置为模态对话框。
一般使用setModal()方法来设置对话框的modal属性。
我们总结一下设置对话框为模态的方法。
◆ 如果要设置为模态对话框,最简单的就是使用exec()方法,示例代码如下:
MyDialog myDlg;
myDlg.exec();
//也可以使用show()方法,示例代码如下:
MyDialog myDlg;
myDlg.setModal(true);
myDlg.show();
◆ 如果要设置为非模态对话框,必须使用show()方法,示例代码如下:
MyDialog myDlg;
myDlg.setModal(false);
//或者
myDlg.setModal();
myDlg.show();
再次强调,目前有的朋友对于模态对话框和非模态对话框的认识有误解,认为使用show()方法显示的就是非模态对话框,这是不正确的。
小贴士:有时候,我们需要一个对话框以非模态的形式显示,但又需要它总在所有窗口的最前面,这时可以通过如下代码设置:
MyDialog myDlg;
myDlg.setModal(false);
//或者
myDlg.setModal();
myDlg.show();
//关键是下面这行
myDlg.setWindowFlags(Qt::WindowStaysOnTopHint);
在Qt中创建模态对话框,主要用到了QDialog的exec函数:
SonDialog dlg(this);
int res = dlg.exec();
if (res == QDialog::Accepted)
{
QMessageBox::information(this, “INFORMATION”, “You clicked OK button!”);
}
if (res == QDialog::Rejected)
{
QMessageBox::information(this, “INFORMATION”, “You clicked CANCEL button!”);
}
正如上面代码所显示的,可以通过exec函数的返回值来判断用户点击了哪个按钮使得模态对话框退出的,这可以使得我们能够根据用户的不同行为在退出模态对话框之后采取不同的处理方法。
既然new了,如果不delete,那么内存不就存在了泄露的问题了吗?确实如此!所以,我们希望该Qt窗口在退出时自动能够delete掉自己,因此,我们在SonDialog的构造函数里,添加这样的一句代码:
setAttribute (Qt::WA_DeleteOnClose);
这样,我们的SonDialog就能够在它退出时自动的delete掉自己了,不会再造成内存泄漏问题。
Qt中存在“窗口”与“部件”的区分,但“窗口”的概念太过浅显,以至于可以忽略不谈。但有时候还是多少有些了解为好。
很多书上说,Qt中吧没有嵌入到其他部件中的部件成为“窗口”,而这种“窗口”都包含有边框和标题栏。“窗口”就是没有父窗口(或部件)的部件,又称为顶级部件。但在实际开发过Qt程序的工程师看来,这种说法有点欠佳。“窗口是没有嵌入到其他部件的部件“这个好理解,但是“窗口”就是没有父部件的部件?QDialog为窗口是毋庸置疑的吧,但是在使用对话框时为其指定父窗口也是在正常不过了。例如,当我点击主窗口某个按钮时弹出个提示对话框:
QDialog dlg(this);
dlg.exec();
弹出的Dialog一样具有边框和标题栏,难道这种具有父部件的对话框就是不是窗口了?很多人难以接受吧! 所以,一个QWidget是窗体还是窗体上的控件和是否有父类无关,只与窗口标记类型有关,也只有窗口flag才能直接说明此部件是否为窗口!设置或修改部件类型:setWindowFlags(Qt::Window)
但是也无需怀疑很多书本的可靠性,其实书上说的也没错,只是不够深入。例如:
QPushButton * pPushBtn = new QPushButton(this);
//当没有父类时,构造函数就会加上Qt::Window标记
QPushButton * pPushBtn = new QPushButton;
因为,当没有指定父窗口(部件)时都是默认设置了Qt::Window标记的。再如:
//不管有无父类都为窗体,因为向QWidget传参数时传递了Qt::Dialog标记.
QDialog * dlg = new QDialog(this);
因此,QDialog是个独特的部件,无论有无指定父部件,其生来就是Window!
总而言之:所以使QWidget变成Window(窗体)只能使用setWindowFlags(Qt::Window); !!!在使用Qt是一般不考虑窗口的概念,较多情况下都直接使用QWidget就行了,对于自定义部件也是如此。对于之前做过VC的选手可能习惯了使用CDialog,但在Qt中QDialog却没那么受待见,熟练使用QWidget才是王道。
对于 QDialog 的模态及非模态是直接可以实现的,很多课本中都会提到,此处总结下。
模态QDialog
方式一:
QDialog dlg(this);
dlg.exec();
方式二:
QDialog *pDlg=new QDialog(this);
pDlg->setModal(true);
pDlg->show();
非模态QDialog
QDialog *pDlg=new QDialog(this);
pDlg->show();
QDialog实现模态非模态很简单,但是对于QWidget有点迷茫,QWidget中没有exec(),也没有setModal()方式,但是想想看,QWidget作为QDialog的基类,而且QWidget作为“窗口”使用也是在平常不过了,所以会意识到QWidget中是否存在一个相对exec()或setModal()更基本的操作来实现模态和非模态呢?就这样,我找到了setWindowModality(),此函数就是用来设置QWidget运行时的程序阻塞方式的,参数解释如下:
Qt::NonModal 不阻塞
Qt::WindowModal 阻塞父窗口,所有祖先窗口及其子窗口
Qt::ApplicationModal 阻塞整个应用程序
看来,setModal()也就是使用setWindowModality()设置Qt::ApplicationModal参数也实现的模态。
如此,要实现QWidget的模态和非模态,只要调用setWindowModality()设置阻塞类型就好了:
QWidget *pWid = new QWidget(this);
pWid->setWindowModality(Qt::ApplicationModal);
//pWid->setAttribute(Qt::WA_ShowModal, true);
pWid->show();
但是运行发现并未实现模态效果。这里需要注意,当希望使用setWindowModality()将QWidget设置为模态时应该保证QWidget父部件为0,这里修改
QWidget *pWid = new QWidget(this);
为
QWidget *pWid = new QWidget(NULL);
在运行就好了。
此外,通过setWindowModality()设置模态窗口并不是唯一方式,直接设置部件(或窗口)属性也可以:
pWid->setAttribute(Qt::WA_ShowModal, true)
还有很多地方需要注意,当创建QDialog后使用setWindowFlags(Qt::FramelessWindowHint);去掉标题栏时此对话框不再阻塞父窗口,如果需要实现阻塞效果可再次指定Qt::Dialog,即使用:
setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); //这样就会阻塞父窗口了!
但是,这样会影响对话框的半透明(或透明)显示。使用Qt::Dialog之前半透明显示正常:
使用之后却死活不行了:
– 不知道如何是好!
总而言之
是否是模态和QDialog 和QWidget都可以模态和非模态.exec(), show() 等函数无直接关系,只和窗口属性有关,使用以下两种方式都行:
setAttribute(Qt::WA_ShowModal, true);//属性设置
setWindowModality(Qt::ApplicationModal);//设置阻塞类型
QDialog中的成员函数setModal(true)及exec()之所以是模态是因为他先设置了窗口属性:setAttribute()再show()的
模态对话框:指该对话框关闭之前不可以对其他窗口进行操作,只有等该对话框关闭之后才可以操作其他窗口。
非模态对话框:该对话框激活的情况下也可以对其他窗口进行操作。
模态对话框:
Qdialog dlg;
dlg.show();
执行上面的代码,我们会发现窗口一闪而过,其原因是因为dlg被申明为一个局部变量,当用完之后就自动销毁,所以窗口show完之后立马就被释放。为了不让它一闪而过,使用
dlg.exec();//阻塞
这个语句起到阻塞程序的作用,当执行到这里的时候停住了,这样也不能对其他窗口进行操作,所以
Qdialog dlg;
dlg.exec();
就是模态对话框的写法。
非模态对话框:
Qdialog *dlg=new Qdialog;
dlg->show();
dlg->setAttribute(Qt::WA_DelecteOnClose);
执行上面程序弹出窗口不会一闪而过,因为new创建在堆上,不会自动销毁,需要手动delete。dlg->setAttribute(Qt::WA_DelecteOnClose)的作用是当窗口关闭时,对话框释放。
模态对话框:非阻塞
//方法1
TestDialog childWindow ;
childWindow.setModal(false);
//childWindow.show();//不可行
childWindow.exec();//可行
//方法2
TestDialog * childWindow = new TestDialog();
childWindow->setModal(false);
childWindow->show();
在子窗口初始化中加入
setAttribute (Qt::WA_DeleteOnClose); //防止内存泄漏。
防止内存泄漏。
非模态对话框:阻塞
//方法1
TestDialog * childWindow = new TestDialog();
childWindow->setModal(true);
childWindow->show();
//方法2
TestDialog* childWindow = new TestDialog();
childWindow->setWindowModality(Qt::WindowModal);
childWindow->show();
qDialog的setmodal,对话框模态、非模态
对话框模态,关闭当前对话框前,无法操作其他窗口
非模态,当前对话框打开同时,也可以操作其他对话框
模态在对话框创建时设定好后,程序运行过程中无法切换!(如:对话框A当前为非模态,弹出后,设置为模态,不起作用)
1.如果使用exec()默认为模态的。如果用show()需要设置setModel(true)才是模态的。
方法1:模态窗口
A为窗口类, 父类窗口为B
A *dlg = new A(this,pB); //(可确保A显示在B之上)
dlg->exe();
注意:此时使用setModal无效果
方法2:
A *dlg = new A(this,pB); //(可确保A显示在B之上)
dlg-.setModel(true);
dlg->show();
2、close()会销毁对象嘛。只有当设置了 setAttribute(WA:closeOnDelelte)是才会删除,如果这个标志没有设置,其作用和hide(),setvisible(false)一样,只会隐藏改对象。
A为窗口类, 父类窗口为B
A *dlg = new A(this,pB); //(可确保A显示在B之上)
dlg->setAttribute(WA:closeOnDelelte);
dlg->show;
注意,此时需要使用close();否则dlg指针未被管理。
3、QWidget的模态和非模态;
4、阻塞?
QDialog模态对话框与非模态对话框 范例
//模态1
MyWidget*w = new MyWidget; //派生于QWidget
w->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
w->setAttribute(Qt::WA_ShowModal, true);
w->setAttribute(Qt::WA_DeleteOnClose, true);
w->show();
//模态2
MyDialog _dialog; //派生于QDialog
int ret = _dialog.exec();
if (ret == QDialog::Accepted)
{
}
//模态附加
void on__btnSave_clicked()
{
this->accept();
this->close();
}
if (res == QDialog::Accepted)
//非模态
MyDialog* _pMyDialog = new MyDialog ;
_pMyDialog->setAttribute(Qt::WA_DeleteOnClose);
_pMyDialog->setModal(false);
_pMyDialog->show();
[2] Qt工作笔记-主界面往模式对话框emit信号,有注意的问题
原文链接
今天遇到个坑,往主界面往模式对话框emit信号。
应为模式对话框exec后,主界面就不响应了,emit也发不了。所以要先emit,再exec。
运行截图如下:
正常情况下:
此时,相关代码如下:
void Widget::openBtnClicked(){
m_dialog=new Dialog();
connect(this,SIGNAL(btnClicked(QString)),m_dialog,SLOT(receive(QString)));
emit btnClicked(ui->lineEdit->text());
m_dialog->exec();
}
不正常情况下:
代码如下:
void Widget::openBtnClicked(){
m_dialog=new Dialog();
connect(this,SIGNAL(btnClicked(QString)),m_dialog,SLOT(receive(QString)));
m_dialog->exec();
emit btnClicked(ui->lineEdit->text());
}
下面给出正常情况下的代码:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
void receive(QString msg);
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);
}
void Dialog::receive(QString msg){
ui->lineEdit->setText(msg);
}
Dialog::~Dialog()
{
delete ui;
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "dialog.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
public slots:
void openBtnClicked();
signals:
void btnClicked(QString msg);
private:
Ui::Widget *ui;
Dialog *m_dialog;
};
#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);
connect(ui->pushButton,SIGNAL(clicked(bool)),this,SLOT(openBtnClicked()));
}
void Widget::openBtnClicked(){
m_dialog=new Dialog();
connect(this,SIGNAL(btnClicked(QString)),m_dialog,SLOT(receive(QString)));
emit btnClicked(ui->lineEdit->text());
m_dialog->exec();
}
Widget::~Widget()
{
delete ui;
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}