Qt中的QDialog
文章目录1 Qt中的QDialog1.1 QDialog简介1.2 模态对话框和非模态对话框1.3 对话框的返回值1 Qt中的QDialog1.1 QDialog简介对话框的概念:对话框是与用户进行简短交互的顶层窗口。QDialog是Qt中所有对话框窗口的基类。QDialog继承于QWidget是一种容器类型的组件。QDialog的意义:QDialog作为一种专用的交互窗口而存...
文章目录
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 登录对话框的改进
分析下如上对话框存在的问题:
- 没有实现验证码功能,容易被恶意程序攻击,盗取用户名和密码。
改进思路-验证码机制:
- 随机产生验证码。
- 用户后填写。
- 判断用户识别的正确性。
需求:
- 验证码必须能够有效避开恶意程序的识别!
关于验证码和恶意程序:
- 自动测试原理:
- 利用一些特殊的系统函数能够通过代码控制程序,从而模拟用户操作。
- 恶意程序:
- 使用自动测试原理对目标程序进行控制,从而盗取信息或进行攻击。
- 验证码:
- 随机产生,用户容易识别,程序难以识别,从而有效避免恶意攻击。
需要注意的问题:
- 验证码必须动态随机产生。
- 验证码的显示避开使用标准组件(标签、文本框等)。
- 验证码应该附带足够多的障碍增加程序识别难度。
解决方案:
- 随机产生目标验证码。
- 将验证码直接绘制于登录对话框。
- 验证码中的字符颜色随机改变。
- 在验证码区域随机绘制噪点。
关于随机数:
- 计算机无法产生真正意义上的随机数。
- 计算机只能模拟随机数序列(伪随机数)。
- 随机种子决定每次产生的随机序列是否相同。
随机产生验证码:
验证码绘制:
改进后的代码如下:
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中的标准对话框遵循相同的使用方式:
参考资料:
更多推荐
所有评论(0)