文章目录

  • 1 Qt中的QDialog
    • 1.1 QDialog简介
    • 1.2 模态对话框和非模态对话框
    • 1.3 对话框的返回值
  • 2 登陆对话框实例分析
    • 2.1 分析
    • 2.2 代码实现
    • 2.3 登录对话框的改进
  • 3 Qt种的标准对话框

1 Qt中的QDialog

1.1 QDialog简介

对话框的概念:

  • 对话框是与用户进行简短交互的顶层窗口。
  • QDialog是Qt中所有对话框窗口的基类。
  • QDialog继承于QWidget是一种容器类型的组件。

    QDialog的意义:
  • QDialog作为一种专用的交互窗口而存在。
  • QDialog不能作为子部件嵌入其它容器中。
  • QDialog是定制了窗口样式的特殊的QWidget。

注意:如果QDialog没有指定parent是不会一直处于最上层的,如果制定了parent则会一直处于最上层。

1.2 模态对话框和非模态对话框

模态对话框(QDialog::exec()):

  • 显示后无法与父窗口进行交互。
  • 是一种阻塞式的对话框调用方式。

非模态对话框(QDialog::show()):

  • 显示后独立存在可以同时与父窗口进行交互。
  • 是一种非阻塞式的对话框调用方式。

一般情况下:

  • 模态对话框用于必须依赖用户选择的场合(80%):

    • 消息提示、文件选择、打印设置等。
  • 非模态对话框用于特殊功能设置的场合(20%):
    • 查找操作、属性设置等。

小技巧:

  • 在栈上创建模态对话框是最简单常用的方式。
  • 一般情况下非模态对话框需要在堆上创建。
  • 通过QDialog::setModal函数可以创建混合特性的对话框(不会阻塞,但是必须做出选择)。
  • 非模态对话框需要指定Qt::WA_DeleteOnClose属性。

测试代码如下:

Dialog.h:

#ifndef DIALOG_H
#define DIALOG_H#include <QtGui/QDialog>
#include <QPushButton>class Dialog : public QDialog
{Q_OBJECT
protected:QPushButton ModalBtn;QPushButton NormalBtn;QPushButton MixedBtn;
protected slots:void ModalBtn_Clicked();void NormalBtn_Clicked();void MixedBtn_Clicked();
public:Dialog(QWidget *parent = 0);~Dialog();
};#endif // DIALOG_H

Dialog.cpp:

#include "Dialog.h"#include <QDebug>Dialog::Dialog(QWidget *parent) :QDialog(parent), ModalBtn(this), NormalBtn(this), MixedBtn(this)
{ModalBtn.setText("Modal Dialog");ModalBtn.move(20, 20);ModalBtn.resize(100, 30);NormalBtn.setText("Normal Dialog");NormalBtn.move(20, 70);NormalBtn.resize(100, 30);MixedBtn.setText("Mixed Dialog");MixedBtn.move(20, 120);MixedBtn.resize(100, 30);connect(&ModalBtn, SIGNAL(clicked()), this, SLOT(ModalBtn_Clicked()));connect(&NormalBtn, SIGNAL(clicked()), this, SLOT(NormalBtn_Clicked()));connect(&MixedBtn, SIGNAL(clicked()), this, SLOT(MixedBtn_Clicked()));resize(140, 170);
}void Dialog::ModalBtn_Clicked()
{qDebug() << "ModalBtn_Clicked() Begin";QDialog dialog(this);dialog.exec();qDebug() << "ModalBtn_Clicked() End";
}void Dialog::NormalBtn_Clicked()
{qDebug() << "NormalBtn_Clicked() Begin";QDialog* dialog = new QDialog(this);dialog->setAttribute(Qt::WA_DeleteOnClose);dialog->show();qDebug() << "NormalBtn_Clicked() End";
}void Dialog::MixedBtn_Clicked()
{qDebug() << "MixedBtn_Clicked() Begin";QDialog* dialog = new QDialog(this);dialog->setAttribute(Qt::WA_DeleteOnClose);dialog->setModal(true);dialog->show();qDebug() << "MixedBtn_Clicked() End";
}Dialog::~Dialog()
{qDebug() << "~Dialog()";
}

main.cpp:

#include <QtGui/QApplication>
#include <QWidget>
#include <QDialog>
#include <QDebug>
#include "Dialog.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Dialog dlg;dlg.show();return a.exec();
}

1.3 对话框的返回值

只有模态对话框才有返回值的概念:

  • 模态对话框的返回值用于表示交互结果。
  • QDialog::exec()的返回值为交互结果:
    • void QDialog::done(int i)关闭对话框并将参数作为交互结果。
    • QDialog::Accepted:用户操作成功。
    • QDialog:Rejected:用户操作失败。

