Jak używać modeli z QML?
Mam GUI napisane w qml i c++. Istnieją 2 comboboxy (Kontrola qt 5.1). Drugi combobox musi aktualizować się w czasie wykonywania przy każdej zmianie wartości pierwszego.
maincontext->setContextProperty("typemodel", QVariant::fromValue(m_typemodel));
maincontext->setContextProperty("unitmodel", QVariant::fromValue(m_unitmodel));
Są to 2 modele, które daję qml z 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);
}
To pierwszy combobox. Jak widać, model C++ drugiego comboboxu jest aktualizowany za każdym razem, gdy zmienia się wartość pierwszego (mainwin.unitGenerator (typebox.currentText)). Ale wydaje się, że nie aktualizuje modelu combobox.
Jak zaktualizować model qml w trybie runtime?
2 answers
Aby nawet zacząć rozwiązywać twój problem, musimy zobaczyć, co robi metoda unitGenerator
. Jeśli używasz modelu niestandardowego, jest prawie pewne, że nie wdrażasz powiadomień poprawnie. Założę się, że nie sygnalizujesz resetu modelu.
Poniżej znajduje się kompletny przykład kodu, który pokazuje, jak można powiązać QStringListModel
z edytowalnym ListView
i ComboBox
es. Drugi model ComboBox
jest regenerowany na podstawie wyboru z pierwszego. To prawdopodobnie przybliża pożądaną funkcjonalność.
Zwróć uwagę na specyficzną obsługę ról wykonywaną przez QStringListModel
. Model traktuje role wyświetlania i edycji prawie tak samo: obie są mapowane do wartości łańcuchowej na liście. Jednak kiedy aktualizujesz dane konkretnej roli, sygnał dataChanged
niesie tylko rolę, którą zmieniłeś. Można to wykorzystać do przerwania pętli wiążącej, która w innym przypadku może być obecna w elemencie edytora modeli (TextInput). W przypadku korzystania z modelu niestandardowego może być konieczne zaimplementuj podobną funkcjonalność.
Rola display
jest używana do łączenia pól combo z modelem. Rola edit
służy do wstępnego wypełniania obiektów edytora. Funkcja obsługi sygnału onTextChanged
edytora aktualizuje rolę display
, a to nie powoduje pętli wiążącej do siebie. Jeśli funkcja obsługi aktualizowała rolę edit
, wywołałaby pętlę wiążącą za pośrednictwem właściwości text
.
Na modelach w QML
Istnieją różne rodzaje "modeli" w QML. Wewnętrznie, QML zawija prawie "wszystko" w modelu. Wszystko, co jest wewnętrznie , a nie QObject , nadal może być modelem (powiedzmy QVariant
), nie będzie powiadamiać nikogo o niczym.
Na przykład "model" oparty na QVariant
, który owija int
nie będzie wysyłać powiadomień, ponieważ QVariant
nie jest QObject
, które mogłyby sygnalizować zmiany.
Podobnie, jeśli twój "model" jest powiązany z wartością właściwości klasy pochodzącej z QObject
, ale nie uda Ci się emit
sygnału powiadomienia o zmianie właściwości, to również to nie zadziała.
Bez wiedzy, jakie są Twoje typy modelek, nie da się powiedzieć.
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 <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QStringListModel>
#include <QQmlContext>
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<QQuickWindow *>(topLevel);
window->show();
return app.exec();
}
#include "main.moc"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-23 18:04:12
To właściwie odpowiedź / komentarz do odpowiedzi @KubaOber.
Stwierdziłem, że w rzeczywistości nie jest konieczne wykonywanie specjalnych trików przy użyciu wielu ról, jeśli wiąże się z odpowiednim zdarzeniem:
onAccepted: model.edit = text
Działa bez zarzutu i nie tworzy żadnej pętli update (ponieważ jest wywoływana tylko przy modyfikacjach"human" /input).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-30 17:04:48