Come usare i modelli con QML?

Ho una GUI scritta in qml e c ++. Ci sono 2 caselle combinate (controllo qt 5.1). La seconda casella combinata deve essere aggiornata in fase di esecuzione ogni volta che viene modificato il valore della prima.

maincontext->setContextProperty("typemodel", QVariant::fromValue(m_typemodel)); maincontext->setContextProperty("unitmodel", QVariant::fromValue(m_unitmodel)); 

Questi sono 2 modelli che io do a qml da c ++.

 ComboBox { id: typebox anchors.left: text1.right anchors.leftMargin: 5 signal changed(string newtext) width: 70 height: 23 anchors.top: parent.top anchors.topMargin: 37 model: typemodel onCurrentTextChanged: { mainwin.unitGenerator(typebox.currentText); } 

Questa è la prima casella combinata. Come vedi, il modello c ++ della seconda casella combinata viene aggiornato ogni volta che viene modificato il valore della prima (mainwin.unitGenerator (typebox.currentText)). Ma non sembra aggiornare il modello della combobox.

Come posso aggiornare il modello di qml su runtime?

Per iniziare a risolvere il problema, dovremmo vedere cosa fa il metodo unitGenerator . Se stai utilizzando un modello personalizzato, è quasi certo che non stai implementando correttamente le notifiche. La mia scommessa al momento sarebbe che non stai segnalando il reset del modello.

Di seguito è riportato un esempio di codice completo che mostra come è ansible QStringListModel un QStringListModel a un ListView modificabile e a un ComboBox . Il secondo modello di ComboBox viene rigenerato in base alla selezione del primo. Questo presumibilmente si avvicina alla tua funzionalità desiderata.

Si noti la gestione specifica dei ruoli eseguita da QStringListModel . Il modello tratta la visualizzazione e modifica i ruoli quasi allo stesso modo: entrambi sono associati al valore di stringa nell’elenco. Tuttavia, quando aggiorni i dati di un particolare ruolo, il segnale dataChanged trasporta solo il ruolo che hai cambiato. Questo può essere usato per interrompere un loop di binding che potrebbe essere altrimenti presente nell’elemento dell’editor del modello (TextInput). Quando si utilizza un modello personalizzato, potrebbe essere necessario implementare funzionalità simili.

Il ruolo di display viene utilizzato per associare le caselle combinate al modello. Il ruolo di edit viene utilizzato per precompilare gli oggetti dell’editor. Il gestore del segnale onTextChanged dell’editor sta aggiornando il ruolo di display e questo non causa un loop di binding a se stesso. Se il gestore stava aggiornando il ruolo di edit , causerebbe un loop di legame tramite la proprietà text .

Sui modelli in QML

Esistono vari tipi di “modelli” in QML. Internamente, QML avvolgerà quasi “qualsiasi cosa” in un modello. Tutto ciò che non è internamente un QObject può ancora essere un modello (ad esempio un QVariant ), non notificherà nessuno su nulla.

Ad esempio, un “modello” basato su QVariant che avvolge un int non genererà notifiche, perché QVariant non è un QObject che potrebbe segnalare cambiamenti.

Allo stesso modo, se il tuo “modello” è legato a un valore di proprietà di una class derivata da QObject , ma non si riesce a emit il segnale di notifica di modifica delle proprietà, anche questo non funzionerà.

Senza sapere quali sono i tuoi modelli, è imansible dirlo.

main.qml

 import QtQuick 2.0 import QtQuick.Controls 1.0 ApplicationWindow { width: 300; height: 300 ListView { id: view width: parent.width anchors.top: parent.top anchors.bottom: column.top model: model1 spacing: 2 delegate: Component { Rectangle { width: view.width implicitHeight: edit.implicitHeight + 10 color: "transparent" border.color: "red" border.width: 2 radius: 5 TextInput { id: edit anchors.margins: 1.5 * parent.border.width anchors.fill: parent text: edit // "edit" role of the model, to break the binding loop onTextChanged: model.display = text } } } } Column { id: column; anchors.bottom: parent.bottom Text { text: "Type"; } ComboBox { id: box1 model: model1 textRole: "display" onCurrentTextChanged: generator.generate(currentText) } Text { text: "Unit"; } ComboBox { id: box2 model: model2 textRole: "display" } } } 

main.cpp

 #include  #include  #include  #include  #include  class Generator : public QObject { Q_OBJECT QStringListModel * m_model; public: Generator(QStringListModel * model) : m_model(model) {} Q_INVOKABLE void generate(const QVariant & val) { QStringList list; for (int i = 1; i <= 3; ++i) { list << QString("%1:%2").arg(val.toString()).arg(i); } m_model->setStringList(list); } }; int main(int argc, char *argv[]) { QStringListModel model1, model2; Generator generator(&model2); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QStringList list; list << "one" << "two" << "three" << "four"; model1.setStringList(list); engine.rootContext()->setContextProperty("model1", &model1); engine.rootContext()->setContextProperty("model2", &model2); engine.rootContext()->setContextProperty("generator", &generator); engine.load(QUrl("qrc:/main.qml")); QObject *topLevel = engine.rootObjects().value(0); QQuickWindow *window = qobject_cast(topLevel); window->show(); return app.exec(); } #include "main.moc" 

Questo è in realtà più di una risposta / commento alla risposta di @KubaOber.

Ho scoperto che in realtà non è necessario eseguire trucchi speciali utilizzando più ruoli se ci si lega all’evento corretto:

 onAccepted: model.edit = text 

funziona perfettamente e non crea alcun ciclo di aggiornamento (dato che è chiamato solo su “human” / input change).