测试代码如下:
QDialog.h的代码和上面一样,就不贴了。

QDialog.cpp:

#include "Dialog.h"#include <QDebug>Dialog::Dialog(QWidget *parent) :QDialog(parent), ModalBtn(this), NormalBtn(this), MixedBtn(this)
{ModalBtn.setText("Modal Dialog");ModalBtn.move(20, 20);ModalBtn.resize(100, 30);NormalBtn.setText("Normal Dialog");NormalBtn.move(20, 70);NormalBtn.resize(100, 30);MixedBtn.setText("Mixed Dialog");MixedBtn.move(20, 120);MixedBtn.resize(100, 30);connect(&ModalBtn, SIGNAL(clicked()), this, SLOT(ModalBtn_Clicked()));connect(&NormalBtn, SIGNAL(clicked()), this, SLOT(NormalBtn_Clicked()));connect(&MixedBtn, SIGNAL(clicked()), this, SLOT(MixedBtn_Clicked()));resize(140, 170);
}void Dialog::ModalBtn_Clicked()
{done(Accepted);
}void Dialog::NormalBtn_Clicked()
{done(Rejected);
}void Dialog::MixedBtn_Clicked()
{done(100);
}Dialog::~Dialog()
{qDebug() << "~Dialog()";
}

main.cpp:

#include <QtGui/QApplication>
#include <QWidget>
#include <QDialog>
#include <QDebug>
#include "Dialog.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Dialog dlg;int r = dlg.exec();if( r == QDialog::Accepted ){qDebug() << "Accepted";}else if( r == QDialog::Rejected ){qDebug() << "Rejected";}else{qDebug() << r;}return r;
}

2 登陆对话框实例分析

2.1 分析

登陆对话框是应用程序中的常用部件,思考:如何开发一个可以在不同项目间复用的登陆对话框?

登陆对话框需求分析:

  • 可复用软件部分。
  • 获取用户名和密码。

附加需求:

  • 随机验证码。

登陆对话框的设计与架构:

如何获取用户输入的用户名和密码:

  • 如何在两个不同的对话框之间传递数据?


对话框之间通过成员变量和成员函数传递数据:

  • 将用户数据保存在私有成员变量中。
  • 通过公有成员函数进行数据传递。

我们话可以进一步开发(这里未完成):

  • 检查用户名和密码是否为空:

    • 当用户名或密码为空时提示错误。
  • 随机验证码:
    • 当验证码输入错误时进行提示。
    • 验证码随机刷新。

2.2 代码实现

代码组织如下:

QLoginDialog.h:

#ifndef _QLOGINDIALOG_H_
#define _QLOGINDIALOG_H_#include <QtGui/QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>class QLoginDialog : public QDialog
{Q_OBJECT
private:QLabel UserLabel;QLabel PwdLabel;QLineEdit UserEdit;QLineEdit PwdEdit;QPushButton LoginBtn;QPushButton CancelBtn;QString m_user;QString m_pwd;
private slots:void LoginBtn_Clicked();void CancelBtn_Clicked();
public:QLoginDialog(QWidget *parent = 0);QString getUser();QString getPwd();~QLoginDialog();
};#endif

QLoginDialog.cpp:

#include "QLoginDialog.h"QLoginDialog::QLoginDialog(QWidget *parent): QDialog(parent, Qt::WindowCloseButtonHint), m_lblName(this), m_lblPwd(this), m_editName(this), m_editPwd(this),m_btnCancle(this), m_btnLogin(this)
{setWindowTitle("Login");setFixedSize(285, 170);m_lblName.setText("User ID:");m_lblName.resize(80, 25);m_lblName.move(10, 30);m_lblPwd.setText("Password:");m_lblPwd.resize(80, 25);m_lblPwd.move(10, 65);m_editName.move(95, 30);m_editName.resize(180, 25);m_editPwd.move(95, 65);m_editPwd.resize(180, 25);m_editPwd.setEchoMode(QLineEdit::Password);m_btnCancle.setText("Cancle");m_btnCancle.resize(85, 30);m_btnCancle.move(95, 110);m_btnLogin.setText("Login");m_btnLogin.resize(85, 30);m_btnLogin.move(190, 110);connect(&m_btnCancle, SIGNAL(clicked()), this, SLOT(onBtnCancleClicked()));connect(&m_btnLogin, SIGNAL(clicked()), this, SLOT(onBtnLoginClicked()));
}void QLoginDialog::onBtnCancleClicked()
{m_name = "";m_pwd = "";done(Rejected);
}void QLoginDialog::onBtnLoginClicked()
{m_name = m_editName.text().trimmed();m_pwd = m_editPwd.text();done(Accepted);
}QString QLoginDialog::getName()
{return m_name;
}QString QLoginDialog::getPwd()
{return m_pwd;
}QLoginDialog::~QLoginDialog()
{}

