QTreeView mit QIdentityProxyModel
-
Moin,
jetzt mal im deutschen Teil des Forums. da fällt es mir leichter, mich verständlich zu machen.
Die Aufgabe besteht darin, Daten aus einer Datenbank in einem Widget QTreeView darzustellen.
Die Daten werden korrekt aus der Datenbank gelesen und liegen "linear" im BackendModel. Die Klasse BackendModel ist von QSqlTableModel abgeleitet.
Die Verbindung zu QTreeView wird (versucht) mit dem FrontendModel zu erschlagen. FrontendModel ist abgeleitet von QIdentityProxyModel. Wird das FrontendModel erstellt, werden die Daten von der Datenbank in das BackendModel geladen und dann im FrontendModel in eine Baumstruktur über eine Klasse (TreeItem) überführt. Auch das funktioniert korrekt.
Und dann hapert es. Ich blick's nicht. Einiges scheint im Hintergrund zu laufen bzw. ich sehe und verstehe damit die Zusammenhänge nicht. Kann auch sein, dass alles ganz einfach ist. Ich bin gesundheitlich, d.h. kognitiv angeschlagen und manchmal fällt es mir schwer, komplexere Zusammenhänge zu durchschauen. Aber mal Schritt für Schritt:
Baumstruktur:
#include <QObject> #include "ProjectsViewEntity.h" class ProjectsViewTreeItem : public QObject { Q_OBJECT public: explicit ProjectsViewTreeItem(int backendrow, QObject *parent = nullptr); // ReSharper disable once CppHidingFunction [[nodiscard]] ProjectsViewTreeItem *parent() const { return dynamic_cast<ProjectsViewTreeItem *>(QObject::parent()); } [[nodiscard]] int backendRow() const { return m_backendrow; } [[nodiscard]] int frontendRow() const { return m_frontendrow; } private: int m_backendrow; int m_frontendrow; };
ProjectsViewTreeItem::ProjectsViewTreeItem(int backendrow, QObject *parent): QObject(parent) { m_backendrow = backendrow; m_frontendrow = [parent]() { if (parent != nullptr) { return static_cast<int>(parent->children().size()); } return 0; }(); auto txt = QString("backendrow:%1 frontendrow:%2").arg(m_backendrow).arg(m_frontendrow); qDebug() << txt; setObjectName(txt); }
Die Klasse ist von QObject abgeleitet weil diese schon eine fertige Struktur für die Behandlung von Kindobjekten enthält und ich das nicht mehr selbst dann basteln muss. In dieser Klasse merke ich mir die Zeilennummer des entsprechenden Eintrages im Backend und auch die im Frontend. Beides lege ich noch im Objektnamen ab, damit ich später danach suchen kann.
Frontend
class ProjectsFrontendModel : public QIdentityProxyModel { Q_OBJECT public: ProjectsFrontendModel(); ~ProjectsFrontendModel() override; [[nodiscard]] QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override; [[nodiscard]] QModelIndex mapToSource(const QModelIndex &proxyIndex) const override; [[nodiscard]] QModelIndex parent(const QModelIndex &childIndex) const override; [[nodiscard]] QModelIndex index(int row, int column, const QModelIndex &parentIndex) const override; [[nodiscard]] int rowCount(const QModelIndex &parentIndex) const override; [[nodiscard]] int columnCount(const QModelIndex &parentIndex) const override; void setSourceModel(QAbstractItemModel *sourceModel) override; private: ProjectsViewTreeItem *m_root = nullptr; QVariant getParentIdFromBackend(int row); [[nodiscard]] ProjectsViewTreeItem *getRootFromBackend(int projectId); void findChildsFromBackend(ProjectsViewTreeItem *item); [[nodiscard]] ProjectsBackendModel *backendModel() const { return dynamic_cast<ProjectsBackendModel *>(sourceModel()); } };
Bevor QTableView gerendert wird, wird ja schon einiges erledigt. Folge ich dem Debugger, dann wird es ab der Stelle hier interessant.
... 2024-10-29 16:19:39.552 [debug] JHXManager::unknown : Projects::ProjectsViewTreeItem::backendrow:0 frontendrow:0 2024-10-29 16:19:39.552 [debug] JHXManager::unknown : Projects::ProjectsViewTreeItem::backendrow:1 frontendrow:1 2024-10-29 16:19:39.552 [debug] JHXManager::unknown : Projects::ProjectsViewTreeItem::backendrow:3 frontendrow:1 2024-10-29 16:19:39.552 [debug] JHXManager::unknown : Projects::ProjectsViewTreeItem::backendrow:2 frontendrow:2 2024-10-29 16:19:39.552 [debug] JHXManager::unknown : Projects::ProjectsViewTreeItem::backendrow:4 frontendrow:1 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50)) ...
Nach dem Erzeugen der Baumstruktur mache ich einen dump
void ProjectsFrontendModel::setSourceModel(QAbstractItemModel *sourceModel) { QIdentityProxyModel::setSourceModel(sourceModel); backendModel()->select(); m_root = getRootFromBackend(1); findChildsFromBackend(m_root); m_root->dumpObjectTree(); }
Dieser Zeigt, alles ist OK und dann ruft das FrontendModel als erstes
mapToSource
mit einem ungültigen Modelindex auf (s.o. im Log).QModelIndex ProjectsFrontendModel::mapToSource(const QModelIndex &proxyIndex) const { #if defined(_LOCALDEBUG_) qDebug() << "proxyindex: " << proxyIndex; #endif ProjectsViewTreeItem *proxyItem = proxyIndex.isValid() ? static_cast<ProjectsViewTreeItem *>(proxyIndex.internalPointer()) : m_root; auto column = proxyIndex.column() >= 0 ? proxyIndex.column() : 0; auto ret = createIndex(proxyItem->backendRow(), column, proxyItem); qDebug() << ret; return ret; }
Soweit ich verstanden habe, ruft das ProxyModel damit nach dem Root-Eintrag. Daher bilde ich das entsprechend ab. Das habe ich mir aus dem Qt-Beispiel Simple Tree Model Example abgeschaut
Danach geht es nicht weiter. Zig-mal wird
mapToSource
aufgerufen und es passiert sichtbar nichts mehr.2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50)) 2024-10-29 16:19:39.552 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.553 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50)) 2024-10-29 16:19:39.553 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.553 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50)) 2024-10-29 16:19:39.556 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : proxyindex: QModelIndex(-1,-1,0x0,QObject(0x0)) 2024-10-29 16:19:39.556 [debug] JHXManager::Projects::ProjectsFrontendModel::mapToSource : QModelIndex(0,0,0x27d76ef0,Projects::ProjectsFrontendModel(0x27e03e50))
Das war jetzt viel Geschreibsel. Aber vlt hilfts, mir zu zeigen, was da falsch ist. Andere Routinen im FrontendModel werden anscheinend bis dahin nicht aufgerufen.
rowCount
hätte ich evtl. erwartet. Das erscheint im Log aber nicht.Ich habe jetzt alles ausprobiert, was mir eingefallen war. Aber es brachte mich nicht weiter.
Ein ProxyModel hatte ich schon mal verwendet, allerdings mit QTableView. Da klappt alles.