• Qt Quick读取本地文件并显示成表格


    🚀作者:CAccept
    🎂专栏:Qt Quick
    在这里插入图片描述

    🍎C++代码部分实现

    C++代码部分负责读取本地的文本文件,通过规则将文件进行解析,然后再通过信号与槽机制将数据传递给QML中供其使用,现在让我们来看看思路吧。
    实现思路:
    1、在QML中实现QML的信号和FileLoad槽方法的绑定
    2、QML触发信号并将文件路径传递给FileLoad
    3、一行一行解析数据
    4、每次解析完一行数据就将一行数据利用信号传给QML,用于添加表格数据



    fileload.h

    #ifndef FILELOAD_H
    #define FILELOAD_H
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    class FileLoad : public QObject
    {
        Q_OBJECT
    public:
        explicit FileLoad(QObject *parent = nullptr);
        //解析一行数据
        void parseLineData(QString line);
    signals:
    	//由于文件有9列所以就搞了9个参数,来传递数据
        void sendFileData(QString p1,QString p2,QString p3,QString p4,QString p5,QString p6,QString p7,QString p8,QString p9);
    public slots:
    	//读取整体文件
        void fileRead(QString fileName);
    
    };
    
    #endif // FILELOAD_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    fileload.cpp

    #include "fileload.h"
    #include 
    FileLoad::FileLoad(QObject *parent) : QObject(parent)
    {
    
    }
    
    void FileLoad::parseLineData(QString line)
    {
        //将line前面的空格进行去除
        line.remove (QRegExp ("^ +\s*"));
        //以四个空格为分隔符进行分割
        QStringList list = line.split("   ");
        QStringList data;
        int count = 0;
        for(auto parameter:list){
        	//去除字符串两边的空格
            parameter = parameter.simplified();
            count++;
            data.push_back(parameter);
        }
        for(int i=0;i<count;i++)
        {
            qDebug()<<data[i];
        }
        if(count == 9)
        {
        	//发送信号
            emit sendFileData(data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7],data[8]);
        }
    }
    
    void FileLoad::fileRead(QString fileName)
    {
        //qDebug()<<"开始fileRead!"<
        QFile f(fileName);
        if (!f.open(QIODevice::ReadOnly|QIODevice::Text))//打开指定文件
        {
            qDebug()<<"没有找到文件!!";
            return;
        }
    
        QTextStream txtInput(&f);
        QString lineStr;
        while (!txtInput.atEnd())
        {
            lineStr = txtInput.readLine();  //读取数据
    		//解析这一行的数据
            parseLineData(lineStr);
        }
    
        f.close();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    🚀C++类注册到QML

    注册过程:
    1、main.cpp包含头文件fileload.h
    2、创建FileLoad对象
    3、engine.rootContext()->setContextProperty对FileLoad对象进行注册
    main.cpp

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QApplication app(argc, argv);
        QString path = QCoreApplication::applicationDirPath();
        //创建FileLoad对象
        FileLoad fileload;
        QQmlApplicationEngine engine;
        //将path传递进去,方便调用路径查找文件
        engine.rootContext()->setContextProperty("appDir",path);
        engine.rootContext()->setContextProperty("fileload", &fileload);
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
        return app.exec();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    🎂QML部分实现

    QML部分的实现关键点在👇
    1、定义信号

    signal qmlGetData(string p1, string p2, string p3,string p4, string p5, string p6,string p7, string p8, string p9)
    //将地址送给fileload,让fileload解析
    signal qmlFilePathAccepted(string filename)
    
    • 1
    • 2
    • 3

    2、将QML定义的信号与C++类对象fileload的槽方法进行连接

    //将qmlFilePathAccepted和fileload的槽方法fileRead进行连接
    qmlFilePathAccepted.connect(fileload.fileRead)
    
    • 1
    • 2

    3、将C++类对象fileload的信号实现对应的槽方法

    //绑定信号槽
    Connections{
        target: fileload
        //实现fileload中sendFileData信号对应的槽方法
        function onSendFileData(p1,p2,p3,p4,p5,p6,p7,p8,p9)
        {
        	//发射信号
            qmlGetData(p1,p2,p3,p4,p5,p6,p7,p8,p9)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、实现qmlGetData对应响应的槽方法

    onQmlGetData:
    {
    	 //给model后面追加数据
         listModel.append({"p1":p1,"p2":p2,"p3":p3,"p4":p4,"p5":p5,"p6":p6,"p7":p7,"p8":p8,"p9":p9})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5、实现表格的显示

    main.qml

    import QtQuick 2.6
    import QtQuick.Window 2.2
    import QtQuick.Layouts 1.2
    import QtQuick.Controls 1.4
    import QtQuick.Controls.Styles 1.2
    
    Window {
        id:gridArea
        width: 1050;
        height: 457
        visible: true
        signal qmlGetData(string p1, string p2, string p3,string p4, string p5, string p6,string p7, string p8, string p9)
        signal qmlFilePathAccepted(string filename)
        onQmlGetData:
        {
            console.log("触发qmlGetData")
            listModel.append({"p1":p1,"p2":p2,"p3":p3,"p4":p4,"p5":p5,"p6":p6,"p7":p7,"p8":p8,"p9":p9})
        }
    
        TableView {
            id: tableView
            objectName: "tableView"
            anchors.fill: parent
    
            TableViewColumn {
                id: p1
                title: "p1"
                role: "p1"
                width:60
    
            }
            TableViewColumn {
                id: p2
                title: "p2"
                role: "p2"
                width:60
            }
            TableViewColumn {
                id: p3
                title: "p3"
                role: "p3"
                width:60
            }
            TableViewColumn {
                id: p4
                title: "p4"
                role: "p4"
                width:60
    
            }
            TableViewColumn {
                id: p5
                title: "p5"
                role: "p5"
                width:60
    
            }
            TableViewColumn {
                id: p6
                title: "p6"
                role: "p6"
                width:60
    
            }
            TableViewColumn {
                id: p7
                title: "p7"
                role: "p7"
                width:60
    
            }
            TableViewColumn {
                id: p8
                title: "p8"
                role: "p8"
                width:60
    
            }
            TableViewColumn {
                id: p9
                title: "p9"
                role: "p9"
                width:60
    
            }
    
            model: ListModel {
                id: listModel
                objectName: "listModel"
    
            }
        }
        //绑定信号槽
        Connections{
            target: fileload
            //实现fileload中sendFileData信号对应的槽方法
            function onSendFileData(p1,p2,p3,p4,p5,p6,p7,p8,p9)
            {
                qmlGetData(p1,p2,p3,p4,p5,p6,p7,p8,p9)
            }
        }
    
        Component.onCompleted: {
        	//将qmlFilePathAccepted和fileload的槽方法fileRead进行连接
            qmlFilePathAccepted.connect(fileload.fileRead)
            //将传进行来的appDir运行路径进行组合这样更好,且移植性强
            qmlFilePathAccepted(appDir+"/inpparameter.DAT")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    我的文件👇
    在这里插入图片描述

    运行效果👇
    在这里插入图片描述


    🌰小知识点

    ⭐C++与QML进行交互

    将C++类注册到QML中一般有两种方法
    1、qmlRegisterType函数

    int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
    
    • 1

    第一个参数uri指的是QML中import后的内容,相当于头文件名,第二个第三个参数分别是主次版本号,第四个指的是QML中类的名字(第四个QML的类名首字母一定要大写,要不然会报错)。<>中放的是C++的类的名字

    qmlRegisterType则用于向QML引擎注册一个新的类型,该类型可以在QML代码中直接创建。这种方法适用于需要在QML中创建新对象或自定义组件时使用。通过qmlRegisterType函数注册后,我们就可以在QML代码中像使用其他标准类型一样使用该类型了。

    //在main.cpp中使用👇
    qmlRegisterType("QuickQanava", 2, 0, "RightResizer");
    //那么我们在qml文件中就要👇
    import QuickQanava 2.0 as Qan
    Qan.RightResizer{
       balabala
       ..... 
       ....
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2、engine->rootContext()->setContextProperty

    engine.rootContext()->setContextProperty用于将一个现有的C++对象实例暴露给QML引擎。这种方法适合于简单的场景,例如在QML中调用C++对象中的方法或访问其属性等。我们可以使用以下代码将C++对象实例暴露给QML引擎:

    // C++对象
    MyObject myObject;
    // 将myObject暴露给QML引擎,这样就可以在QML文件中使用myObject来控制和使用我们外面定义的C++对象myObject
    engine.rootContext()->setContextProperty("myObject", &myObject);
    
    • 1
    • 2
    • 3
    • 4

    engine->rootContext()->setContextProperty更适用于一些简单的场景不需要多次创建,整个过程就只要存在一个这个对象就可以,而qmlRegisterType就相当于创建了一个新的类型,可以反复给QML创建


    ⭐将运行路径进行传递保证程序的稳定性

    可以通过Qt的API得到当前程序的执行路径,然后通过注册将路径传递给QML使用,这样就可以在一定程度上保证程序的可移植性👇
    main.cpp

    QString path = QCoreApplication::applicationDirPath();
    engine.rootContext()->setContextProperty("appDir",path);
    
    • 1
    • 2

    在qml中就可以这样使用👇

    qmlFilePathAccepted(appDir+"/inpparameter.DAT")
    
    • 1

    ⭐QML中定义信号其默认的槽方法是on+大写信号名

    signal qmlGetData(string p1, string p2, string p3,string p4, string p5, string p6,string p7, string p8, string p9)
    onQmlGetData:
    {
       listModel.append({"p1":p1,"p2":p2,"p3":p3,"p4":p4,"p5":p5,"p6":p6,"p7":p7,"p8":p8,"p9":p9})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    感谢您看完了这篇文章,希望这篇文章对您有所帮助,当然,如果在这篇文章中有遇到一些问题或者疑问的话请一定在评论区中提出万分感谢!!
    在这里插入图片描述

  • 相关阅读:
    基于springboot车辆充电桩管理系统springboot000
    2023二建备考第二天Day02
    面试遇到的问题(持续更新...)
    Flutter 精品项目大全之 侧边栏银行管理完成App(教程含源码)
    人是AppSec的核心影响因素
    flink测试redis sink报错
    代码随想录day43|1049. 最后一块石头的重量 II494. 目标和474. 一和零
    emq Neuron工业协议采集使用
    若依RuoYi-Vue分离版—PageHelper分页的坑
    vue.js毕业设计,基于vue.js前后端分离图书购物商城系统(H5移动项目) 开题报告
  • 原文地址:https://blog.csdn.net/Jacksqh/article/details/133779064