【qml入门】在qml项目上加入用户登录qml页面(包含源码)

前言

参照QT项目做一个qml项目并不复杂,先从"在主框架上加一个页面"开始吧,方便初学者构建自己的qml项目。本人也有分享类似的QT项目博文(借鉴此博文的风格来分享):

【QT入门到晋级】拿别人的QT项目,加入用户登录页面

一、创建一个qml项目

完成以上傻瓜式的操作之后,我们在qtcreator可以看到3个能打开的文件

.pro文件,与qt项目相比,有如下变化

main.cpp文件,与qt项目相比,有如下变化

qt的main(),是直接调用w.show();来显示界面,而qml的main(),需要通过以下5步来显示界面

  1. 初始化Qt GUI应用程序框架
  2. 创建QML引擎用于界面渲染
  3. 设置QML主界面文件路径(使用Qt资源系统)
  4. 添加对象创建失败的异常处理
  5. 异步加载QML界面文件

自带的main.qml

显示一个窗口标题为"hello word"的空白页面

二、增加一个登录页面LoginWindow

以上操作完成之后,在qtcreator中可以看到多出了一个内容为空白的LoginWindow.qml文件

这里提供一个登录页面的代码

复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

Window {
    id: loginWindow
    width: 300
    height: 200
    title: "用户登录"
    modality: Qt.ApplicationModal
    flags: Qt.Dialog

    Column {
        anchors.centerIn: parent
        spacing: 15
        width: parent.width * 0.8

        TextField {
            id: username
            width: parent.width
            placeholderText: "用户名"
        }

        TextField {
            id: password
            width: parent.width
            placeholderText: "密码"
            echoMode: TextInput.Password
        }

        Row {
            spacing: 10
            anchors.horizontalCenter: parent.horizontalCenter

            Button {
                text: "登录"
                onClicked: {
                    if(username.text === "admin" && password.text === "123456") {
                        console.log("登录成功")
                        loginWindow.close()//关闭自己的窗口
                    } else {
                        console.log("登录失败")
                    }
                }
            }

            Button {
                text: "退出"
                onClicked: {
                    //退出方式一:强制关闭所有窗口,资源完全释放
                    Qt.quit()//强制终止整个Qt应用程序进程
                    //退出方式二:关闭两个窗口,资源有可能未完全释放
                    //loginWindow.close()//关闭自己的窗口
                    //mainWindow.close()//关闭主窗口

                }

            }
        }
    }
}

注意了,这里有一个坑,如果在刚创建项目时,你点击过运行项目。然后再添加LoginWindow.qml文件的话,会报以下错误:

复制代码
qmlcache_loader.cpp:-1: error: undefined reference to `QmlCacheGeneratedCode::_0x5f__login_qml::qmlData'

这是qml的资源缓存没有包含新增加的login.qml导致,点击【构建】->【重新构建项目】之后,再点击运行项目就正常了(这个现象,你可以理解为,当你只修改.h头文件时,执行make,make会反馈"没有任何变化",清掉缓存,重新编译就正常了)。

三、main.qml加载登录页面LoginWindow

注意一点,以上增加LoginWindow.qml文件时,它与main.qml是在同一个目录下,方便引用,以下提供两种引用方式:

方式一:静态加载

复制代码
import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    id:mainWindow
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    //在窗口完成初始化后执行
    Component.onCompleted: {
        loginwin.visible = true
    }
    //登录窗口
    LoginWindow{//文件名称:直接引用组件(静态加载)
        id:loginwin
        visible: false
    }
}

方式二:动态加载

复制代码
import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    id:mainWindow
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    //在窗口完成初始化后执行
    Component.onCompleted: {
        var component = Qt.createComponent("LoginWindow.qml")
        if (component.status === Component.Ready) {
            var loginWindow = component.createObject(mainWindow)
            loginWindow.show()
        }
    }
}
场景 推荐方式
始终显示的界面元素 静态加载
按需加载的页面 动态加载
资源密集型组件 动态加载
简单的子组件 静态加载
需要频繁切换的视图 动态加载
应用核心组件 静态加载

四、登录页面在后端实时验证信息

在【三、main.qml加载登录页面LoginWindow】中提供了在qml上静态方式校验用户名和密码的代码,这只是为了让【三】能正常编译,实际项目中,是要动态方式校验的,以下展示创建一个后端的CheckPwd类进行校验,并于页面互通。

1、创建新类

添加过程跟QT项目一样,

2、声明及定义页面调用的函数

创建完成之后,在头文件checkpwd.h中加入页面引入的函数,代码如下

复制代码
#ifndef CHECKPWD_H
#define CHECKPWD_H

#include <QObject>
#include <QVariant>  //新增头文件,前后端传参/结果

class CheckPwd : public QObject
{
    Q_OBJECT
public:
    explicit CheckPwd(QObject *parent = nullptr);
    //声明给qml调用的函数
    Q_INVOKABLE bool logincheck(const QVariant usrname,const QVariant passwd);

signals:

};

#endif // CHECKPWD_H

要点有两个:

  1. 使用Q_INVOKABLE宏声明为qml调用的函数;
  2. 使用QVariant传参或者返回结果给qml,QVariant是Qt框架中提供的通用数据类型容器。QVariant的作用是:MVD(Model-View-‌Delegate)模式中Model<->Delegate之间传递数据的容器载体。‌

==============以下是关系图,内容来源于AI=====================

以下函数的定义代码,把QVariant转换成QString之后,其他就是常规的QT代码开发(以下代码只做简单的判断逻辑)

复制代码
bool CheckPwd::logincheck(const QVariant usrname,const QVariant passwd){
    QString name=usrname.toString();
    QString pwd=passwd.toString();
    if(name== "admin" && pwd == "123456")
        return true;
    else
        return false;
}

3、将C++类注册到QML系统

main.cpp中创建QML引擎并指定加载的qml页面之后才能显示该页面。qml页面要使用后端的C++类,也要进行注册,代码如下

复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "checkpwd.h"  //-------------新增的头文件

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);//创建Qt GUI应用程序实例,管理主事件循环和应用程序资源

    QQmlApplicationEngine engine;//创建QML引擎,用于加载和运行QML界面文件
    const QUrl url(QStringLiteral("qrc:/main.qml"));//定义QML主界面文件的路径(qrc资源系统中的main.qml)
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,//连接引擎的objectCreated信号
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection); //使用队列连接确保异步执行

    //将C++类注册到QML系统
    //CheckPwd的类的名称,必须与checkpwd.h类中的名称完全一致
    //CheckPwdObj是自主命名(名称随意),在LoginWindow.qml页面中引用
    //PasswordValidator引用的类型名称
    qmlRegisterType<CheckPwd>("CheckPwdObj",1,0,"PasswordValidator");//-------新增的注册类

    //加载以上指定的main.qml文件
    engine.load(url);

    return app.exec();
}

4、qml引入C++类的函数

在LoginWindow.qml中增加3个要素:

  1. 头部通过import进行引用:import CheckPwdObj 1.0,对应关系如下

  2. 类型引用

    复制代码
        PasswordValidator {
            id: validator
        }
  3. C++函数引用

    复制代码
    Button {
                    text: "登录"
                    onClicked: {
                        var pwdck = validator.logincheck(username.text,password.text);
                        if(pwdck===true){
                            console.log("登录成功")
                            loginWindow.close()//关闭自己的窗口
                        } else {
                            console.log("登录失败")
                        }
                    }
                }

    完成以上3步骤即可实现引用C++类函数,LoginWindow.qml完整代码如下

    import QtQuick 2.12
    import QtQuick.Controls 2.12
    import QtQuick.Window 2.12

    import CheckPwdObj 1.0
    Window {
    id: loginWindow
    width: 300
    height: 200
    title: "用户登录"
    modality: Qt.ApplicationModal
    flags: Qt.Dialog

    复制代码
     PasswordValidator {
         id: validator
     }
    
     Column {
         anchors.centerIn: parent
         spacing: 15
         width: parent.width * 0.8
    
         TextField {
             id: username
             width: parent.width
             placeholderText: "用户名"
         }
    
         TextField {
             id: password
             width: parent.width
             placeholderText: "密码"
             echoMode: TextInput.Password
         }
    
         Row {
             spacing: 10
             anchors.horizontalCenter: parent.horizontalCenter
    
             Button {
                 text: "登录"
                 onClicked: {
                     var pwdck = validator.logincheck(username.text,password.text);
                     if(pwdck===true){
                         console.log("登录成功")
                         loginWindow.close()//关闭自己的窗口
                     } else {
                         console.log("登录失败")
                     }
                     /*if(username.text === "admin" && password.text === "123456") {
                         console.log("登录成功")
                         loginWindow.close()//关闭自己的窗口
                     } else {
                         console.log("登录失败")
                     }*/
                 }
             }
    
             Button {
                 text: "退出"
                 onClicked: {
                     //退出方式一:强制关闭所有窗口,资源完全释放
                     Qt.quit()//强制终止整个Qt应用程序进程
                     //退出方式二:关闭两个窗口,资源有可能未完全释放
                     //loginWindow.close()//关闭自己的窗口
                     //mainWindow.close()//关闭主窗口
    
                 }
    
             }
         }
     }

    }

相关推荐
云边有个稻草人2 分钟前
【MySQL】第五节—一文详解 | 表的约束(上)
数据库·mysql·default·表的约束·zerofill·主键约束
马克学长6 分钟前
SSM校外实习管理平台6tu82(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·计算机毕设·ssm框架·实习管理信息化·校企协同实习
山峰哥6 分钟前
数据库性能优化实战:从工程架构到SQL调优的深度解析
大数据·数据库·oracle·性能优化·架构·深度优先
soft200152519 分钟前
MySQL Buffer Pool性能优化:LRU链表极致设计之道
数据库·mysql·链表
我可以将你更新哟26 分钟前
【scrapy框架】爬取内容后写入数据库
数据库·windows·scrapy
骄傲的心别枯萎28 分钟前
RV1126 NO.58:ROCKX+RV1126人脸识别推流项目之读取人脸数据库并保存到map
linux·数据库·计算机视觉·音视频·rv1126
枫叶丹430 分钟前
【Qt开发】Qt事件(一)
c语言·开发语言·数据库·c++·qt·microsoft
AIOps打工人32 分钟前
Grafana Query MCP:基于FastAPI的Grafana查询转换与分页服务
运维·数据库·python·ai·grafana·fastapi·devops
小鸡吃米…35 分钟前
Python - 数据库访问
数据库·python
极限实验室42 分钟前
INFINI Labs 产品更新 - Coco AI v0.10 × Easysearch v2.0 联袂上线:UI 全面重构,体验焕然一新
数据库·人工智能·产品