如何导出qml

时间:2019-04-23 08:29:00

标签: qt qml

我想做的是一个通用函数,该函数获取有关所有输入字段(TextField,SpinBox,ComboBox,也许我忘记的一些信息)的信息

让我们想象一下这种形式:

enter image description here

我想得到一个填充在那里的物体。它必须检查它是TextField还是ComboBox,因为获取信息的方式不同。

所以我想要类似这样的“元”代码:

Object = {}
for(input in inputs) {
  if(input.type=="TextField") {
    Object.push(input.text)
  } else if (input.type == "ComboBox") {
    Object.push(input.currentText)
  }
}

我将实现一个按钮或将触发该功能的东西。

为了更困难一点,并非表单的所有元素都处于同一级别,例如,某些元素将是子项。

下面我提供一些我想做的代码:

import QtQuick 2.9
import QtQuick.Controls 2.2
    import QtQuick.Layouts 1.3

ApplicationWindow {
    id: window
    title: "Stack"
    visible: true
    width: 1400

    Page {
        id: page
        anchors.fill: parent
        property int responsiveWidth: 1000
        property int maximumWidth: 900

        ScrollView {
            anchors.fill: parent
            GridLayout {
                columns: 2
                width: page.width > page.responsiveWidth ? page.maximumWidth : page.width
                anchors.top: parent.top
                anchors.left: parent.left
                anchors.leftMargin: page.width > page.responsiveWidth ? (page.width - childrenRect.width)/2 : 10
                anchors.rightMargin: page.width > page.responsiveWidth ? 0 : 10

                    Button {
                        Layout.fillWidth: true
                        Layout.columnSpan: 2
                        text: "export"
                        onClicked: {
                            console.log("here i want to get an object with info related with the fields of these form")
                        }
                    }


                    Label {
                        text: "Company Name"
                        color: "red"
                        Layout.fillWidth: true
                    }

                    TextField  {
                        objectName: "company_name"
                        font.bold: true
                        Layout.fillWidth: true
                        Layout.rightMargin: 10
                    }


                    Label {
                        text: "choices"
                        color: "red"
                        Layout.fillWidth: true
                    }

                    ComboBox {
                        Layout.fillWidth: true
                        model: [ "Banana", "Apple", "Coconut" ]
                    }

                    Item {
                        Layout.fillWidth: true
                        implicitHeight: 100
                        Layout.columnSpan: 2
                        Label {
                            anchors.left: parent.left
                            anchors.top: parent.top
                            text: "label"
                            color: "red"
                            width: parent.width
                        }

                        TextField  {
                            anchors.left: parent.left
                            anchors.bottom: parent.bottom
                            objectName: "company_name"
                            font.bold: true
                            width: parent.width
                            //Layout.rightMargin: 10
                        }
                    }

                    Label {
                        text: "number"
                        color: "red"
                        Layout.fillWidth: true
                    }

                    SpinBox {
                        id: spinBox1
                        height: 30
                        stepSize: 1
                        editable: true
                        Layout.fillWidth: true
                        Layout.rightMargin: 10
                    }
            }
        }
    }
}

有一种方法可以检查组件的类型,但是我们需要传递它的id

            function isTextField(item) {
              return item instanceof TextField
            }

是否使用了不是组件instaceof的其他引用来使用id

我曾经想到要像这样children的{​​{1}}

component

2 个答案:

答案 0 :(得分:1)

对于QML表单,应使用TableView,并且应使用包含表单标签和输入的自定义表格模型:

NmForm.qml:

import QtQuick 2.9
import QtQuick.Controls 2.2
import Nmaster 13.37

TableView {
    id: form_table
    model: TableModel {
        fields: [
            {
                f_label: "Company Name",
                f_input: ""
            },
            {
                f_label: "Choices",
                f_input: ""
            },
            // And so on
        ]
    }

    delegate: Item {
        Label {
            color: "red"
            anchors.fill: parent
            visible: column === 0
            text: f_label // fieldInfos[row].label on the C++ side, displayed with the "f_label" role defined in roleNames().
        }

        TextField {
            anchors.fill: parent
            visible: column === 1 && (row ===1 || row === 4 || ... || row === /* another row index where you use a text field */)
            text: f_input // fieldInfos[row].input on the C++ side, displayed with the "f_input" role defined in roleNames().
        }
        // And so on for other input components.
    }

    function getAllFields() {
        return model.getAllFieldValues()
    }
}

main.qml:

import QtQuick 2.9
import QtQuick.Controls 2.2

ApplicationWindow {
    id: window

    //...

    NmForm { id: form }

    //...

    Button {
        id: fields_button
        text: qsTr("Get all fields")
        onclicked: {
            var fields = form.getAllFields()

            for (var i = 0; i < fields.length; i++) {
                console.log(qsTr("Field n°%L1 = %2").arg(i).arg(fields[i]))
            }
        }
    }

    //...
}

tablemodel.hpp:

#ifndef TABLEMODEL_HPP
#define TABLEMODEL_HPP

#include <QAbstractTableModel>
#include <QJsonArray>

class TableModel: public QAbstractTableModel
{
    Q_OBJECT

    public:
        TableModel(QObject * parent = nullptr);
        static void registerQML();

        /// @brief Your "Object = {}; for(input in inputs) { Object.push(/* ... */) }" thing.
        Q_INVOKABLE QStringList getAllFieldValues() const;

        // Implementing QAbstractTableModel
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
        bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
        QHash<int, QByteArray> roleNames() const override;

