Results 1 to 15 of 15

Thread: QAbstractItemModel newbie question

  1. #1
    Join Date
    Dec 2007
    Posts
    6
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Question QAbstractItemModel newbie question

    Dear Qt masters,

    I have the following very simple "model":

    Qt Code:
    1. typedef QPair<QString,QStringList> EnumDefinition;
    2. typedef QList<EnumDefinition> EnumDefinitionList;
    3. EnumDefinitionList enumTypes;
    4.  
    5. // ... example:
    6. enumTypes[0].first = "Boolean";
    7. enumTypes[0].second[0] = "False";
    8. enumTypes[0].second[1] = "True";
    9. enumTypes[1].first = "Color";
    10. enumTypes[1].second[0] = "Red";
    11. enumTypes[1].second[1] = "Green";
    12. enumTypes[1].second[2] = "Blue";
    To copy to clipboard, switch view to plain text mode 

    Now I would like this to display in a tree view as:

    - Boolean
    +-- False
    +-- True
    - Color
    +-- Red
    +-- Green
    +-- Blue

    Can this be done using the QAbstractItemModel?
    (I am a little confused about the mapping between QModelIndex
    and the indexes in my EnumDefinitionList)

    Many thanks,

    Oliver

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QAbstractItemModel newbie question

    The mapping between model indices and values in your case looks this way:

    index( 0, 0, QModelIndex() ) -> Boolean

    index( 0, 0, index( 0, 0, QModelIndex() ) ) -> False
    index( 1, 0, index( 0, 0, QModelIndex() ) ) -> True

    index( 1, 0, QModelIndex() ) -> Color

    index( 0, 0, index( 1, 0, QModelIndex() ) ) -> Red
    index( 1, 0, index( 1, 0, QModelIndex() ) ) -> Green
    index( 2, 0, index( 1, 0, QModelIndex() ) ) -> Blue

    The parameters of index() method are respectively row, column and parent index.

  3. The following user says thank you to jacek for this useful post:

    okellogg (16th December 2007)

  4. #3
    Join Date
    Dec 2007
    Posts
    6
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QAbstractItemModel newbie question

    Thanks Jacek.
    I was trying to put the enumTypes as a member variable in my EnumItemModel
    (AbstractItemModel subtype) but that didn't work out.
    So instead, I use public methods in the EnumItemModel:

    void populateModelFromEnumDefs(EnumDefinitionList l);
    EnumDefinitionList extractEnumDefs();

    that will convert the model info to the external format, EnumDefinitionList.

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,012 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QAbstractItemModel newbie question

    Why not wrap the model directly over the "external format" instead of doing conversions?

  6. #5
    Join Date
    Dec 2007
    Posts
    6
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QAbstractItemModel newbie question

    Maybe I gave up too early - but I can't seem to find why this code is not working:

    Qt Code:
    1. // file: enumitemmodel.h
    2. #ifndef ENUMITEMMODEL_H
    3. #define ENUMITEMMODEL_H
    4.  
    5. #include <QAbstractItemModel>
    6. #include <QModelIndex>
    7. #include <QVariant>
    8. #include <QPair>
    9. #include <QList>
    10. #include <QStringList>
    11.  
    12. typedef QPair<QString,QStringList> EnumDefinition;
    13. typedef QList<EnumDefinition> EnumDefinitionList;
    14.  
    15.  
    16. class EnumItemModel : public QAbstractItemModel
    17. {
    18. Q_OBJECT
    19.  
    20. public:
    21. EnumItemModel(QObject *parent = 0);
    22. virtual ~EnumItemModel();
    23.  
    24. QVariant data(const QModelIndex &index, int role) const;
    25. Qt::ItemFlags flags(const QModelIndex &index) const;
    26. QModelIndex index(int row, int column,
    27. const QModelIndex &parent = QModelIndex()) const;
    28. QModelIndex parent(const QModelIndex &index) const;
    29. int rowCount(const QModelIndex &parent = QModelIndex()) const;
    30. int columnCount(const QModelIndex &parent = QModelIndex()) const;
    31.  
    32. EnumDefinitionList enumTypes;
    33. private:
    34. void setupModelData();
    35. };
    36. #endif
    37.  
    38. // file: enumitemmodel.cpp
    39. #include <QtGui>
    40. #include <iostream>
    41.  
    42. #include "enumitemmodel.h"
    43.  
    44. EnumItemModel::EnumItemModel(QObject *parent)
    45. {
    46. setupModelData();
    47. }
    48.  
    49. EnumItemModel::~EnumItemModel()
    50. {
    51. }
    52.  
    53. int EnumItemModel::columnCount(const QModelIndex &parent) const
    54. {
    55. return 1;
    56. }
    57.  
    58. QVariant EnumItemModel::data(const QModelIndex &index, int role) const
    59. {
    60. if (!index.isValid())
    61. return QVariant();
    62.  
    63. if (role != Qt::DisplayRole)
    64. return QVariant();
    65.  
    66. const QModelIndex &parentIndex = index.parent();
    67.  
    68. if (!parentIndex.isValid())
    69. return QVariant(enumTypes[index.row()].first);
    70.  
    71. int parentRow = parentIndex.row();
    72. return QVariant(enumTypes[parentRow].second[index.row()]);
    73. }
    74.  
    75. Qt::ItemFlags EnumItemModel::flags(const QModelIndex &index) const
    76. {
    77. if (!index.isValid())
    78. return 0;
    79.  
    80. return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    81. }
    82.  
    83. QModelIndex EnumItemModel::index(int row, int column, const QModelIndex &parent)
    84. const
    85. {
    86. if (!hasIndex(row, column, parent))
    87. return QModelIndex();
    88.  
    89. return createIndex(row, column, NULL);
    90. }
    91.  
    92. QModelIndex EnumItemModel::parent(const QModelIndex &index) const
    93. {
    94. if (!index.isValid())
    95. return QModelIndex();
    96.  
    97. return index.parent();
    98. }
    99. int EnumItemModel::rowCount(const QModelIndex &parent) const
    100. {
    101. if (parent.column() > 0)
    102. return 0;
    103.  
    104. if (!parent.isValid())
    105. return 0;
    106.  
    107. return enumTypes[parent.row()].second.count();
    108. }
    109.  
    110. void EnumItemModel::setupModelData()
    111. {
    112. QStringList booleanValues;
    113. booleanValues.append("False");
    114. booleanValues.append("True");
    115. enumTypes.append(EnumDefinition("Boolean", booleanValues));
    116.  
    117. QStringList colorValues;
    118. colorValues.append("Red");
    119. colorValues.append("Green");
    120. colorValues.append("Blue");
    121. enumTypes.append(EnumDefinition("Color", colorValues));
    122. }
    123.  
    124. // file: main.cpp
    125. #include <QtGui>
    126.  
    127. #include "enumitemmodel.h"
    128. int main(int argc, char *argv[])
    129. {
    130. QApplication app(argc, argv);
    131.  
    132. EnumItemModel model;
    133.  
    134. QTreeView view;
    135. view.setModel(&model);
    136. view.setWindowTitle(QObject::tr("Simple Tree Model"));
    137. view.show();
    138. return app.exec();
    139. }
    To copy to clipboard, switch view to plain text mode 

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,012 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QAbstractItemModel newbie question

    I don't have much time now, so only quick remarks:
    • your parent() implementation is invalid - you can't return an index by using QModelIndex::parent() because this method will call the model's parent() method to find the proper parent index
    • rowCount() will take an invalid model index for top level items, thus row() will return -1 and your rowCount() method will break


    Correct these and then we'll continue.

  8. #7
    Join Date
    Dec 2007
    Posts
    6
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QAbstractItemModel newbie question

    Many thanks for replying, wysota.

    > your parent() implementation is invalid - you can't return an index by using
    > ModelIndex:arent() because this method will call the model's parent() method
    > to find the proper parent index

    Okay. The problem then is, how do I get to the parent index when only given the
    child index.
    I resorted to a trick with internalPointer inEnumItemModel::index() :[*] on a top level item, call createIndex() with (void*)0 as the internalPointer[*] on a non toplevel item, call createIndex() with (parent.row() + 1) as the internalPointer

    I would hope that there's a better way to get the parent index but I can't think of one...

    > rowCount() will take an invalid model index for top level items, thus row() will
    > return -1 and your rowCount() method will break

    I'm not sure I understand that comment.
    Here's my modified enumitemmodel.cpp:

    Qt Code:
    1. #include <QtGui>
    2. #include <iostream>
    3.  
    4. #include "enumitemmodel.h"
    5.  
    6. EnumItemModel::EnumItemModel(QObject *parent)
    7. {
    8. setupModelData();
    9. }
    10.  
    11. EnumItemModel::~EnumItemModel()
    12. {
    13. }
    14.  
    15. int EnumItemModel::columnCount(const QModelIndex &parent) const
    16. {
    17. return 1;
    18. }
    19.  
    20. QVariant EnumItemModel::data(const QModelIndex &index, int role) const
    21. {
    22. if (!index.isValid())
    23. return QVariant();
    24.  
    25. if (role != Qt::DisplayRole)
    26. return QVariant();
    27.  
    28. const QModelIndex &parentIndex = index.parent();
    29.  
    30. if (!parentIndex.isValid())
    31. return QVariant(enumTypes[index.row()].first);
    32.  
    33. int parentRow = parentIndex.row();
    34. return QVariant(enumTypes[parentRow].second[index.row()]);
    35. }
    36.  
    37. Qt::ItemFlags EnumItemModel::flags(const QModelIndex &index) const
    38. {
    39. if (!index.isValid())
    40. return 0;
    41.  
    42. return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    43. }
    44.  
    45. QModelIndex EnumItemModel::index(int row, int column, const QModelIndex &parent)
    46. const
    47. {
    48. if (!hasIndex(row, column, parent))
    49. return QModelIndex();
    50.  
    51. if (!parent.isValid())
    52. return createIndex(row, column, NULL);
    53.  
    54. long parentRowPlusOne = (long) parent.row() + 1;
    55. return createIndex(row, column, (void*)parentRowPlusOne);
    56. }
    57.  
    58. QModelIndex EnumItemModel::parent(const QModelIndex &index) const
    59. {
    60. if (!index.isValid())
    61. return QModelIndex();
    62.  
    63. long parentRowPlusOne = (long)index.internalPointer();
    64. if (!parentRowPlusOne) // Top level item
    65. return QModelIndex();
    66.  
    67. return createIndex((int)parentRowPlusOne - 1, 0, NULL);
    68. }
    69.  
    70. int EnumItemModel::rowCount(const QModelIndex &parent) const
    71. {
    72. if (!parent.isValid())
    73. return 0;
    74.  
    75. if (parent.column() > 0)
    76. return 0;
    77.  
    78. //return enumTypes[parent.row()].second.count(); // or perhaps:
    79. long parentRowPlusOne = (long)parent.internalPointer();
    80. if (!parentRowPlusOne)
    81. {
    82. std::cerr << "EnumItemModel::rowCount(row=" << parent.row()
    83. << "): parentRowPlusOne is 0 ?!?" << std::endl;
    84. return 0;
    85. }
    86. return enumTypes[parentRowPlusOne - 1].second.count();
    87. }
    88.  
    89. void EnumItemModel::setupModelData()
    90. {
    91. QStringList booleanValues;
    92. booleanValues.append("False");
    93. booleanValues.append("True");
    94. enumTypes.append(EnumDefinition("Boolean", booleanValues));
    95.  
    96. QStringList colorValues;
    97. colorValues.append("Red");
    98. colorValues.append("Green");
    99. colorValues.append("Blue");
    100. enumTypes.append(EnumDefinition("Color", colorValues));
    101. }
    To copy to clipboard, switch view to plain text mode 

  9. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QAbstractItemModel newbie question

    Quote Originally Posted by okellogg View Post
    > rowCount() will take an invalid model index for top level items, thus row() will
    > return -1 and your rowCount() method will break

    I'm not sure I understand that comment.
    "model.rowCount()" (or more precisely: "model.rowCount( QModelIndex() )" ) should return the number of top-level items and you have two such items ("Boolean" and "Color").

  10. #9
    Join Date
    Dec 2007
    Posts
    6
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QAbstractItemModel newbie question

    Quote Originally Posted by jacek View Post
    "model.rowCount()" (or more precisely: "model.rowCount( QModelIndex() )" ) should return the number of top-level items and you have two such items ("Boolean" and "Color").
    Yippie!
    Qt Code:
    1. int EnumItemModel::rowCount(const QModelIndex &parent) const
    2. {
    3. if (!parent.isValid())
    4. return enumTypes.count();
    5. [...]
    To copy to clipboard, switch view to plain text mode 

    With that change, I now got the top level items displayed:

    - Boolean
    - Color

    And with the following, I got everything displayed:
    Qt Code:
    1. int EnumItemModel::rowCount(const QModelIndex &parent) const
    2. {
    3. if (parent.column() > 0)
    4. return 0;
    5. if (!parent.isValid())
    6. return enumTypes.count();
    7. return enumTypes[parent.row()].second.count();
    8. }
    To copy to clipboard, switch view to plain text mode 

    Last remaining problem: The leaf items ("False", "True", etc.) have a
    "+" symbol and are expandable, and when expanding they show again
    the same leaf items, again with "+" ad infinitum. (I'm sure that's an
    easy one

    Thanks again for your help, jacek and wysota.

  11. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QAbstractItemModel newbie question

    Quote Originally Posted by okellogg View Post
    Last remaining problem: The leaf items ("False", "True", etc.) have a
    "+" symbol and are expandable, and when expanding they show again
    the same leaf items, again with "+" ad infinitum. (I'm sure that's an
    easy one
    Try this: http://labs.trolltech.com/page/Proje...view/Modeltest.

  12. #11
    Join Date
    Dec 2007
    Posts
    6
    Thanks
    1
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: QAbstractItemModel newbie question

    Just for completeness, the rowCount() was still faulty. Here's the corrected version:
    Qt Code:
    1. int EnumItemModel::rowCount(const QModelIndex &parent) const
    2. {
    3. if (parent.column() > 0)
    4. return 0;
    5. if (!parent.isValid()) // return total top level items
    6. return enumTypes.count();
    7. long parentRowPlusOne = (long)parent.internalPointer();
    8. if (!parentRowPlusOne) // type name, e.g. "Color"
    9. return enumTypes[parent.row()].second.count();
    10. // leaf item, e.g. "Red"
    11. return 0;
    12. }
    To copy to clipboard, switch view to plain text mode 

  13. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,012 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QAbstractItemModel newbie question

    Qt Code:
    1. long parentRowPlusOne = (long)index.internalPointer();
    To copy to clipboard, switch view to plain text mode 
    How about QModelIndex::internalId() instead?

    BTW. a trivial rowCount() implementation:
    Qt Code:
    1. int Model::rowCount(const QModelIndex &parent) const {
    2. // if parent is invalid, return number of top level items
    3. if(!parent.isValid())
    4. return enumTypes.count();
    5. // if parent's parent is invalid, this is level one - return components' count
    6. if(!parent.parent().isValid() && hasIndex(parent))
    7. return enumTypes[parent.row()].second.count();
    8. // otherwise at least level 2 - none in our case
    9. return 0;
    10. }
    To copy to clipboard, switch view to plain text mode 

    No need for internal data and you can continue the descent ad infinitum depending on your needs. (for instance root -> QRect -> QPoint -> (int, int))

  14. #13
    Join Date
    Jan 2006
    Location
    Earth (Terra)
    Posts
    87
    Thanks
    4
    Thanked 6 Times in 4 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows Symbian S60

    Default Re: QAbstractItemModel newbie question

    Quote Originally Posted by wysota View Post
    How about QModelIndex::internalId() instead?

    BTW. a trivial rowCount() implementation:
    Qt Code:
    1. int Model::rowCount(const QModelIndex &parent) const {
    2. // if parent is invalid, return number of top level items
    3. if(!parent.isValid())
    4. return enumTypes.count();
    5. // if parent's parent is invalid, this is level one - return components' count
    6. if(!parent.parent().isValid() && hasIndex(parent))
    7. return enumTypes[parent.row()].second.count();
    8. // otherwise at least level 2 - none in our case
    9. return 0;
    10. }
    To copy to clipboard, switch view to plain text mode 

    No need for internal data and you can continue the descent ad infinitum depending on your needs. (for instance root -> QRect -> QPoint -> (int, int))
    Following along, here - very interesting. Can you explain what the 'hasIndex' call does/verifies in this context?

    thanx,
    rickb

  15. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,012 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QAbstractItemModel newbie question

    Whether parent.row() is within the valid range - [0 - rowCount(parent.parent())-1]. Instead you could use (enumTypes.count()>parent.row() && parent.row()>=0).

  16. #15
    Join Date
    Feb 2008
    Posts
    6
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QAbstractItemModel newbie question

    Can you please post the updated code for this problem?

Similar Threads

  1. Question on QAbstractItemModel vs. QTableView
    By lni in forum Qt Programming
    Replies: 1
    Last Post: 26th April 2007, 07:29
  2. Newbie threading question
    By deepayan in forum Qt Programming
    Replies: 17
    Last Post: 16th April 2007, 00:25
  3. Replies: 1
    Last Post: 15th March 2007, 20:45
  4. newbie question about qtextedit fields
    By otortos in forum Qt Programming
    Replies: 1
    Last Post: 23rd February 2006, 18:21

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
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.