Widget.h:

#ifndef _WIDGET_H_
#define _WIDGET_H_#include <QtGui/QWidget>
#include <QPushButton>class Widget : public QWidget
{Q_OBJECT
private:QPushButton TestBtn;
private slots:void TestBtn_Clicked();
public:Widget(QWidget *parent = 0);~Widget();
};#endif

Widget.cpp:

#include "Widget.h"
#include "QLoginDialog.h"
#include "QDebug"Widget::Widget(QWidget *parent) :QWidget(parent), m_btnTestLoginDialog(this)
{m_btnTestLoginDialog.setText("Test login dialog");setFixedSize(300, 200);connect(&m_btnTestLoginDialog, SIGNAL(clicked()), this, SLOT(onBtnTest()));
}void Widget::onBtnTest()
{QLoginDialog loginDlg(this);if (loginDlg.exec() == QDialog::Accepted){qDebug() << loginDlg.getName();qDebug() << loginDlg.getPwd();}
}

main.cpp:

#include <QtGui/QApplication>
#include "QLoginDialog.h"
#include "Widget.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

2.3 登录对话框的改进

分析下如上对话框存在的问题:

  • 没有实现验证码功能,容易被恶意程序攻击,盗取用户名和密码。

改进思路-验证码机制:

  1. 随机产生验证码。
  2. 用户后填写。
  3. 判断用户识别的正确性。

需求:

  • 验证码必须能够有效避开恶意程序的识别!

关于验证码和恶意程序:

  • 自动测试原理:

    • 利用一些特殊的系统函数能够通过代码控制程序,从而模拟用户操作。
  • 恶意程序:
    • 使用自动测试原理对目标程序进行控制,从而盗取信息或进行攻击。
  • 验证码:
    • 随机产生,用户容易识别,程序难以识别,从而有效避免恶意攻击。

需要注意的问题:

  • 验证码必须动态随机产生。
  • 验证码的显示避开使用标准组件(标签、文本框等)。
  • 验证码应该附带足够多的障碍增加程序识别难度。

解决方案:

  1. 随机产生目标验证码。
  2. 将验证码直接绘制于登录对话框。
  3. 验证码中的字符颜色随机改变。
  4. 在验证码区域随机绘制噪点。

关于随机数:

  • 计算机无法产生真正意义上的随机数。
  • 计算机只能模拟随机数序列(伪随机数)。
  • 随机种子决定每次产生的随机序列是否相同。


随机产生验证码:

验证码绘制:

改进后的代码如下:

QLoginDialog.h:

#ifndef _QLOGINDIALOG_H_
#define _QLOGINDIALOG_H_#include <QtGui/QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTimer>class QLoginDialog : public QDialog
{Q_OBJECT
private:QLabel UserLabel;QLabel PwdLabel;QLabel CaptLabel;QLineEdit UserEdit;QLineEdit PwdEdit;QLineEdit CaptEdit;QPushButton LoginBtn;QPushButton CancelBtn;QString m_user;QString m_pwd;QString m_captcha;Qt::GlobalColor* m_colors;QTimer m_timer;
private slots:void LoginBtn_Clicked();void CancelBtn_Clicked();void Timer_Timeout();
protected:void paintEvent(QPaintEvent *);QString getCaptcha();Qt::GlobalColor* getColors();
public:QLoginDialog(QWidget *parent = 0);QString getUser();QString getPwd();~QLoginDialog();
};#endif

QLoginDialog.cpp:

