Bienvenue sur le forum !

Si vous souhaitez rejoindre la communauté, cliquez sur l'un de ces boutons !

Qt 5 : 5.9.1 - Qt Creator : 4.4.0 - Qt Installer : 2.0.3 - JOM : 1.1.2 - Qt Build suite : 1.7.0 - VS Qt 5 : 2.0.0

Proxy modèle qui ne "refiltre" pas les lignes lorsque le modèle change.

Bonjour,

J'ai un modèle en arbre qui ressemble fortement à l'exemple dans la doc de Qt. Il sert à faire un système de fichiers virtuel (une arborescence de fichiers définie par l'utilisateur, stockée dans une base sqlite).

Lorsque l'utilisateur souhaite supprimer un dossier ou un fichier, il n'est pas supprimé du modèle, mais à la place, les items contiennent un champ "QDateTime deletionDate;" qui quand il est valide, signifie que l'élément a été supprimé.

Comme je ne veux pas afficher les éléments supprimés, Je suis parti sur l'utilisation d'un QSortFilterProxyModel sur lequel j'ai surchargé "filterAcceptsRow" :
bool FilesFilterModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
{
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
if (index.isValid())
{
auto item = static_cast<FilesItem*>(index.internalPointer());
if (item && item->deletedAt().isValid())
{
return false;
}
}
return true;
}
Jusque là, tout ce passe bien. Le problème apparaît lorsque je veux supprimer un élément. Quand je fais un "clic droit > supprimer élément" sur mon QTreeView, je récupère le QModelIndex de l'élément dans le modèle source (et non dans le modèle proxy), met à jour le champ "deletionDate" de l'élément et de ses enfants (si c'est un dossier) puis j'émets "dataChanged".
void LocalFilesModel::remove(const QModelIndex & index)
{
FilesItem * item = static_cast<FilesItem*>(index.internalPointer());
FilesItem * parentItem = item->parent();

int row = index.row();

// beginResetModel();
parentItem->removeChild(row);
// endResetModel();

emit dataChanged(index, index);
}

//////

void FilesItem::removeChild(int index)
{
FilesItem * childItem = childAt(index);

if (childItem->isDir())
{
for (int i = 0;i < childItem->childCount();i++)
{
childItem->removeChild(i);
}
}

QDateTime UTC(QDateTime::currentDateTime().toUTC());
childItem->deletionDate = UTC;
}
Le résultat est que l'élément supprimé ne disparaît pas tant que je ne relance pas l'application ou que j'utilise pas "beginResetModel/endResetModel" (mais dans ce cas, les dossiers ouverts se referment et la sélection est perdue).

Ai-je raté quelque chose ?
merci.

Réponses

  • Hello,

    Émettre dataChanged() depuis le proxy n'a pas l'effet que tu escomptes. Le proxy n'est pas le modèle, il émet lui-même ce signal lorsque le modèle source l'émet (après avoir traité les changements). Il faut l'émettre depuis le modèle lui-même (donc modifier le modèle dans le modèle source, idéalement).


    Il y a aussi une note dans la doc de QSortFilterProxyModel, je ne pense pas que ça s'applique vraiment dans ce cas précis (on est un peu dedans quand même), mais ça pourra peut-être t'éviter des problèmes par la suite ;) :
    Note that you should not update the source model through the proxy model when dynamicSortFilter is true. [...]
    http://doc.qt.io/qt-5/qsortfilterproxymodel.html#dynamicSortFilter-prop
  • 11 May modifié
    oui oui, LocalFilesModel est mon modèle de données (et non le proxy) et c'est bien lui qui émet le signal "dataChanged" (cf code dans le message précédent). Je ne passe par le proxy que pour convertir les QModelIndex.
  • Oops, pas fait assez attention désolé...
    Ton problème n'apparaitrait pas uniquement sur les enfants de l'élément supprimé ?

    Sinon, j'avoue que je ne vois pas trop la subtilité qu'il pourrait y avoir. Si tu as un code exemple minimal qui reproduit le bug, ça aiderait.
  • 12 May modifié
    Et je suppose que QSortFilterProxyModel::dynamicSortFilter est bien à true ?
  • Salut,
    @minirop :
    Il sert à faire un système de fichiers virtuel (une arborescence de fichiers définie par l'utilisateur, stockée dans une base sqlite).
    Je dois faire sensiblement la même chose au boulot, juste pour info, tu es parti d'un QAbstractItemModel ?
    Je me tâtais de faire comme ça ou alors faire une classe qui se baserait sur le code de QFileSystemModel en changeant la source de données.
  • @BBenj: oui, c'est le cas par défaut et je n'y ai pas touché.
    @babaOroms: oui, je suis parti de QAbstractItemModel. je vois pas trop comment changer la source de données du QFileSystemModel vu qu'il se base sur le FS directement (et utilise QFile et tout), donc à moins de coder un driver de FS puis de te monter une "partoche".
Connectez-vous ou Inscrivez-vous pour répondre.