【问题标题】:How to export information of fields in qmlqml中如何导出字段信息
【发布时间】:2019-04-27 00:19:19
【问题描述】:

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

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

我想要一个对象来获取那里填充的内容。它必须检查它是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
            }

使用不是组件的id 的其他引用来使用instaceof 是否有变化?

我想像这样获得componentchildren

var objects = configgrid.children

【问题讨论】:

  • 你不能“传递 id”,id 不是一个属性,一般来说它是一个指向对象的指针。所以通过传递 id 你传递对对象的引用。但我仍然不确定 instaceof 是否可以返回除 ItemQObject 之外的其他内容。应该检查一下。

标签: qt qml


【解决方案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;
}

【讨论】:

    【解决方案2】:

    非常感谢@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
        }
    }
    

    这似乎工作得很好。

    你有什么意见?

    【讨论】:

      猜你喜欢
      • 2013-12-21
      • 1970-01-01
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 2019-05-15
      • 2022-01-13
      • 2018-09-06
      • 2012-03-29
      相关资源
      最近更新 更多