PDA

View Full Version : Using list model in C++ code with UI in QML



chiru
23rd November 2010, 12:14
Hello,
I am writing an application that fetches few items from the symbian database and adds them to a list view that is shown using QML.
I am using listview in my qml file and i have named the model to that list view as "listModel"
Hence, I am initialising it in C++ code like this:

QDeclarativeContext *context = view->rootContext();

context->setContextProperty("listModel",QVariant::fromValue(mItemsList));

where, mItemsList is a QList of items.

Things are working fine till now. Now, when I get a notification that new item has been added, I want to update the model.
Right now, am again calling:

context->setContextProperty("listModel",QVariant::fromValue(mAlarmsList));

This will again set the new model to the list view. This is working fine.
But, I would like to know, if this is the only way to update the model.
Is there a way to append/insert just newly added item to the already existing model in my C++ code?

One more thing -> As you all might know, listview has a property called "currentIndex".
If I want to manipulate this property of the list view that is defined in qml, how can I do that?

Regards
Chiru

shalu
1st December 2010, 14:24
Hi Chiru ,
Can u pls explain a little more,I have also created 1 list,it needs to be updated when any item is added/removed or edited.
I am also calling setContextProperty again.But list is not getting updated.
Please paste few lines of code to understand in better way.

wysota
1st December 2010, 16:56
You do not really have a model, you just have a static list of items that acts as a model. You can implement your model in the QAbstractItemModel infrastructure and set your qml item's model to that. Then every update of this model in C++ should immediately be reflected in qml.

delor
3rd December 2010, 07:06
How to expose item's data from such model to QML's delegate.

wysota
3rd December 2010, 10:00
Read the docs about Using QML in C++ Applications.

delor
3rd December 2010, 10:50
Let me provide example of what I'm trying to do.


// addressbook.cpp
AddressBook::AddressBook(QObject *parent) :
QSqlQueryModel(parent)
{
setQuery("select * from person");
setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
setHeaderData(1, Qt::Horizontal, QObject::tr("firstName"));
setHeaderData(2, Qt::Horizontal, QObject::tr("lastName"));
}

// main.cpp
int main(int argc, char *argv[]) {
// ...
AddressBook addressBook;
rootContex->setContextProperty("addressBook", &addressBook);
// ...
}

// main.qml
import Qt 4.7

Rectangle {
// ...

ListView {
id: list

anchors.fill: parent
model: addressBook
delegate: Item {
Column {
Text {
text: firstname
}
Text {
text: lastName
}
}
}
}
}

wysota
3rd December 2010, 11:04
And the problem is...?

Hint: There is an example in examples/declarative/modelviews that shows you how to use a c++ model with qml.

Another hint: ListView is a single column view.

delor
3rd December 2010, 11:31
And the problem is...?
...that it can't reference variables firstname and lastName.


Another hint: ListView is a single column view.
What does this have to do with my example?

wysota
3rd December 2010, 12:54
...that it can't reference variables firstname and lastName.

What does this have to do with my example?

Exactly that. It can't reference those variables because you think that settng header names for model columns implicitly binds them with QML variables which is not the case. You can only accessroles of a single column from within Qt Quick's ListView element and you have to tell QtQuick what the roles are called. To use a multicolumn model with ListView you need a proxy model that will turn single role multiple column model into single column multiple role model.

delor
3rd December 2010, 14:13
How about this then:
// addressbook.cpp
AddressBook::AddressBook(QObject *parent) :
QSqlQueryModel(parent)
{
setQuery("select * from person");

QHash<int, QByteArray> roles;
roles[FirstName] = "firstName";
roles[LastName] = "lastName";
setRoleNames(roles);
}

QVariant AddressBook::data(const QModelIndex &item, int role) const
{
QSqlRecord *r = reinterpret_cast<QSqlRecord*>(item.internalPointer());

if (role == FirstName)
return r->field("firstname").value();
if (role == LastName)
return r->field("lastName").value();
return QVariant();
}item.internalPointer() returns null pointer all the time.

wysota
3rd December 2010, 14:17
Why would it return a valid QSqlRecord pointer?

delor
3rd December 2010, 14:57
This worked out just fine:

QVariant AddressBook::data(const QModelIndex &item, int role) const
{
switch (role) {
case FirstName:
return record(item.row()).field("firstname").value();
break;
case LastName:
return record(item.row()).field("lastName").value();
break;
default:
return QSqlQueryModel::data(item, role);
break;
}
}

wysota
3rd December 2010, 15:56
I made a quick implementation of a general way to solve this situation:

QMLifyProxyModel

nouch64
28th November 2011, 08:01
Hi,

QMLifyProxyModel works quite good for me.
Just one bug correction on it :

The function QMLifyProxyModel::rowCount is actually returning columnCount.
Need to modify it :



int QMLifyProxyModel::rowCount(const QModelIndex &parent) const
{
if(!sourceModel())
return 0;
if(parent.isValid())
return 0;

return sourceModel()->rowCount();
}

olegdim
21st August 2012, 22:58
can you show all structure of connection list model in C++ code with UI in QML???
thanks
i have the same issue

nouch64
22nd August 2012, 02:21
can you show all structure of connection list model in C++ code with UI in QML???

Sorry, I don't have it anymore, it was in my previous company one year ago.