用QML(Qt)读写文件

时间:2013-07-26 13:25:08

标签: qt qml

我正在尝试实施Reading and writing files in QML并遇到来自诺基亚的链接文章,但未能成功使用看似明显的代码示例。我想我不必说我是这个领域的新手。

我在哪里放置此代码段(这是页面上的第二个代码段。 ):

#include "fileio.h"
Q_DECL_EXPORT int main(int argc, char *argv[])
{
    qmlRegisterType<FileIO, 1>("FileIO", 1, 0, "FileIO");
}

当我将上面的代码片段放在我的主窗体中时,我也一直收到关于qmlRegisterType没有在上下文中注册的错误。 有人可以就如何实现这个(或任何用QML / Qt读写文件的方法)提供一些建议吗?

4 个答案:

答案 0 :(得分:19)

如果您的文件只是文本,您可以使用XMLHttpRequest(用于读取和写入),如下所示:

function openFile(fileUrl) {
    var request = new XMLHttpRequest();
    request.open("GET", fileUrl, false);
    request.send(null);
    return request.responseText;
}

function saveFile(fileUrl, text) {
    var request = new XMLHttpRequest();
    request.open("PUT", fileUrl, false);
    request.send(text);
    return request.status;
}

这是演示应用程序(Qt 5.6):

import QtQuick 2.6
import QtQuick.Dialogs 1.2
import QtQuick.Controls 1.5

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Demo App")

    function openFile(fileUrl) {
        var request = new XMLHttpRequest();
        request.open("GET", fileUrl, false);
        request.send(null);
        return request.responseText;
    }

    function saveFile(fileUrl, text) {
        var request = new XMLHttpRequest();
        request.open("PUT", fileUrl, false);
        request.send(text);
        return request.status;
    }

    FileDialog {
        id: openFileDialog
        nameFilters: ["Text files (*.txt)", "All files (*)"]
        onAccepted: textEdit.text = openFile(openFileDialog.fileUrl)
    }

    FileDialog {
        id: saveFileDialog
        selectExisting: false
        nameFilters: ["Text files (*.txt)", "All files (*)"]
        onAccepted: saveFile(saveFileDialog.fileUrl, textEdit.text)
    }

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("&Open")
                onTriggered: openFileDialog.open()
            }
            MenuItem {
                text: qsTr("&Save")
                onTriggered: saveFileDialog.open()
            }
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }

    TextArea {
        id: textEdit
        anchors.fill: parent
        text:
            "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
            "sed do eiusmod tempor incididunt ut labore et dolore magna " +
            "aliqua. Ut enim ad minim veniam, quis nostrud exercitation " +
            "ullamco laboris nisi ut aliquip ex ea commodo cosnsequat. ";
    }
}

P.S。请注意,如果您尝试使用上述功能,所有现代浏览器都将抛出安全性异常,但QML允许它(即使是文件重写)。但不确定是设计还是错误。

答案 1 :(得分:8)

诺基亚在教程中编写的示例不是纯粹的QML程序。它包含C ++和QML。这种程序通常是一个C ++程序,它加载一个QML文件并呈现它。 C ++程序通常以名为int main(int argc, char *argv[]);的函数开头。在您的情况下,正是这个“main()”函数加载您的QML主文件(main.qml)文件并呈现它。

但在加载QML主文件之前,您必须告诉QML系统您将使用名为FileIO的自定义QML类。为此,您必须使用int qmlRegisterType<T>(const char * package, int majorVersion, int minorVersion, char * classNameInQML); C ++函数。它需要大约5个参数:

  • T :C ++模板参数。它是您的C ++类(FileIO)。
  • :所有QML类都在版本化的包中。这是包的名称。
  • majorVersion :所有QML类都在版本化的包中。这是包的主要版本号。
  • minorVersion :所有QML类都包含在版本中。这是包的次要版本号。
  • classNameInQML :所有QML类都在版本化的包中。这是您将在QML文件中使用的类的名称大多数情况下,该名称与C ++类名相同。

要使用此功能,您必须在C ++文件中包含C ++标题:

  • 如果您使用Qt 4,则标题为<QtDeclarative>
  • 如果您使用Qt 5,则标题为<QtQml>

最后你应该有这样的东西:

main.cpp(带有main()C ++函数的文件):

// C++ header to include for using qmlRegisterType();
#include <QtDeclarative>    // If you use Qt4
#include <QtQml>            // If you use Qt5

// Some stuff used by the main(); function
#include <QApplication>
#include <QLatin1String>

#include "ui/qtquickapplicationviewer.hpp"    // Something which manages your QML files. Qt Creator will generate it for you if you use it to code..
#include "fileio.h"    // Your FileIO C++ class

/**
 * @fn Q_DECL_EXPORT int main(int argc, char *argv[])
 * @brief The C++ main(); function. Your program begins HERE.
 */
Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // ...

    // Declaring your C++ class to the QML system
    qmlRegisterType<FileIO>("MyCustomClasses", 1, 0, "FileIOQML");

    // ...

    // Loading your main QML file
    QLatin1String mainQMLFile = "./ui/qml/main.qml";
    QtQuickApplicationViewer viewer;
    viewer.setMainQmlFile(mainQMLFile);

    // Showing how beautiful your QML interface is :)
    viewer.showExpanded();

    // Now let's play with your QML interface is :)
    return app.exec();
}

要加载的main.qml文件(从诺基亚教程开始):

import QtQuick 1.1
import MyCustomClasses 1.0

Rectangle {
    width: 360
    height: 360
    Text {
        id: myText
        text: "Hello World"
        anchors.centerIn: parent
    }

    FileIOQML {
        id: myFile
        source: "my_file.txt"
        onError: console.log(msg)
    }

    Component.onCompleted: {
        console.log( "WRITE"+ myFile.write("TEST"));
        myText.text =  myFile.read();
    }
}

注意:我已经从诺基亚教程中更改了一些“ FileIO ”,以避免混淆。

答案 2 :(得分:1)

可以在此页面上找到FileIO的完整示例:https://qmlbook.github.io/ch17-extensions/extensions.html#fileio-implementation

class FileIO : public QObject {
    ...
    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
    ...
public:
    Q_INVOKABLE void read();
    Q_INVOKABLE void write();
    ...
}
  

我们将遗漏属性,因为它们是简单的设置者和吸气剂。

     

read方法以读取模式打开文件,并使用文本流读取数据。

void FileIO::read()
{
    if(m_source.isEmpty()) {
        return;
    }
    QFile file(m_source.toLocalFile());
    if(!file.exists()) {
        qWarning() << "Does not exits: " << m_source.toLocalFile();
        return;
    }
    if(file.open(QIODevice::ReadOnly)) {
        QTextStream stream(&file);
        m_text = stream.readAll();
        emit textChanged(m_text);
    }
}
  

更改文本后,必须使用emit textChanged(m_text)通知其他人有关更改的信息。否则,属性绑定将不起作用。

     

write方法执行相同操作,但在写入模式下打开文件并使用流写入内容。

void FileIO::write()
{
    if(m_source.isEmpty()) {
        return;
    }
    QFile file(m_source.toLocalFile());
    if(file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << m_text;
    }
}

源代码可以在这里找到: https://github.com/qmlbook/qmlbook/tree/master/docs/ch17-extensions/src/fileio

答案 3 :(得分:1)

使用V-Play SDK,您可以使用QML中的FileUtils类来访问任何平台上的文件系统。

这看起来像这样:

var success = fileUtils.writeFile("TextFiles/myFile.txt", "test text")