Qmlとc ++で書かれたGUIがあります。 2つのコンボボックスがあります(qtコントロール5.1)。 2番目のコンボボックスは、最初のコンボボックスの値が変更されるたびに、実行時に更新する必要があります。
maincontext->setContextProperty("typemodel", QVariant::fromValue(m_typemodel));
maincontext->setContextProperty("unitmodel", QVariant::fromValue(m_unitmodel));
これらは私がc ++からqmlに与える2つのモデルです。
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);
}
これは最初のコンボボックスです。ご覧のとおり、2番目のコンボボックスのc ++モデルは、最初のコンボボックスの値が変更されるたびに更新されます(mainwin.unitGenerator(typebox.currentText))。しかし、それはコンボボックスのモデルを更新していないようです。
実行時にqmlのモデルを更新するにはどうすればよいですか?
問題への対処を開始するには、unitGenerator
メソッドの機能を確認する必要があります。カスタムモデルを使用している場合、通知を正しく実装していないことはほぼ確実です。現時点での私の賭けは、モデルのリセットを通知していないことです。
以下は、QStringListModel
を編集可能なListView
およびComboBox
esに関連付ける方法を示す完全なコード例です。 2番目のComboBox
のモデルは、最初のモデルからの選択に基づいて再生成されます。これはおそらく望ましい機能に近いものです。
QStringListModel
によって行われるロールの特定の処理に注意してください。モデルは表示と編集の役割をほぼ同じに扱います。どちらもリスト内の文字列値にマップされます。ただし、特定のロールのデータを更新すると、dataChanged
シグナルは変更したロールをのみ伝えます。これは、モデルエディターアイテム(TextInput)に存在する可能性のあるバインディングループを解除するために使用できます。カスタムモデルを使用する場合、同様の機能を実装する必要がある場合があります。
display
ロールは、コンボボックスをモデルにバインドするために使用されます。 edit
ロールは、エディターオブジェクトを事前入力するために使用されます。エディターのonTextChanged
シグナルハンドラーがdisplay
ロールを更新しています。これにより、バインディングループ自体が発生することはありません。ハンドラがedit
ロールを更新している場合、text
プロパティを介してバインディングループが発生します。
QMLにはさまざまな種類の「モデル」があります。内部的には、QMLはモデルのほとんどすべてのものをラップします。内部的にはQObjectではないものの、まだモデルである可能性があります(たとえば、QVariant
)、誰にも何も通知しません。
たとえば、QVariant
は変更を通知するint
ではないため、QVariant
をラップするQObject
に基づく「モデル」は通知を発行しません。
同様に、「モデル」がQObject
から派生したクラスのプロパティ値に関連付けられているが、プロパティ変更通知信号をemit
に失敗した場合も、機能しません。
モデルのタイプが何であるかを知らなければ、それを知ることは不可能です。
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"
これは実際には@KubaOberの回答に対する回答/コメントの多くです。
正しいイベントにバインドする場合、複数のロールを使用して特別なトリックを行う必要は実際にはないことがわかりました。
onAccepted: model.edit = text
正常に動作し、更新ループは作成されません(「人間」/入力の変更でのみ呼び出されるため)。