【问题标题】:Reading and writing files in QML (Qt)在 QML (Qt) 中读写文件
【发布时间】:2013-07-26 13:25:07
【问题描述】:

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

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

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

当我将上述代码 sn-p 放在我的主窗体中时,我还不断收到关于 qmlRegisterType 未在上下文中注册的错误。 有人可以就如何实现这个(或在 QML / Qt 中读写文件的任何方法)提供一些建议吗?

【问题讨论】:

  • 这绝对是 C++ 中要做的事情。让 QML 保持其应有的薄 UI 层。
  • 弗兰克,感谢您的回复。实际上,链接中的代码是 C++ 中文件访问的实现,我的问题是如何完成这个(再次在 C++ 中)
  • 你的“主要形式”是什么?
  • alexisdm - 我没有主要的 ID,它位于 main.qml

标签: qt qml


【解决方案1】:

如果你的文件是纯文本的,你可以使用 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. ";
    }
}

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

【讨论】:

    【解决方案2】:

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

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

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

    为了使用这个函数,你必须在你编写它的 C++ 文件中包含一个 C++ 头文件:

    • 如果您使用 Qt 4,则标头为 &lt;QtDeclarative&gt;。
    • 如果您使用 Qt 5,则标头为 &lt;QtQml&gt;。

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

    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”。

    【讨论】:

    • air-dex - 谢谢。我想这个教程是为有经验的程序员准备的,但从来没有搞清楚 qmlRegisterType 参数,这完全让我大吃一惊!但就像我怀疑的那样,事实证明就是这么简单。再次感谢,在 stackoverflow 中失去了希望!
    【解决方案3】:

    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();
        ...
    }
    

    我们将省略属性,因为它们是简单的 setter 和 getter。

    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

    【讨论】:

    【解决方案4】:

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

    看起来像这样:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多