#include "QLoginDialog.h"
#include <QPainter>
#include <QTime>
#include <QDebug>
#include <QMessageBox>QLoginDialog::QLoginDialog(QWidget* parent) : QDialog(parent, Qt::WindowCloseButtonHint),UserLabel(this), PwdLabel(this), CaptLabel(this),UserEdit(this), PwdEdit(this), CaptEdit(this),LoginBtn(this), CancelBtn(this)
{UserLabel.setText("User ID:");UserLabel.move(20, 30);UserLabel.resize(60, 25);UserEdit.move(85, 30);UserEdit.resize(180, 25);PwdLabel.setText("Password:");PwdLabel.move(20, 65);PwdLabel.resize(60,25);PwdEdit.move(85, 65);PwdEdit.resize(180, 25);PwdEdit.setEchoMode(QLineEdit::Password);CaptLabel.setText("Captcha:");CaptLabel.move(20, 100);CaptLabel.resize(60, 25);CaptEdit.move(85, 100);CaptEdit.resize(85, 25);CancelBtn.setText("Cancel");CancelBtn.move(85, 145);CancelBtn.resize(85, 30);LoginBtn.setText("Login");LoginBtn.move(180, 145);LoginBtn.resize(85, 30);m_timer.setParent(this);setWindowTitle("Login");setFixedSize(285, 205);connect(&m_timer, SIGNAL(timeout()), this, SLOT(Timer_Timeout()));connect(&LoginBtn, SIGNAL(clicked()), this, SLOT(LoginBtn_Clicked()));connect(&CancelBtn, SIGNAL(clicked()), this, SLOT(CancelBtn_Clicked()));qsrand(QTime::currentTime().second() * 1000 + QTime::currentTime().msec());m_captcha = getCaptcha();m_colors = getColors();m_timer.start(100);
}void QLoginDialog::LoginBtn_Clicked()
{qDebug() << "LoginBtn_Clicked() Begin";QString captcha = CaptEdit.text().replace(" ", "");if( m_captcha.toLower() == captcha.toLower() ){m_user = UserEdit.text().trimmed();m_pwd = PwdEdit.text();if( m_user == "" ){QMessageBox::information(this, "Info", "User ID can NOT be empty!");}else if( m_pwd == "" ){QMessageBox::information(this, "Info", "Password can NOT be empty!");}else{done(Accepted);}}else{QMessageBox::critical(this, "Error", "The captcha is NOT matched!");m_captcha = getCaptcha();CaptEdit.selectAll();}qDebug() << "LoginBtn_Clicked() End";
}void QLoginDialog::CancelBtn_Clicked()
{qDebug() << "CancelBtn_Clicked() Begin";done(Rejected);qDebug() << "CancelBtn_Clicked() End";
}QString QLoginDialog::getUser()
{return m_user;
}QString QLoginDialog::getPwd()
{return m_pwd;
}void QLoginDialog::Timer_Timeout()
{m_colors = getColors();update();
}void QLoginDialog::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.fillRect(180, 100, 84, 24, Qt::white);painter.setFont(QFont("Comic Sans MS", 12));for(int i=0; i<150; i++){painter.setPen(m_colors[i%4]);painter.drawPoint(180 + qrand() % 84, 100 + qrand() % 24);}for(int i=0; i<4; i++){painter.setPen(m_colors[i]);painter.drawText(180 + 20 * i, 100, 20, 24, Qt::AlignCenter, QString(m_captcha[i]));}
}QString QLoginDialog::getCaptcha()
{QString ret = "";for(int i=0; i<4; i++){int c = (qrand() % 2) ? 'a' : 'A';ret += static_cast<QChar>(c + qrand() % 26);}return ret;
}Qt::GlobalColor* QLoginDialog::getColors()
{static Qt::GlobalColor colors[4];for(int i=0; i<4; i++){colors[i] = static_cast<Qt::GlobalColor>(2 + qrand() % 16);}return colors;
}QLoginDialog::~QLoginDialog()
{}

Widget.h:

#ifndef _WIDGET_H_
#define _WIDGET_H_#include <QtGui/QWidget>
#include <QPushButton>class Widget : public QWidget
{Q_OBJECT
private:QPushButton TestBtn;
private slots:void TestBtn_Clicked();
public:Widget(QWidget *parent = 0);~Widget();
};#endif

Widget.cpp:

#include "Widget.h"
#include "QLoginDialog.h"#include <QDebug>Widget::Widget(QWidget *parent) : QWidget(parent), TestBtn(this)
{TestBtn.setText("Test Login Dialog");setFixedSize(200, 50);connect(&TestBtn, SIGNAL(clicked()), this, SLOT(TestBtn_Clicked()));
}void Widget::TestBtn_Clicked()
{QLoginDialog dlg;if( dlg.exec() == QDialog::Accepted ){qDebug() << "User: " + dlg.getUser();qDebug() << "Pwd: " + dlg.getPwd();}
}Widget::~Widget()
{}

main.cpp:

#include <QtGui/QApplication>
#include "widget.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

3 Qt种的标准对话框

标准对话框:

  • Qt为开发者提供了一些可复用的对话框类型。
  • Qt提供的可复用对话框全部继承自QDialog类。

    Qt中的标准对话框遵循相同的使用方式:

参考资料:

  1. QT实验分析教程

