QML与C++交互:登陆界面设计
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
环境:
主机:WIN7
开发环境:Qt5.2.1
说明:
QML设计前台界面,C++后台负责逻辑
效果图:
源代码:
前台qml文件
login.qml
/*********************************************************************
* 登陆界面qml文件
* (c)copyright 2014,jdh
* All Right Reserved
*新建日期:2014/4/29 by jdh
*修改日期:2014/4/30 by jdh
*修改日期:2014/5/4 by jdh
*修改日期:2014/5/5 by jdh
**********************************************************************/
import QtQuick 2.0
import "content"
import Login_Gui 1.0
Rectangle
{
id: login
width: 320; height: 512
SystemPalette { id: activePalette }
//C++组件:用户界面
Login_Gui
{
id:login_gui
onSig_login_result:
{
//关闭登陆动画
load_gif.opacity = 0
//根据登陆结果处理
switch (result)
{
//登陆成功
case 0:
message.text = "登陆成功"
message.opacity = 1
break;
//无此用户名
case 1:
message.text = "登陆失败:无此用户名"
message.opacity = 1
break;
//密码错误
case 2:
message.text = "登陆失败:密码错误"
message.opacity = 1
break;
//达到最大登陆次数
case 3:
message.text = "登陆失败:达到最大登陆次数"
message.opacity = 1
break;
}
}
}
//背景图片
Image
{
id: background
anchors { top: parent.top; bottom: parent.bottom }
anchors.fill: parent
source: "pics/pic1.png"
fillMode: Image.PreserveAspectCrop
}
//消息框
Message
{
id: message
font_size: login.height * 0.03
anchors {centerIn: parent}
opacity: 0
}
//登陆动画
AnimatedImage
{
id: load_gif; source: "pics/load.gif"
anchors {horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter}
z: 100
opacity: 0
}
//顶栏
Item
{
id: top_bar
width: login.width; height: login.height * 0.06
anchors.top: parent.top
Text
{
id: title
anchors { top: parent.top; horizontalCenter: parent.horizontalCenter }
//text: "登陆"
text: "登陆"
font.bold: true
font.pointSize: login.height * 0.06 * 0.4
color: "dark red"
}
}
//空白栏
Item
{
id: space1
width: login.width; height: login.height * 0.1
anchors.top: top_bar.bottom
}
//登陆框
Rectangle
{
id: rect1
width: login.width * 0.8; height: login.height * 0.3
anchors { top: space1.bottom; horizontalCenter: parent.horizontalCenter }
border.color: "#707070"
color: "transparent"
radius: 8
Row
{
spacing: rect1.width * 0.05
Item
{
width: rect1.width * 0.05; height: rect1.height
}
Column
{
spacing: rect1.height * 0.025
Item
{
width: rect1.width * 0.8; height: rect1.height * 0.05
}
LineInput
{
id: txt_user_id
width: rect1.width * 0.8; height: rect1.height * 0.2
font_size:height * 0.7
//anchors {horizontalCenter: rect1.horizontalCenter; top: rect1.top; topMargin: 8}
hint: "请输入用户号"
text:login_gui.user_id
}
LineInput
{
id: txt_password
width: rect1.width * 0.8; height: rect1.height * 0.2
font_size:height * 0.7
//anchors {horizontalCenter: rect1.horizontalCenter; bottom: btn_login.top; bottomMargin: rect1.height * 0.1}
hint: "请输入密码"
text:login_gui.password
}
Row
{
spacing: rect1.width * 0.1
Button
{
id: btn_login
width: rect1.width * 0.35; height: rect1.height * 0.2
//anchors { left: rect1.left; leftMargin: 28; bottom: rect1.bottom; bottomMargin: 8 }
text: "登陆"
onClicked: login_req()
}
Button
{
id: btn_quit
width: rect1.width * 0.35; height: rect1.height * 0.2
//anchors { right: rect1.right; rightMargin: 28; bottom: rect1.bottom; bottomMargin: 8 }
text: "退出"
onClicked:
{
Qt.quit();
}
}
}
Row
{
spacing: rect1.width * 0.1
CheckBox
{
id: check1
width: rect1.width * 0.35; height: rect1.height * 0.2
//anchors { left: rect1.left; top: rect1.bottom }
caption: "记住密码"
selected: login_gui.flag_remember
}
CheckBox
{
id: check2
width: rect1.width * 0.35; height: rect1.height * 0.2
//anchors { right: rect1.right; top: rect1.bottom }
caption: "自动登陆"
selected: login_gui.flag_auto
}
}
}
}
}
//android自带键处理
FocusScope
{
focus: true
Keys.onReleased:
{
if (event.key == Qt.Key_Back)
{
console.log("qml login quit")
login.sig_btn_quit()
}
}
}
//登陆请求函数
function login_req()
{
//判断用户名是否有效
if (txt_user_id.text == "")
{
message.text = "请输入用户名"
message.opacity = 1
return
}
//判断密码是否有效
if (txt_password.text == "")
{
message.text = "请输入密码"
message.opacity = 1
return
}
//显示登陆动画
load_gif.opacity = 1
//登陆请求
login_gui.user_id = txt_user_id.text
login_gui.password = txt_password.text
login_gui.flag_remember = check1.selected
login_gui.flag_auto = check2.selected
login_gui.slot_login_req()
}
// //信号槽绑定
// Component.onCompleted:
// {
// login_gui.sig_user_id_changed.connect(login_gui.slot_btn_login)
// }
}
后台C++代码
main.c
/*********************************************************************
* 主文件
* (c)copyright 2014,jdh
* All Right Reserved
*新建日期:2014/1/27 by jdh
*修改日期:2014/1/28 by jdh
*修改日期:2014/2/4 by jdh
*修改日期:2014/2/18 by jdh
*修改日期:2014/2/27 by jdh
*修改日期:2014/2/28 by jdh
*修改日期:2014/3/1 by jdh
*修改日期:2014/4/10 by jdh
*修改日期:2014/5/4 by jdh
**********************************************************************/
#include "world.h"
#include "main_gui.h"
#include "login_gui.h"
#include "light_gui.h"
#include "heart_beat.h"
#include "net.h"
#include "data_sync_center.h"
#include "set_ctrl_state.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
//注册组件到QML
qmlRegisterType<Login_Gui>("Login_Gui", 1, 0, "Login_Gui");
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/SH_User/login.qml"));
viewer.showExpanded();
return app.exec();
}
login_gui.h
/*********************************************************************
* 登陆界面模块头文件
* (c)copyright 2014,jdh
* All Right Reserved
*新建日期:2014/1/29 by jdh
*修改日期:2014/2/1 by jdh
*修改日期:2014/2/18 by jdh
*修改日期:2014/3/18 by jdh
*修改日期:2014/5/4 by jdh
*修改日期:2014/5/5 by jdh
*修改日期:2014/5/13 by jdh
**********************************************************************/
#ifndef LOGIN_GUI_H
#define LOGIN_GUI_H
/*********************************************************************
* 头文件
**********************************************************************/
#include "world.h"
/*********************************************************************
* 宏定义
**********************************************************************/
/*********************************************************************
* 登录间隔
*单位:ms
**********************************************************************/
#define INTERVAL_LOGIN 500
/*********************************************************************
* 最大登录次数
**********************************************************************/
#define NUM_LOGIN 5
/*********************************************************************
* 数据结构
**********************************************************************/
/*********************************************************************
* 登录界面类
**********************************************************************/
class Login_Gui : public QObject
{
Q_OBJECT
//属性:用户名
Q_PROPERTY(QString user_id READ user_id WRITE set_user_id NOTIFY sig_user_id_changed)
//属性:密码
Q_PROPERTY(QString password READ password WRITE set_password NOTIFY sig_password_changed)
//属性:记住密码标志
Q_PROPERTY(bool flag_remember READ flag_remember \
WRITE set_flag_remember NOTIFY sig_flag_remember_changed)
//属性:自动登录标志
Q_PROPERTY(bool flag_auto READ flag_auto \
WRITE set_flag_auto NOTIFY sig_flag_auto_changed)
public:
/*********************************************************************
* 函数
**********************************************************************/
/*********************************************************************
* 初始化函数
**********************************************************************/
Login_Gui();
/*********************************************************************
* 解构函数
**********************************************************************/
~Login_Gui();
/*********************************************************************
* 属性读取:用户号
**********************************************************************/
QString user_id();
/*********************************************************************
* 属性写入:用户号
**********************************************************************/
void set_user_id(QString str);
/*********************************************************************
* 属性读取:密码
**********************************************************************/
QString password();
/*********************************************************************
* 属性写入:密码
**********************************************************************/
void set_password(QString str);
/*********************************************************************
* 属性读取:记住密码标志
**********************************************************************/
bool flag_remember();
/*********************************************************************
* 属性写入:记住密码标志
**********************************************************************/
void set_flag_remember(bool flag);
/*********************************************************************
* 属性读取:自动登陆标志
**********************************************************************/
bool flag_auto();
/*********************************************************************
* 属性写入:自动登陆标志
**********************************************************************/
void set_flag_auto(bool flag);
signals:
/*********************************************************************
* 属性改变信号:用户号
**********************************************************************/
void sig_user_id_changed();
/*********************************************************************
* 属性改变信号:密码
**********************************************************************/
void sig_password_changed();
/*********************************************************************
* 属性改变信号:记住密码标志
**********************************************************************/
void sig_flag_remember_changed();
/*********************************************************************
* 属性改变信号:自动登陆标志
**********************************************************************/
void sig_flag_auto_changed();
/*********************************************************************
* 信号:登陆结果
*参数:result:0:成功
* 1:无此用户名
* 2:密码错误
* 3:达到登陆的最大次数
**********************************************************************/
void sig_login_result(int result);
/*********************************************************************
* 发送网络帧
*参数:id:用户名
* password:密码
* cmd:帧命令
* index:发送序列号
* frame:发送的报文
**********************************************************************/
void sig_net_tx_frame_with_id(uint32_t id,uint32_t password,int cmd,uint16_t index,QByteArray frame);
public slots:
/*********************************************************************
* 槽函数:登陆请求
**********************************************************************/
void slot_login_req();
/*********************************************************************
* 槽函数:登陆响应
*参数:data:接收的数据
**********************************************************************/
void slot_login_ack(QByteArray data);
private slots:
/*********************************************************************
* 槽函数:心跳滴答函数
*说明:1滴答触发1次
**********************************************************************/
void slot_tick();
private:
/*********************************************************************
* 变量
**********************************************************************/
/*********************************************************************
* 属性:用户号
**********************************************************************/
QString _user_id;
/*********************************************************************
* 属性:密码
**********************************************************************/
QString _password;
/*********************************************************************
* 属性:记住密码标志
**********************************************************************/
bool _flag_remember;
/*********************************************************************
* 属性:自动登录标志
**********************************************************************/
bool _flag_auto;
/*********************************************************************
* 滴答定时器
**********************************************************************/
QTimer *timer;
/*********************************************************************
* 登录计数器
**********************************************************************/
int Login_Counter;
};
#endif // LOGIN_GUI_H
login_gui.c
/*********************************************************************
* 登陆界面模块主文件
* (c)copyright 2014,jdh
* All Right Reserved
*新建日期:2014/1/29 by jdh
*修改日期:2014/2/1 by jdh
*修改日期:2014/2/17 by jdh
*修改日期:2014/2/18 by jdh
*修改日期:2014/2/16 by jdh
*修改日期:2014/5/4 by jdh
*修改日期:2014/5/5 by jdh
*修改日期:2014/5/13 by jdh
**********************************************************************/
/*********************************************************************
* 头文件
**********************************************************************/
#include "login_gui.h"
/*********************************************************************
* 函数
**********************************************************************/
/*********************************************************************
* 初始化函数
**********************************************************************/
Login_Gui::Login_Gui()
{
//初始化变量
Login_Counter = 0;
//滴答初始化
timer = new QTimer(this);
//绑定信号槽
connect(timer, SIGNAL (timeout()), this , SLOT(slot_tick()));
QFile file_cfg("cfg.txt");
QByteArray arr;
bool ok;
int flag_remember = 0;
int flag_auto_login = 0;
int id = 0;
int password = 0;
QString str;
int i = 0;
int j = 0;
//属性初始化
_user_id = "";
_password = "";
_flag_remember = false;
_flag_auto = false;
//判断文件是否存在
if (!file_cfg.exists())
{
file_cfg.close();
}
else
{
//文件存在
file_cfg.open(QIODevice::ReadOnly);
//读取文件
do
{
str.clear();
arr = file_cfg.readLine();
for (i = 0;i < arr.count();i++)
{
if ((arr.at(i) >= '0' && arr.at(i) <= '9') || \
(arr.at(i) >= 'a' && arr.at(i) <= 'f') || \
arr.at(i) == 'x')
{
str[j++] = arr.at(i);
}
}
flag_remember = str.toInt(&ok,16);
if (!ok)
{
break;
}
str.clear();
arr = file_cfg.readLine();
for (i = 0;i < arr.count();i++)
{
if ((arr.at(i) >= '0' && arr.at(i) <= '9') || \
(arr.at(i) >= 'a' && arr.at(i) <= 'f') || \
arr.at(i) == 'x')
{
str[j++] = arr.at(i);
}
}
flag_auto_login = str.toInt(&ok,16);
if (!ok)
{
break;
}
str.clear();
arr = file_cfg.readLine();
for (i = 0;i < arr.count();i++)
{
if ((arr.at(i) >= '0' && arr.at(i) <= '9') || \
(arr.at(i) >= 'a' && arr.at(i) <= 'f') || \
arr.at(i) == 'x')
{
str[j++] = arr.at(i);
}
}
id = str.toInt(&ok,16);
if (!ok)
{
break;
}
str.clear();
arr = file_cfg.readLine();
for (i = 0;i < arr.count();i++)
{
if ((arr.at(i) >= '0' && arr.at(i) <= '9') || \
(arr.at(i) >= 'a' && arr.at(i) <= 'f') || \
arr.at(i) == 'x')
{
str[j++] = arr.at(i);
}
}
password = str.toInt(&ok,16);
if (!ok)
{
break;
}
//判断是否记住密码
if (flag_remember == VALID_FLAG)
{
_user_id = QString::number(id,10);
_password = QString::number(password,10);
_flag_remember = true;
//判断是否自动登录
if (flag_auto_login == VALID_FLAG)
{
_flag_auto = true;
slot_login_req();
}
}
} while (0);
file_cfg.close();
}
}
/*********************************************************************
* 解构函数
**********************************************************************/
Login_Gui::~Login_Gui()
{
}
/*********************************************************************
* 属性读取:用户号
**********************************************************************/
QString Login_Gui::user_id()
{
return _user_id;
}
/*********************************************************************
* 属性写入:用户号
**********************************************************************/
void Login_Gui::set_user_id(QString str)
{
if (_user_id != str)
{
_user_id = str;
emit sig_user_id_changed();
}
}
/*********************************************************************
* 属性读取:密码
**********************************************************************/
QString Login_Gui::password()
{
return _password;
}
/*********************************************************************
* 属性写入:密码
**********************************************************************/
void Login_Gui::set_password(QString str)
{
if (_password != str)
{
_password = str;
emit sig_password_changed();
}
}
/*********************************************************************
* 属性读取:记住密码标志
**********************************************************************/
bool Login_Gui::flag_remember()
{
return _flag_remember;
}
/*********************************************************************
* 属性写入:记住密码标志
**********************************************************************/
void Login_Gui::set_flag_remember(bool flag)
{
if (_flag_remember != flag)
{
_flag_remember = flag;
emit sig_flag_remember_changed();
}
}
/*********************************************************************
* 属性读取:自动登陆标志
**********************************************************************/
bool Login_Gui::flag_auto()
{
return _flag_auto;
}
/*********************************************************************
* 属性写入:自动登陆标志
**********************************************************************/
void Login_Gui::set_flag_auto(bool flag)
{
if (_flag_auto != flag)
{
_flag_auto = flag;
emit sig_flag_auto_changed();
}
}
/*********************************************************************
* 槽函数:登陆请求
**********************************************************************/
void Login_Gui::slot_login_req()
{
//初始化计数器
Login_Counter = 0;
//开始尝试登陆
timer->start(INTERVAL_LOGIN);
slot_tick();
}
/*********************************************************************
* 槽函数:登陆响应
*参数:data:接收的数据
**********************************************************************/
void Login_Gui::slot_login_ack(QByteArray data)
{
uint32_t id = 0;
uint32_t password = 0;
int flag_remember = 0;
int flag_auto_login = 0;
uint8_t result = 0;
bool ok;
#ifdef DEBUG
qDebug() << "接收帧:尝试登陆" << (uint8_t)data[0] << (uint8_t)data[1] << (uint8_t)data[2];
#endif
//清除计数器
Login_Counter = 0;
//停止登录尝试
timer->stop();
//判断用户号和密码是否匹配
id = ((uint8_t)data[6] << 24) +\
((uint8_t)data[7] << 16) + \
((uint8_t)data[8] << 8) + \
(uint8_t)data[9];
password = ((uint8_t)data[10] << 24) +\
((uint8_t)data[11] << 16) + \
((uint8_t)data[12] << 8) + \
(uint8_t)data[13];
//登陆结果
result = (uint8_t)data[LEN_FRAME_HEAD];
//判断登陆结果
switch (result)
{
//登陆成功
case 0:
{
//判断用户名和密码是否正确
if (id == (uint32_t)_user_id.toInt(&ok) && password == (uint32_t)_password.toInt(&ok))
{
//发送登陆成功信号
emit sig_login_result(0);
#ifdef DEBUG
qDebug() << "登陆成功" << "用户号" << _user_id << "密码" << _password;
#endif
//判断是否勾选记住密码以及自动登录
if (_flag_remember)
{
flag_remember = VALID_FLAG;
}
if (_flag_auto)
{
flag_auto_login = VALID_FLAG;
}
//将用户名密码保存
QFile file_cfg("cfg.txt");
file_cfg.open(QIODevice::WriteOnly);
QTextStream out(&file_cfg);
out << QString::number(flag_remember,16) << "\r\n" \
<< QString::number(flag_auto_login,16) << "\r\n" \
<< _user_id << "\r\n" \
<< _password << "\r\n";
file_cfg.close();
}
break;
}
//无此用户名
case 1:
{
#ifdef DEBUG
qDebug() << "登陆失败" << "用户号不存在";
#endif
//发送登录失败信号
emit sig_login_result(1);
break;
}
//密码错误
case 2:
{
#ifdef DEBUG
qDebug() << "登陆失败" << "密码错误";
#endif
//发送登录失败信号
emit sig_login_result(2);
break;
}
}
}
/*********************************************************************
* 槽函数:心跳滴答函数
*说明:1滴答触发1次
**********************************************************************/
void Login_Gui::slot_tick()
{
QByteArray frame;
bool ok;
//登录计数器
Login_Counter++;
if (Login_Counter > NUM_LOGIN)
{
#ifdef DEBUG
qDebug() << "登录失败" << "达到最大尝试登陆次数:" << NUM_LOGIN;
#endif
//清除计数器
Login_Counter = 0;
//停止登陆尝试
timer->stop();
//发送登陆失败信号
emit sig_login_result(3);
return;
}
//发送登陆请求
//报文
frame.clear();
//发送网络帧
#ifdef DEBUG
qDebug() << "发送帧:发送登陆请求";
#endif
emit sig_net_tx_frame_with_id((uint32_t)_user_id.toInt(&ok),(uint32_t)_password.toInt(&ok),\
CMD_USER_LOGIN_REQUEST,0,frame);
}