QML 对本地文件的读写

QML 里似乎没有提供直接访问本地文件的模块,但是我们能够自己扩展 QML,给它加上访问本地文件的能力。

Qt 官方文档对 QML 是这样介绍的:

It defines and implements the language and engine infrastructure, and provides an API to enable application developers to extend the QML language with custom types and integrate QML code with JavaScript and C++.

自定义模块

我们可以通过自定义 C++ 类,实现文件的读写并整合进 QML 中,使其作为一个文件读写的独立模块。

C++ 里这个类叫做 FileContent

头文件 FileContent.h:

#ifndef FILECONTENT_H
#define FILECONTENT_H #include <QObject>
#include <QFile>
#include <QTextStream> class FileContent : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString content READ getContent)
Q_PROPERTY(QString filename READ getFileName WRITE setFileName)
Q_INVOKABLE QString getContent();
Q_INVOKABLE QString getFileName();
FileContent(QObject *parent = 0);
~FileContent();
private:
QFile *file;
QString content;
QString filename;
public slots:
void setFileName(const QString& filename);
void clearContent();
}; #endif // FILECONTENT_H

FileContent 的实现:

#include "filecontent.h"
#include <QDebug> FileContent::FileContent(QObject *parent) { } FileContent::~FileContent() {
delete file;
} QString FileContent::getFileName() {
return this->filename;
} void FileContent::setFileName(const QString &filename) {
this->filename = filename;
file = new QFile(filename); } QString FileContent::getContent() {
if( content.length() == 0 ) {
file->open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(file);
content = in.readAll();
if( content.length() == 0) {
qDebug() << "[Warning] FileContent: file " << this->filename << "is empty" << endl;
}
}
return content;
} void FileContent::clearContent() {
content.clear();
}

FileContent 需要继承 QObject 类,并且在类内使用 Qt 的一系列宏。

这里用到了 Q_PROPERTY 宏,声明该类的一个属性,并给出 set 和 get 对应的方法名。还有 Q_INVOKABLE 宏,以便在 QML 中可以调用 FileContent 类的方法。

这里的 FileContent 类有两个属性,一个是文件名 filename,另一个是文件的内容 content。这两个属性可以直接在 QML 中作为 Item 的属性进行赋值。

我们把 FileContent 在 QML 中的名字叫做 FileContentItem,但现在还不能直接在 QML 文件中引用 FileContentItem,我们还需要通过 QmlEngine 提供的 qmlRegisterType 方法,向 Qml 系统注册我们写的这个类。

在 main 函数里面添加:

qmlRegisterType<FileContent>("test.filecontent", 1, 0, "FileContentItem");

然后在 QML 文件里面引用我们定义的 FileContent,然后就可以像使用普通的 Item 一样使用 FileContentItem 了。

import test.filecontent 1.0 

FileContentItem {
id: content
filename: ":/obj/craft.obj" // default is craft.obj
property bool ready: false
Component.onCompleted: {
ready = true;
GLcode.readFile = processContent;
} function processContent(process, source) {
while( !ready ) {
;
} if( source !== undefined ) {
filename = source;
}
console.time('Read file: "' + source + '"');
process(getContent());
console.timeEnd('Read file: "' + source + '"');
clearContent(); // save memory
}
}

这里 FileContentItem 里的 filename 和 content 属性其实分别对应的 C++ 里面用 Q_PROPERTY 定义的属性。这里并没有考虑要读取的文件内容大小,而是直接用 getContent() 方法直接返回文件的所有内容,如果文件过大,也可以考虑流式读取文件内容。

JavaScript 异步读取文件

如果需要在 QML 里面读取资源文件而不需要将数据写入到文件中,那么其实可以使用 JavaScript 的 XMLHttpRequest 方法来读取文件。当然这个方法与浏览器里面的使用有一点点区别。

这是我从 Qt 自带的 Planets Example 中扎到的实现:

/**
* this function is copied from planets demo of qt version of threejs
* I modified some of it, now it works fine for me
**/
function readFile(url, onLoad, onProgress, onError) {
var request = new XMLHttpRequest(); request.onreadystatechange = function() {
if (request.readyState === XMLHttpRequest.DONE) {
// TODO: Re-visit https://bugreports.qt.io/browse/QTBUG-45581 is solved in Qt
if (request.status == 200 || request.status == 0) {
// var response;
// response = request.responseText; console.time('Process file: "' + url + '"');
onLoad( request.responseText );
console.timeEnd('Process file: "' + url + '"'); }
else if ( onError !== undefined ) {
onError();
}
}
else if (request.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
if ( onProgress !== undefined ) {
onProgress();
}
}
}; request.open( 'GET', url, true );
request.send( null );
}

因为我暂时只需要回调 onLoad 方法,所以我只关注这一部分的逻辑,该方法和浏览器中 AJAX 的异步请求并没有太大区别,不过需要注意的是这里有个 bug: request 放回的状态码有可能是 0,而这有可能意味着请求成功。所以在检测请求是否成功返回时应该要加上 request.status == 0 的判断。

