I. L'article original▲
Cet article est une adaptation en langue française de Expose nested C++ models to QML.
II. Côté C++▲
Le point de départ est la création d'un modèle C++ qui hérite de QAbstractListModel, comme expliqué dans l'article Utiliser un modèle de liste C++ en QML. On appellera ce modèle FacebookWallModel. Dans l'exemple, chaque item de ce modèle (on appelle leur classe SocialUpdateItem) aura comme propriété un autre modèle contenant les commentaires (CommentsModel).
Voici une version raccourcie du code de SocialUpdateItem. Il ne devrait pas y avoir de surprise.
typedef
ListModel CommentsModel;
class
SocialUpdateItem: public
ListItem {
Q_OBJECT
public
:
enum
Roles {
IdRole =
Qt
::
UserRole+
1
,
SenderRole,
DescriptionRole,
PostTimeRole,
AvatarRole /* ... */
}
;
public
:
SocialUpdateItem(): ListItem() {}
SocialUpdateItem(QString
id, QObject
*
parent=
0
): ListItem(parent), m_id(id) {
// FIXME : instancier m_comments
}
inline
QString
id() const
{
return
m_id;
}
QVariant
data(int
role) const
{
switch
(role) {
case
IdRole:
return
m_id;
/* D'autres rôles... */
default
:
return
QVariant
();
}
}
QHash
<
int
, QByteArray
>
roleNames() const
{
QHash
<
int
, QByteArray
>
roles;
roles[IdRole] =
"socialUpdateId"
;
roles[SenderRole] =
"sender"
;
roles[DescriptionRole] =
"description"
;
/* D'autres rôles... */
return
roles;
}
CommentsModel*
comments() const
{
return
m_comments;
}
private
:
QString
m_id;
CommentsModel *
m_comments;
}
;
À présent, voici FacebookWallModel, le modèle qui sera directement exposé à QML.
class
FacebookWallModel : public
ListModel
{
Q_OBJECT
public
:
explicit
FacebookWallModel(QObject
*
parent =
0
):
ListModel(new
SocialUpdateItem, parent) {
}
Q_INVOKABLE
QObject
*
activityComments(const
QString
&
id) const
{
SocialUpdateItem *
update =
static_cast
<
SocialUpdateItem*>
(find(id));
if
(update) {
return
update->
comments();
}
return
0
;
}
}
;
Comme on peut le voir, le truc, ici, est d'utiliser la macro Q_INVOKABLE pour rendre la fonction activityComments() disponible à QML, comme expliqué dans la documentation. On utilisera cette fonction dans le code QML plus tard pour avoir accès aux commentaires depuis le délégué SocialUpdate. Notez que cette fonction retourne un pointeur sur QObject au lieu d'un pointeur sur ListModel (ou QAbstractListModel). Ceci est requis pour le faire fonctionner, puisque QML ne reconnaît pas d'autres types de données (voir la liste des types supportés).
On expose alors ce modèle à QML :
int
main(int
argc, char
*
argv[])
{
QApplication
app(argc, argv);
QDeclarativeView
view;
FacebookWallModel wall_model(&
app);
view.rootContext()->
setContextProperty("wallModel"
, &
wall_model);
view.setSource(QUrl
::
fromLocalFile("qml/NestedModels/main.qml"
));
view.show();
return
app.exec();
}
III. Côté QML▲
En QML, on utilisera une ListView pour afficher les données du FacebookWallModel.
Rectangle
{
width
:
360
height
:
360
ListView
{
id
:
wallView
anchors.fill
:
parent
model
:
wallModel
delegate
:
SocialUpdateDelegate{}
}
}
Dans le délégué SocialUpdate, on peut afficher le texte de la notification mais aussi le commentaire. Pour accéder au commentaire de l'activité sociale actuelle, on appelle la fonction C++ activityComments(). Dans l'exemple, on utilise l'identifiant de notification sociale pour récupérer son commentaire ; cependant, on aurait pu utiliser son index dans le modèle (voir ListView.currentIndex).
Rectangle
{
id
:
socialUpdateDelegate
width
:
socialUpdateDelegate.ListView.view.width
height
:
updateCol.height
color
:
"#c0c0c0"
Column
{
id
:
updateCol
width
:
parent.width
Text
{
id
:
updateText
width
:
parent.width
text
:
"<b>"
+
sender+
":</b> "
+
description
}
Rectangle
{
id
:
commentsBox
color
:
"white"
anchors.left
:
parent.left
anchors.right
:
parent.right
anchors.leftMargin
:
5
anchors.rightMargin
:
5
height
:
commentsCol.height
Column
{
id
:
commentsCol
width
:
parent.width
Repeater
{
id
:
comments
width
:
parent.width
model
:
wallModel.activityComments(socialUpdateId)
delegate
:
CommentDelegate{}
}
}
}
}
}
On a utilisé un Repeater au lieu d'une ListView pour afficher les commentaires, car il est plus léger et suffit aux besoins.
VI. Remerciements▲
Merci à Claude Leloup pour sa relecture attentive !