QML读取本地⽂件内容
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 的⼀系列宏。
这⾥⽤到了宏,声明该类的⼀个属性,并给出 set 和 get 对应的⽅法名。还有宏,以便在 QML 中可以调⽤ FileContent 类的⽅法。
这⾥的 FileContent 类有两个属性,⼀个是⽂件名filename,另⼀个是⽂件的内容content。这两个属性可以直接在 QML 中作为 Item 的属性进⾏赋值。
我们把 FileContent 在 QML 中的名字叫做 FileContentItem,但现在还不能直接在 QML ⽂件中引⽤ FileContentItem,我们还需要通过提供的⽅法,向 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
ready = true;
}
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 ⾃带的中扎到的实现:
/**
* 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();
if (adyState === XMLHttpRequest.DONE) {
// TODO: Re-visit bugreports.qt.io/browse/QTBUG-45581 is solved in Qt
if (request.status == 200 || request.status == 0) {
//                var response;
//                response = sponseText;
console.time('Process file: "' + url + '"');
onLoad( sponseText );
console.timeEnd('Process file: "' + url + '"');
}
else if ( onError !== undefined ) {
onError();
}
else if (adyState === XMLHttpRequest.HEADERS_RECEIVED) {
if ( onProgress !== undefined ) {
onProgress();
}
}
};
request.open( 'GET', url, true );
request.send( null );
}
因为我暂时只需要回调 onLoad ⽅法,所以我只关注这⼀部分的逻辑,该⽅法和浏览器中 AJAX 的异步请求并没有太⼤区别,不过需要注意的是这⾥有个 bug: request 放回的状态码有可能是 0,⽽这有可能意味着请求成功。所以在检测请求是否成功返回时应该要加上request.status == 0的判断。
总结
getsavefilename此外,如果想要在 QML ⾥⾯读写本地的配置⽂件,还可以使⽤ QML 已经提供的模块,它对应的是 C++ 部分的类,提供平台⽆关的程序配置。
在 QML 中实现⽂件的读写有多种⽅法,具体的做法需要结合具体的需求,由于我做的程序可能需要迁移到 Web 上,因此最终使⽤JavaScript 提供的XMLHttpRequest来进⾏异步请求。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。