Reputation: 1405
I've exposed a QList<MyItem*>
as a model for a ListView
. But how can I get the ListView
index of a MyItem*
object?
Context: I'm making a findObject() function in C++ and when I've found the object (a MyItem*
), I want to scroll to the corresponding item in the ListView
.
Some code (full source code and Qt Creator project can be found at https://github.com/joncol/qml_test).
The item class:
class MyItem : public QObject
{
Q_OBJECT
Q_PROPERTY(qint32 data READ data NOTIFY dataChanged)
public:
MyItem() : m_data(s_counter++) {}
quint32 data() const { return m_data; }
signals:
void dataChanged();
private:
static int s_counter;
int m_data;
};
The model:
class MyCppModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<MyItem> itemList READ itemList NOTIFY itemListChanged)
public:
MyCppModel()
{
m_specialItem = new MyItem;
m_model.append(new MyItem);
m_model.append(new MyItem);
m_model.append(new MyItem);
m_model.append(m_specialItem);
m_model.append(new MyItem);
}
QQmlListProperty<MyItem> itemList()
{
return QQmlListProperty<MyItem>(this, m_model);
}
Q_INVOKABLE QVariant specialItem()
{
return QVariant::fromValue(m_specialItem);
}
signals:
void itemListChanged();
private:
QList<MyItem*> m_model;
MyItem* m_specialItem; // simulate found item
};
The 'main' function:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
QQmlContext* c = engine.rootContext();
MyCppModel* myCppModel = new MyCppModel;
c->setContextProperty("myCppModel", myCppModel);
qmlRegisterUncreatableType<MyItem>("CppModel", 1, 0, "MyItem", "");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
And, finally the QML:
ApplicationWindow {
title: qsTr("Testing")
width: 640
height: 480
visible: true
ColumnLayout {
anchors.centerIn: parent
Rectangle {
width: 150
height: 25
color: "#e67e22"
border.width: 1
border.color: "black"
Text {
anchors.centerIn: parent
text: "Mark Special Item"
}
MouseArea {
anchors.fill: parent
onClicked: {
var item = myCppModel.specialItem()
console.debug("how to color the special item: " + item)
}
}
}
ListView {
id: itemList
width: 200
height: 25 * count
model: myCppModel.itemList
delegate: Item {
width: parent.width
height: 25
Rectangle {
width: parent.width
height: 20
color: "#34495e"
border.width: 1
border.color: "black"
Text {
x: 10
anchors.verticalCenter: parent.verticalCenter
text: modelData.data
color: "white"
}
}
}
}
}
}
Upvotes: 2
Views: 1151
Reputation: 24416
There are a few ways to do this, depending on your application logic.
1. Add a isSpecialItem
property to MyItem
class MyItem : public QObject
{
Q_OBJECT
Q_PROPERTY(qint32 data READ data NOTIFY dataChanged)
Q_PROPERTY(bool isSpecialItem READ isSpecialItem WRITE setIsSpecialItem NOTIFY isSpecialItemChanged)
// ...
}
Your delegate would then look like this:
Rectangle {
width: parent.width
height: 20
color: "#34495e"
border.width: 1
border.color: isSpecialItem ? "red" : "black"
Text {
x: 10
anchors.verticalCenter: parent.verticalCenter
text: modelData.data
color: "white"
}
}
This is the easiest approach, but pollutes MyItem
with something that you might consider more UI-specific.
2. Make MyCppModel
derive from QAbstractItemModel
With this option, you could have a SpecialItem
role that is available in the delegate, with the QML code for the delegate being identical to option #1.
I would call this the canonical approach to this problem, especially if itemList
does not need to be a QQmlListProperty
. It doesn't require adding the potentially UI-specific isSpecialItem
property to MyItem
, and can be stored in the same way that you're currently storing it; in your data() function, you'd write something like:
if (role == SpecialItem) {
return QVariant(m_specialItem == m_model.at(index.row()));
}
3. Expose the special item as an index property of the list
To do it this way, you'd turn the specialItem()
function into a property of MyCppModel
:
Q_PROPERTY(int specialItemIndex READ specialItemIndex WRITE specialItemIndex NOTIFY specialItemIndexChanged)
Then, your delegate would look very similar to option 2, except for one line:
border.color: myCppModel.specialItemIndex == index ? "red" : "black"
Upvotes: 1