Qt中的QDialog相关推荐

  1. 【Qt】QMainWindow |QDialog对话框

    文章目录 1.QMainWindow 1.1 菜单栏 1.2 工具栏 1.3 状态栏 1.4 停靠部件 1.5 核心部件(中心部件) 1.6 使用UI文件创建窗口 1.6.1 UI设计窗口介绍 1.6 ...

  2. QT中QWidget、QDialog及QMainWindow的区别

    QWidget类是所有用户界面对象的基类. 窗口部件是用户界面的一个基本单元:它从窗口系统接收鼠标.键盘和其它事件,并且在屏幕上绘制自己.每一个窗口部件都是矩形的,并且它们按Z轴顺序排列.一个窗口部件 ...

  3. 【PyQt】Qt中QMainWindow, QWidget以及QDialog的区别和选择

    PyQt中MainWindow, QWidget以及Dialog的区别和选择 1. Qt界面分类 在Qt Designer设计界面时,首先需要选择界面模板,主要分为三个类: 1. Main Windo ...

  4. 关于Qt中QDialog对话框调用exec()函数界面退出造成僵尸程序问题

    关于Qt中QDialog对话框调用exec函数产生的问题 问题一: 问题描述: 原因分析: 解决方案: 问题二: 问题描述: 求助:关于这个问题,学识尚浅,求大佬分析一波 问题一: QDialog对话 ...

  5. Qt / QMainWindow、QDialog、QWidget

    在 Qt 中,我们将窗口和控件统称为部件(Widget). 窗口是指程序的整体界面,可以包含标题栏.菜单栏.工具栏.关闭按钮.最小化按钮.最大化按钮等. 控件是指按钮.复选框.文本框.表格.进度条等这 ...

  6. QT中父子窗口事件传递与事件过滤器

    处理监控系统的时候遇到问题,在MainWidget中创建多个子Widget的时候,原意是想鼠标点击先让MainWidget截获处理后再分派给子Widget去处理,但调试后发现如果子Widget重新实现 ...

  7. QT中的模态对话框及非模态对话框

    模态对话框(Modal Dialog)与非模态对话框(Modeless Dialog)的概念不是Qt所独有的,在各种不同的平台下都存在.又有叫法是称为模式对话框,无模式对话框等.所谓模态对话框就是在其 ...

  8. Qt中的模态对话框和非模态对话框

    模态对话框及非模态对话框(详情见课本P51). 模态对话框:在没有被关闭之前,用户不能与同一个应用程序的其他窗口进行交互,直到该对话框关闭. 非模态对话框:当被打开时,用户既可选择和该对话框进行交互, ...

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

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

最新文章

  1. python实用程序育儿法_Python多线程 简明例子
  2. linux挂载fc存储有超级坏块_Nand Flash基础知识与坏块管理机制的研究
  3. linux 文件颜色的含义
  4. Python学习---深浅拷贝的学习
  5. 深入了解AI在金融、能源领域的网络安全应用
  6. 【疾病识别】基于matlab GUI SVM农作物叶子虫害识别与分类【含Matlab源码 1322期】
  7. 企业多园区统一灾备建设最佳实践
  8. c语言敏感词屏蔽编程题,C#敏感词过滤实现方法
  9. [ssd]linux系统sh后,找不到文件夹的解决
  10. Android 查看是否支持指定解码器(H265)
  11. 结对作业-基于GUI的四则运算
  12. 3GPP TS 23501-g51 中英文对照 | 5.3.3 Connection Management
  13. Spring声明式事物配置管理
  14. 国外最大的购物搜索/比较购物网站
  15. SuperSet (真)完全汉化
  16. 未来生活里掌握计算机技术的重要性,浅谈计算机教育重要性的几点理解.doc
  17. Kademlia算法 理解 总结
  18. (转)在图像处理中,散度 div 具体的作用是什么?
  19. 区块链媒体宣发的注意事项
  20. 理解JPEG文件头的格式

热门文章

  1. linux 打开文件表 文件描述符,文件描述符-mjsc1023-ChinaUnix博客
  2. 搭建项目_跟着团子学SAP PS:项目模版搭建
  3. Ardino基础教程 14_倾斜开关
  4. 【system generator】基于system generator的整数除法器设计
  5. go 通过 channel 控制并发任务
  6. 03、Swagger2和Springmvc整合详细记录(爬坑记录)
  7. 【sublime text3】破解 最近破解码 /激活成功,但是过一会就提示激活码失效的 Build3143...
  8. bzoj2720 [Violet 5]列队春游
  9. 【288天】每日项目总结系列026(2017.11.20)
  10. 用html+ccs3就能 做出一个太阳系行星