总结

此外,如果想要在 QML 里面读写本地的配置文件,还可以使用 QML 已经提供的 Settings 模块,它对应的是 C++ 部分的 QSettings 类,提供平台无关的程序配置。

在 QML 中实现文件的读写有多种方法,具体的做法需要结合具体的需求,由于我做的程序可能需要迁移到 Web 上,因此最终使用 JavaScript 提供的 XMLHttpRequest 来进行异步请求。

QML 读取本地文件内容的更多相关文章

  1. 手工创建tomcat应用,以及实现js读取本地文件内容

    手工创建tomcat应用: 1.在webapps下面新建应用目录文件夹 2.在文件夹下创建或是从其他应用中复制:META-INF,WEB-INF这两个文件夹, 其中META-INF清空里面,WEB-I ...

  2. HTML-点击Div读取本地文件内容

    <!DOCTYPE html> <html> <div id="container" onclick="choosefile();" ...

  3. 前台JS(type=‘file’)读取本地文件的内容,兼容各种浏览器

    [自己测了下,能兼容各种浏览器,但是读取中文会出现乱码.自己的解决方法是用notepad++把txt文件编码改为utf-8(应该是和浏览器编码保持一致吧?..)] 原文  http://blog.cs ...

  4. ios本地文件内容读取,.json .plist 文件读写

    ios本地文件内容读取,.json .plist 文件读写 本地文件.json .plist文件是较为常用的存储本地数据的文件,对这些文件的操作也是一种常用的基础. 本文同时提供初始化变量的比较标准的 ...

  5. H5读取本地文件操作

    H5读取本地文件操作 本文转自:转:http://hushicai.com/2014/03/29/html5-du-qu-ben-di-wen-jian.html感谢大神分享. 常见的语言比如php. ...

  6. python 读取本地文件批量插入mysql

    Uin_phone.txt 本地文件内容 有1000条,这里只是展示前几条,供参考 133584752 133584759 133584764 133584773 133584775 13358477 ...

  7. FileReader读取本地文件

    FileReader是一种异步读取文件机制,结合input:file可以很方便的读取本地文件. 一.input:type[file] file类型的input会渲染为一个按钮和一段文字.点击按钮可打开 ...

  8. 五种方式让你在java中读取properties文件内容不再是难题

    一.背景 最近,在项目开发的过程中,遇到需要在properties文件中定义一些自定义的变量,以供java程序动态的读取,修改变量,不再需要修改代码的问题.就借此机会把Spring+SpringMVC ...

  9. .NET 读取本地文件绑定到GridViewRow

    wjgl.aspx.cs: using System; using System.Collections; using System.Configuration; using System.Data; ...

随机推荐

  1. C#中对sqlserver进行增删改查操作(简单易懂)

    1.添加引用using System.Data;using System.Data.SqlData; 2.建立于数据库的连接,建议将它做成一个方法,方便多次利用.string sqlconnectio ...

  2. C#之WinForm界面分辨率问题

    在做上一个C#小工具的时候,当时为了处理界面最大化,分辨率问题,只是简单的用各种···Panle控价简单随意的处理控件的大小位置,字体什么的就随缘了(貌似有点不负责任啊,嘿嘿~). 所以在开始第二个C ...

  3. 访问其他电脑的c盘

    访问其他电脑的c盘 \\192.168.0.1\C$

  4. c++ string.c_str()小结

    c++ const char *c_str(); c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同.(其实它指向的是string对象内部真正的char缓冲区),所以返 ...

  5. CF352B Jeff and Periods 模拟

    One day Jeff got hold of an integer sequence a1, a2, ..., an of length n. The boy immediately decide ...

  6. PAT天梯赛 L1-049 天梯赛座位分配

    题目链接:点击打开链接 天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情.为此我们制定如下策略:假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] ...

  7. react 拆分组件于组件

    Todolist.js(这是父组件) import React, { Component,Fragment } from 'react'; import './style.css'; import T ...

  8. vue.js 基础

      vuejs 遍历 数组, vue js 文章 http://www.cnblogs.com/libin-1/p/6851775.html https://zhuanlan.zhihu.com/p/ ...

  9. 单片机关键字sfr和sbit的理解

    在单片机C语言编程中,扩充了两个关键字sfr和sbit.sfr(Special Function Register特殊功能寄存器的缩写),sbit(特殊功能寄存器位),与定义一般的int.char型变 ...

  10. 最长子序列问题(二分+贪心nlogn算法)

    [题目描述] 给定N个数,求这N个数的最长上升子序列的长度. [样例输入] 7 2 5 3 4 1 7 6 [样例输出] 4 什么是最长上升子序列? 就是给你一个序列,请你在其中求出一段不断严格上升的 ...