2016-09-14 1 views
1

Comment puis-je renvoyer une sous-classe QObject personnalisée à partir de QAbstractListModel et l'utiliser dans un ListView QML. J'ai essayé de retourner les objets en tant que rôle d'affichage et j'utilise dans mon affichage qml display.property pour accéder aux propriétés, ça marche bien mais j'ai vu sur certaines publications des gens utilisant model comme qobject de qml et accédant aux propriétés comme model.property . Ai-je raté quelque chose? Une autre question: Si je veux exposer l'objet au niveau ListView et l'utiliser pour définir un autre panneau comme un détail de la vue maître expose le rôle (dans mon cas affichage) comme une propriété de variante dans le délégué et le définir au niveau listview avec le signal onCurrentItemChanged est la bonne façon de le faire?Renvoyer une sous-classe QObject personnalisée à partir de QAbstractListModel et l'utiliser dans un ListView

ce que je suis en train, mais cela ne fonctionne pas:

#ifndef NOTE_H 
#define NOTE_H 

#include <QObject> 

class Note : public QObject 
{ 
    Q_OBJECT 

    Q_PROPERTY(QString note READ note WRITE setNote NOTIFY noteChanged) 
    Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged) 

    QString m_note; 
    int m_id; 

public: 
    explicit Note(QObject *parent = 0); 
    Note(QString note, int id, QObject *parent = 0); 

    QString note() const 
    { 
     return m_note; 
    } 

    int id() const 
    { 
     return m_id; 
    } 

signals: 

    void noteChanged(QString note); 

    void idChanged(int id); 

public slots: 
    void setNote(QString note) 
    { 
     if (m_note == note) 
      return; 

     m_note = note; 
     emit noteChanged(note); 
    } 
    void setId(int id) 
    { 
     if (m_id == id) 
      return; 

     m_id = id; 
     emit idChanged(id); 
    } 
}; 

#endif // NOTE_H 

le modèle de vue:

#ifndef NOTESVIEWMODEL_H 
#define NOTESVIEWMODEL_H 

#include <QAbstractListModel> 
#include <QVector> 
#include "note.h" 

class NotesViewModel : public QAbstractListModel 
{ 
    Q_OBJECT 

    QVector<Note*> notes; 


public: 
    NotesViewModel(); 

    QVariant data(const QModelIndex &index, int role) const override; 
    int rowCount(const QModelIndex &parent) const override; 

}; 

#endif // NOTESVIEWMODEL_H 

mise en œuvre du modèle de vue:

NotesViewModel::NotesViewModel() 
{ 
    notes.append(new Note("note 1", 1)); 
    notes.append(new Note("note 2", 2)); 
    notes.append(new Note("note 3", 3)); 
    notes.append(new Note("note 4", 4)); 
    notes.append(new Note("note 5", 5)); 
} 

QVariant NotesViewModel::data(const QModelIndex &index, int role) const 
{ 
    qDebug() << "fetching data : " << index.row(); 
    if(!index.isValid()) return QVariant(); 
    if(index.row() >= 5) return QVariant(); 
    if(role == Qt::DisplayRole) 
     return QVariant::fromValue(notes[index.row()]); 
    return QVariant(); 
} 

int NotesViewModel::rowCount(const QModelIndex &parent) const 
{ 
    Q_UNUSED(parent) 
    return notes.count(); 
} 
+1

En général, un modèle n'expose pas ses objets internes mais seulement des choses comme le rôle d'affichage, etc. vous pouvez cependant ajouter des rôles personnalisés et retourner des choses via le 'QVariant' sur les données (...). Comme un identifiant, pour obtenir l'objet ailleurs. – Hayt

+0

Ce que vous dites est correct et je suis d'accord avec vous, mais dans une situation comme une vue masterdetail où la vue détaillée ne fait pas partie du délégué de la vue principale, c'est très difficile à faire. –

+1

c'est un peu difficile à conseiller sans plus de détails. Vous pouvez avoir une carte quelque part avec les notes et un identifiant. Lorsque vous redonnez l'ID comme personnalisé, vous pouvez simplement localiser la note dans la carte par ID. – Hayt

Répondre

2
propriété

Puisque vous avez déjà répondu à votre deuxième question, permettez-moi de prendre le premier, à savoir display.propertyName vs model.propertyName

Fondamentalement, le premier est juste un raccourci pour model.display.propertyName, à savoir le « affichage » du Les données du modèle à l'index donné sont en cours d'accès. Dans votre cas, cela retourne un objet, qui a des propriétés sur son on. Le model.propertyName peut également s'écrire propertyName, ce qui signifie que la méthode data() du modèle est appelée avec "role" étant l'équivalent numérique de "propertyName".

Cette correspondance de "propertyName" à son équivalent numérique est effectuée avec la méthode QAbstractItemModel::roleNames(). Sa mise en œuvre par défaut a quelques mappages de base tels que le mappage "display" à Qt::DisplayRole.

+0

Si je vous comprends bien, model.property est équivalent à model.data (index, roleNames() ["property"]) ?? –

+0

Un peu comme ça, oui. Le nom "property" est mappé en une valeur de rôle entier via le hachage renvoyé par roleNames(). Cette valeur entière est ensuite passé comme deuxième argument à data() –

+0

ok merci pour l'explication, la chose qui me confondait est le modèle dans le délégué qui représente réellement le model.at (index) mais le modèle de trou. –

0

j'ai joué un peu avec le ListView qml essayant de comprendre comment exposer les données currentItem au monde extérieur. C'est ainsi que j'ai réussi à le faire, peut-être que cela sera utile pour les débutants comme moi.

import QtQuick 2.7 
import QtQuick.Controls 2.0 
import QtQuick.Layouts 1.0 

ApplicationWindow { 
    visible: true 
    width: 640 
    height: 480 
    title: qsTr("Hello World") 

    ListModel { 
     id: modell 
     ListElement { 
      fname: "houssem" 
      age: 26 
     } 
     ListElement { 
      fname: "Anna" 
      age: 26 
     } 
     ListElement { 
      fname: "Nicole" 
      age: 26 
     } 
     ListElement { 
      fname: "Adam" 
      age: 27 
     } 
    } 

    ListView { 
     id: lv 
     height: 100 
     width: 200 
     clip: true 
     model: modell 
     property string selectedName: currentItem.name 
     delegate: Component { 
      Item { 
       id: mainItem 
       width: ListView.view.width 
       height: 80 
       property string name: fname 
       Text { 
        text: "name " + fname + " age " + age 
       } 
       MouseArea { 
        anchors.fill: parent 
        onClicked: mainItem.ListView.view.currentIndex = index 
       } 
      } 
     } 
    } 
    Text { 
     anchors.right: parent.right 
     text: lv.selectedName 
    } 
} 

Comme vous pouvez le voir dans le code, pour exposer les données de currentItem que je venais de déclarer des propriétés dans le poste de délégué (propriété de nom de type chaîne dans l'exemple présent) et puis lier une propriété sur ListView (selectedName dans cet exemple) à currentItem.property, de cette façon la propriété sur ListView sera mise à jour automatiquement lorsque je sélectionne d'autres éléments de la liste et j'aurai accès à ces éléments sous forme d'autres éléments de l'interface utilisateur.