我想做的是一个通用函数,该函数获取有关所有输入字段(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
}
是否使用了不是组件instaceof
的其他引用来使用id
?
我曾经想到要像这样children
的{{1}}
component
答案 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
}
}
这看起来效果很好。
您对此有何看法?