        typedef enum {
            LABEL_ROLE = Qt::UserRole +1,
            INPUT_ROLE = Qt::UserRole +2    
        } TableRoles;

    protected:
        // Backend datas: one element per row, each element containing input label text and input data
        typedef struct {
            QString label = "";
            QString input = "";  
        } FieldInfo;

        Q_PROPERTY(QJsonArray fields READ getFields WRITE setFields NOTIFY fieldsChanged)
        QList<FieldInfo> fieldInfos;

        QJsonArray getFields() const;
        void setFields(QJsonArray value);

    signals:
        void fieldsChanged();
};

#endif // TABLEMODEL_HPP

tablemodel.cpp:

#include "tablemodel.hpp"
#include <QJsonObject>
#include <QQmlEngine>

TableModel::TableModel(QObject * parent = nullptr) :
    QAbstractTableModel(parent),
    fieldInfos()
{}

void TableModel::registerQML() {
    qmlRegisterType<TableModel>("Nmaster", 13, 37, "TableModel");
}

QVariant TableModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
    if (!index.isValid()) {
        return QVariant();
    }

    int row = index.row();
    int column = index.column();

    if (column == 0 && role == TableRoles::LABEL_ROLE) {
        return fieldInfos[row].label;
    }
    else if (column == 1 && role == TableRoles::INPUT_ROLE) {
        return fieldInfos[row].input;
    }
    else {
        return QVariant();
    }
}

bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override {
    if (!index.isValid()) {
        return false;
    }

    bool res = true;
    int row = index.row();
    int column = index.column();
    QVector<int> rolesChanged;

    if (column == 0 && role == TableRoles::LABEL_ROLE) {
        fieldInfos[row].label = value.toString();
        rolesChanged << TableRoles::LABEL_ROLE;
    }
    else if (column == 1 && role == TableRoles::INPUT_ROLE) {
        fieldInfos[row].input = value.toString();
        rolesChanged << TableRoles::INPUT_ROLE;
    }
    else {
        res = false;
    }

    emit dataChaged(index, index, rolesChanged);
    return res;
}

int TableModel::rowCount(const QModelIndex &parent = QModelIndex()) const override {
    return fieldInfos.count();
}

// One column for labels, another one for inputs.
int TableModel::columnCount(const QModelIndex &parent = QModelIndex()) const override {
    return 2;
}

QHash<int, QByteArray> TableModel::roleNames() const override {
    QHash<int, QByteArray> roles;
    roles["f_label"] = TableRoles::LABEL_ROLE;
    roles["f_input"] = TableRoles::INPUT_ROLE;
    return roles;
}

QJsonArray TableModel::getFields() const {
    QJsonArray res;

    for (auto it = fieldInfos.begin(); it != fieldInfos.end(); ++it) {
        QJsonObject obj;
        obj["f_label"] = it->label;
        obj["f_input"] = it->input;
        res << obj;
    }

    return res;
}

void TableModel::setFields(QJsonArray value) {
    fieldInfos.clear();

    for (auto it = value.begin(); it != value.end(); ++it) {
        QJsonObject o = it->toObject();
        FieldInfo fi;
        fi.label = o["f_label"];
        fi.input = o["f_input"];
        fieldInfos << fi;
    }

    emit fieldsChanged();
}

QStringList TableModel::getAllFieldValues() const {
    QStringList res;

    for (auto it = fieldInfos.begin(); it != fieldInfos.end(); ++it) {
        res << it->input;
    }

    return res;
}

main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include "tablemodel.hpp"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // ...

    TableModel::registerQML();

    // ...

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    int res = engine.rootObjects().isEmpty() ? -1 : app.exec();

    // ...

    return res;
}

答案 1 :(得分:0)

非常感谢@ air-dex作为答案。这似乎是一个可能的解决方案,但是我以另一种方式解决了这个问题。

导出功能为:

        Button {
            text: "export"
            onClicked: {
                var info
                var viewData = []
                var listObjects = configgrid.children
                for(var i=0; i<listObjects.length; i++) {
                    if(listObjects[i].getInfo !== undefined) {
                        info = listObjects[i].getInfo()
                        if(info.length > 0) {
                            for(var j=0; j<info.length; j++) {
                                viewData.push([info[j]['label'],info[j]['value']])
                            }
                        } else{
                            viewData.push([info['label'],info['value']])
                        }
                    }
                }
                dl.exportTest(JSON.stringify(viewData))
            }
            Component.onCompleted: {

            }
        }

因此,在我的情况下,表单的父项是GridLayout。那是我送孩子的地方。

然后,我检查GridLayout中的组件是否已实现功能getInfo(),如果已经实现,则它们对导出很重要。

我举一个TextField的例子:

            PanelTextField {
                id: companyNameText
                labelExport: companyNameLabel.text
function getInfo() {
    var dict = {
        label: this.labelExport,
        value: this.text
    }
    return dict
}
                KeyNavigation.tab: languagesComboBox
                objectName: "company_name"
                Layout.fillWidth: true
                maximumLength: Globals.COMPANY_NAME_LEN
                selectByMouse: true
                Layout.columnSpan: page.width > page.responsiveWidth ? 1 : 2
            }

如果我有一个RowLayout,我可以这样做:

RowLayout {
    function getInfo() {
        var selfList = this.children
        var info = []
        for(var i=0; i<selfList.length; i++) {
            if(selfList[i].getInfo !== undefined) {
                info.push(selfList[i].getInfo())
            }
        }
        return info
    }
}

这看起来效果很好。

您对此有何看法?