+ Reply to Thread
Results 1 to 2 of 2

Thread: Viewing QSqlTableModel in QTreeView through a proxy model

  1. #1
    Join Date
    Nov 2017
    Posts
    3
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Viewing QSqlTableModel in QTreeView through a proxy model

    I'm trying to use a proxy model to take a 'parentId' column in a QSqlTableModel (using SQLITE) and view the hierarchy with a QTreeView. To make this work without needed a treeItem-type class I'm using internalId() from QModelIndex to store the 'parentId'. It works 99% of the time and I can't nail down where I'm messing up. I can view the parents/children and even expand/collapse them but I cannot select the children of a parent item. The selectionModel's selectionChanged() signal and the proxy models index() return the expected QModelIndex and so I don't know what is making the view upset. Here is the code that produces the issue. Thanks for any insight or suggestions

    mainwindow.h
    Qt Code:
    1. #ifndef MAINWINDOW_H
    2. #define MAINWINDOW_H
    3.  
    4. #include <QMainWindow>
    5. #include <QSqlError>
    6.  
    7. class QTreeView;
    8. class sqlTreeModelTest;
    9.  
    10. class MainWindow : public QMainWindow
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. explicit MainWindow(QWidget *parent = 0);
    16. QSqlError initdb();
    17. private:
    18. QTreeView *treeView;
    19. void setupModel();
    20. };
    21.  
    22. #endif // MAINWINDOW_H
    To copy to clipboard, switch view to plain text mode 

    mainwindow.cpp
    Qt Code:
    1. #include "mainwindow.h"
    2. #include "sqltreemodeltest.h"
    3. #include "proxytreemodeltest.h"
    4.  
    5. #include <QTreeView>
    6. #include <QVBoxLayout>
    7. #include <QSqlQuery>
    8.  
    9. MainWindow::MainWindow(QWidget *parent) :
    10. QMainWindow(parent)
    11. {
    12. QWidget *centralWidget = new QWidget(this);
    13. QVBoxLayout *verticalLayout = new QVBoxLayout(centralWidget);
    14. treeView = new QTreeView(centralWidget);
    15. verticalLayout->addWidget(treeView);
    16. setCentralWidget(centralWidget);
    17.  
    18. QSqlError error = initdb();
    19. if(error.isValid())
    20. qDebug() << error.text();
    21. setupModel();
    22. }
    23.  
    24. QSqlError MainWindow::initdb() {
    25.  
    26. QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    27.  
    28. db.setDatabaseName(":memory:");
    29. if(!db.open())
    30. return db.lastError();
    31.  
    32. QStringList tables = db.tables();
    33. if(tables.contains("test", Qt::CaseInsensitive))
    34. if(!q.exec("DROP TABLE test"))
    35. return q.lastError();
    36.  
    37. if(!q.exec(QLatin1String("CREATE TABLE test(id INTEGER PRIMARY KEY, title VARCHAR, type INTEGER, parentId INTEGER DEFAULT 0)")))
    38. return q.lastError();
    39. if(!q.exec(QLatin1String("INSERT INTO test (title, type, parentId)"
    40. "VALUES ('row0', 0, 0),"
    41. "('row0a', 0, 1)")))
    42. return q.lastError();
    43. return QSqlError();
    44. }
    45.  
    46. void MainWindow::setupModel() {
    47.  
    48. sqlTreeModelTest *testModel = new sqlTreeModelTest(this);
    49. testModel->setTable("test");
    50. testModel->select();
    51.  
    52. proxyTreeModelTest *treeProxy = new proxyTreeModelTest(this);
    53. treeProxy->setSourceModel(testModel);
    54.  
    55. treeView->setModel(treeProxy);
    56. treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
    57. treeView->setSelectionMode(QAbstractItemView::SingleSelection);
    58. }
    To copy to clipboard, switch view to plain text mode 

    sqltreemodeltest.h
    Qt Code:
    1. #ifndef SQLTREEMODELTEST_H
    2. #define SQLTREEMODELTEST_H
    3.  
    4. #include <QSqlTableModel>
    5.  
    6. class sqlTreeModelTest : public QSqlTableModel
    7. {
    8. Q_OBJECT
    9.  
    10. public:
    11. sqlTreeModelTest(QObject *parent=0);
    12. virtual Qt::ItemFlags flags(const QModelIndex &index) const;
    13. };
    14.  
    15. #endif // SQLTREEMODELTEST_H
    To copy to clipboard, switch view to plain text mode 

    sqltreemodeltest.cpp
    Qt Code:
    1. #include "sqltreemodeltest.h"
    2.  
    3. sqlTreeModelTest::sqlTreeModelTest(QObject *parent) : QSqlTableModel(parent) {}
    4.  
    5. Qt::ItemFlags sqlTreeModelTest::flags(const QModelIndex &index) const {
    6. //QSqlTableModel doesn't allow children so use these flags
    7. if(index.isValid())
    8. return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    9. else
    10. return 0;
    11. }
    To copy to clipboard, switch view to plain text mode 

    proxytreemodeltest.h
    Qt Code:
    1. #ifndef PROXYTREEMODELTEST_H
    2. #define PROXYTREEMODELTEST_H
    3.  
    4. #include <QDebug>
    5. #include <QAbstractProxyModel>
    6.  
    7. class QSqlQuery;
    8.  
    9. class proxyTreeModelTest : public QAbstractProxyModel
    10. {
    11. Q_OBJECT
    12.  
    13. public:
    14. proxyTreeModelTest(QObject *parent=0);
    15. virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
    16. virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
    17. virtual QModelIndex parent(const QModelIndex &child) const;
    18.  
    19. virtual QModelIndex index(int row, int column, const QModelIndex &parent) const;
    20. virtual int rowCount(const QModelIndex &parent) const;
    21. virtual int columnCount(const QModelIndex &parent) const { return sourceModel()->columnCount(parent); }
    22.  
    23. virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const { return sourceModel()->headerData(section,orientation,role); }
    24. virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { return sourceModel()->setHeaderData(section,orientation,value,role); }
    25.  
    26. virtual bool hasChildren(const QModelIndex &parent) const;
    27.  
    28. private:
    29.  
    30. int getParentId(int childId) const;
    31. QSqlQuery* getChildren(int parentId) const;
    32. };
    33.  
    34. #endif // PROXYTREEMODELTEST_H
    To copy to clipboard, switch view to plain text mode 

    proxytreemodeltest.cpp
    Qt Code:
    1. #include "proxytreemodeltest.h"
    2.  
    3. #include <QSqlQuery>
    4. #include <QSqlTableModel>
    5. #include <QSqlError>
    6.  
    7. #include <QDebug>
    8.  
    9. proxyTreeModelTest::proxyTreeModelTest(QObject *parent) : QAbstractProxyModel(parent) {}
    10.  
    11. QModelIndex proxyTreeModelTest::mapFromSource(const QModelIndex &sourceIndex) const {
    12. if(!sourceIndex.isValid())
    13. return QModelIndex();
    14.  
    15. int id = (sourceIndex.column() == 0) ? sourceIndex.data().toInt() : sourceIndex.sibling(sourceIndex.row(),0).data().toInt();
    16.  
    17. int row = -1;
    18. QSqlQuery* q = getChildren(getParentId(id));
    19. while(q->next()) {
    20. row++;
    21. if(q->value(0).toInt() == id)
    22. break;
    23. }
    24. delete q;
    25. return createIndex(row, sourceIndex.column(), id);
    26. }
    27.  
    28. QModelIndex proxyTreeModelTest::mapToSource(const QModelIndex &proxyIndex) const {
    29. if(!proxyIndex.isValid())
    30. return QModelIndex();
    31.  
    32. int id = proxyIndex.internalId();
    33.  
    34. q.exec("SELECT id FROM test");
    35. int row = -1;
    36. while(q.next()) {
    37. row++;
    38. if(q.value(0).toInt() == id)
    39. break;
    40. }
    41. return sourceModel()->index(row, proxyIndex.column());
    42. }
    43.  
    44. bool proxyTreeModelTest::hasChildren(const QModelIndex &parent) const {
    45.  
    46. q.prepare("SELECT COUNT(*) FROM test WHERE parentId=?");
    47. q.addBindValue(parent.internalId());
    48. q.exec();
    49. q.first();
    50. return q.value(0).toInt() > 0;
    51. }
    52.  
    53. QModelIndex proxyTreeModelTest::parent(const QModelIndex &childIndex) const {
    54.  
    55. int childId = childIndex.internalId();
    56. int parentId = getParentId(childId);
    57. if(parentId == 0)
    58. return QModelIndex();
    59.  
    60. int parentRow = -1;
    61. QSqlQuery* q = getChildren(getParentId(parentId));
    62. while(q->next()) {
    63. parentRow++;
    64. if(q->value(0).toInt() == parentId)
    65. break;
    66. }
    67. delete q;
    68. return createIndex(parentRow, childIndex.row(), parentId);
    69. }
    70.  
    71. QModelIndex proxyTreeModelTest::index(int row, int column, const QModelIndex &parent) const {
    72.  
    73. if(row < 0 || column < 0)
    74. return QModelIndex();
    75.  
    76. QSqlQuery* q = getChildren(parent.internalId());
    77. q->seek(row);
    78. int id = q->value(0).toInt();
    79. delete q;
    80. return createIndex(row, column, id);
    81. }
    82.  
    83. int proxyTreeModelTest::rowCount(const QModelIndex &parent) const {
    84.  
    85. QSqlQuery* q = getChildren(parent.internalId());
    86.  
    87. //use last() and at() since SQLite does not support query size calls
    88. q->last();
    89. int size = q->at() + 1;
    90. delete q;
    91. return size;
    92. }
    93.  
    94. int proxyTreeModelTest::getParentId(int childId) const {
    95. q.prepare("SELECT parentId FROM test WHERE id=?");
    96. q.addBindValue(childId);
    97. q.exec();
    98. q.first();
    99. return q.value(0).toInt();
    100. }
    101.  
    102. QSqlQuery* proxyTreeModelTest::getChildren(int parentId) const {
    103. QSqlQuery* q = new QSqlQuery;
    104. q->prepare("SELECT id FROM test WHERE parentId=?");
    105. q->addBindValue(parentId);
    106. q->exec();
    107. return q;
    108. }
    To copy to clipboard, switch view to plain text mode 

    main.cpp
    Qt Code:
    1. #include "mainwindow.h"
    2. #include <QApplication>
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication a(argc, argv);
    7. MainWindow w;
    8. w.show();
    9.  
    10. return a.exec();
    11. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Mar 2018
    Posts
    1
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Viewing QSqlTableModel in QTreeView through a proxy model

    In sqltreemodeltest.cpp.

    return Qt::ItemIsEnabled | Qt::ItemIsSelectable|Qt::ItemIsEditable;

    You need add a flag Qt::ItemIsEditable;


    Added after 19 minutes:


    Oh, sorry, I misunderstand the question.
    Last edited by LinJH; 14th March 2018 at 22:22.

+ Reply to Thread

Similar Threads

  1. How to use proxy model?
    By gurmeet in forum Qt Programming
    Replies: 3
    Last Post: 18th March 2015, 08:18
  2. Replies: 24
    Last Post: 18th September 2013, 06:35
  3. Replies: 1
    Last Post: 29th August 2013, 05:41
  4. Source Model Ad Proxy Model
    By sajis997 in forum Qt Programming
    Replies: 1
    Last Post: 19th July 2011, 05:13
  5. Custom Model and Proxy Model
    By frank100 in forum Qt Programming
    Replies: 1
    Last Post: 20th December 2010, 14:30

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts