Results 1 to 6 of 6

Thread: Problem inserting child items into a QAbstractItemModel

  1. #1
    Join Date
    Aug 2006
    Posts
    163
    Thanks
    12
    Thanked 5 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Problem inserting child items into a QAbstractItemModel

    This one is a bit complex, for me at least

    I have a QAbstractItemModel. This is because a large amount of items are added at one go, and using a normal QTreeWidget is horribly slow.
    The model uses a self-made ModelItem that is more or less copied from the Qt documentation for each row in it. This works fine. When I want to add children to the existing rows however, something goes horribly wrong.

    What I'm doing is displaying newsgroup posts in a threaded view, ie. replies to posts show up under that parent rows in the QTreeView and can be expanded with a "+". Using qDebug() I can see that my code does exactly as expected...except that Qt somehow messes up what it displays in the QTreeView. I suspect that this is because the internal index of the children I am adding is being set wrong, but I can't tell what is going wrong. If anyone can help with this I'd be very grateful, I've been staring at this for the last hour trying everything I can think of, but my understanding of how to implement this just isn't on par with what I'm trying to do

    The code of interest is in the constructor of the QAbstractItemModel. Basically what happens is that none of the children actually show up. What is shown in their place are multiple instances of more-or-less random various parent rows.

    Qt Code:
    1. /***************************************************************************
    2. * Copyright (C) 2006 by Lawrence Lee *
    3. * valheru@facticius.net *
    4. * *
    5. * This program is free software; you can redistribute it and/or modify *
    6. * it under the terms of the GNU General Public License as published by *
    7. * the Free Software Foundation; either version 2 of the License, or *
    8. * (at your option) any later version. *
    9. * *
    10. * This program is distributed in the hope that it will be useful, *
    11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
    12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
    13. * GNU General Public License for more details. *
    14. * *
    15. * You should have received a copy of the GNU General Public License *
    16. * along with this program; if not, write to the *
    17. * Free Software Foundation, Inc., *
    18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
    19. ***************************************************************************/
    20. #include "modelItem.h"
    21. #include "articleModel.h"
    22. #include <QtCore/QDebug>
    23. #include <QtCore/QStringList>
    24.  
    25. ArticleModel::ArticleModel( const QStringList &data, QObject *parent ) : QAbstractItemModel( parent )
    26. {
    27. QList<QString> rootData;
    28. rootData << "From" << "Subject" << "Date" << "Message-ID" << "References" << "Lines";
    29. rootItem = new ModelItem( rootData );
    30. for ( int i = 0; i < data.count(); i += 6 ){
    31. if( data[ i + 4 ] == "" || data[ i + 4 ].isEmpty() ){
    32. ///It has no reference, so we simply add it to the root of the model
    33. ModelItem *item = new ModelItem( QStringList() << data[ i ] << data[ i + 1 ]
    34. << data[ i + 2 ] << data[ i + 3 ]
    35. << data[ i + 4 ] << data[ i + 5 ], rootItem );
    36. rootItem->appendChild( item );
    37. ///Remove it from the list
    38. // for( int x = i; x < i + 6; ++x ){
    39. // const_cast< QStringList& >( data ).removeAt( x );
    40. // }
    41. }
    42. }
    43. int maxReferences = 0;
    44. for ( int i = 0; i < data.count(); i += 6 ){
    45. if( !data[ i + 4 ].isEmpty() ){
    46. QStringList references = data[ 4 ].split( " ", QString::SkipEmptyParts );
    47. if( references.count() > maxReferences ){
    48. maxReferences = references.count();
    49. }
    50. }
    51. }
    52. int iteration = 1;
    53. while( iteration <= maxReferences ){
    54. for( int i = 0; i < data.count(); i += 6 ){
    55. if( !data[ i + 4 ].isEmpty() ){
    56. QStringList references = data[ i + 4 ].split( " ", QString::SkipEmptyParts );
    57. if( references.count() == iteration ){
    58. for( int p = 0; p < rowCount(); ++p ){
    59. if( references[ 0 ] == rootItem->child( p )->data( 3 ).toString() ){
    60. ModelItem *item = new ModelItem( QStringList() << data[ i ] << data[ i + 1 ]
    61. << data[ i + 2 ] << data[ i + 3 ]
    62. << data[ i + 4 ] << data[ i + 5 ], rootItem );
    63. rootItem->child( p )->appendChild( item );
    64. for( int t = 0; t < item->columnCount(); ++t ){
    65. qDebug() << item->data( t ).toString();
    66. }
    67. qDebug() << data[ i + 1 ] << "is the child of" << rootItem->child( p )->data( 1 ).toString();
    68. qDebug() << "because reference" << references[ 0 ] << "in child refers to parents Message-ID"
    69. << rootItem->child( p )->data( 3 ).toString() << "\r\n";
    70. }
    71. }
    72. }
    73. }
    74. }
    75. ++iteration;
    76. }
    77. }
    78.  
    79. ArticleModel::~ArticleModel()
    80. {
    81. delete rootItem;
    82. }
    83.  
    84. QModelIndex ArticleModel::index( int row, int column, const QModelIndex &parent ) const
    85. {
    86. ModelItem * parentItem;
    87.  
    88. if ( !parent.isValid() )
    89. parentItem = rootItem;
    90. else
    91. parentItem = static_cast<ModelItem*>( parent.internalPointer() );
    92.  
    93. ModelItem *childItem = parentItem->child( row );
    94. if ( childItem )
    95. return createIndex( row, column, childItem );
    96. else
    97. return QModelIndex();
    98. }
    99.  
    100. QModelIndex ArticleModel::parent( const QModelIndex &index ) const
    101. {
    102. if ( !index.isValid() )
    103. return QModelIndex();
    104.  
    105. ModelItem *childItem = static_cast<ModelItem*>( index.internalPointer() );
    106. ModelItem *parentItem = childItem->parent();
    107.  
    108. if ( parentItem == rootItem )
    109. return QModelIndex();
    110.  
    111. return createIndex( parentItem->row(), 0, parentItem );
    112. }
    113.  
    114. int ArticleModel::rowCount( const QModelIndex &parent ) const
    115. {
    116. ModelItem * parentItem;
    117.  
    118. if ( !parent.isValid() )
    119. parentItem = rootItem;
    120. else
    121. parentItem = static_cast<ModelItem*>( parent.internalPointer() );
    122.  
    123. return parentItem->childCount();
    124. }
    125.  
    126. int ArticleModel::columnCount( const QModelIndex &parent ) const
    127. {
    128. if ( parent.isValid() )
    129. return static_cast<ModelItem*>( parent.internalPointer() ) ->columnCount();
    130. else
    131. return rootItem->columnCount();
    132. }
    133.  
    134. QVariant ArticleModel::data( const QModelIndex &index, int role ) const
    135. {
    136. if ( !index.isValid() )
    137. return QVariant();
    138.  
    139. if ( role != Qt::DisplayRole )
    140. return QVariant();
    141.  
    142. ModelItem *item = static_cast<ModelItem*>( index.internalPointer() );
    143.  
    144. return item->data( index.column() );
    145. }
    146.  
    147. Qt::ItemFlags ArticleModel::flags( const QModelIndex &index ) const
    148. {
    149. if ( !index.isValid() )
    150. return Qt::ItemIsEnabled;
    151.  
    152. return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    153. }
    154.  
    155. QVariant ArticleModel::headerData( int section, Qt::Orientation orientation, int role ) const
    156. {
    157. if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
    158. return rootItem->data( section );
    159.  
    160. return QVariant();
    161. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. /***************************************************************************
    2. * Copyright (C) 2006 by Lawrence Lee *
    3. * valheru@facticius.net *
    4. * *
    5. * This program is free software; you can redistribute it and/or modify *
    6. * it under the terms of the GNU General Public License as published by *
    7. * the Free Software Foundation; either version 2 of the License, or *
    8. * (at your option) any later version. *
    9. * *
    10. * This program is distributed in the hope that it will be useful, *
    11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
    12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
    13. * GNU General Public License for more details. *
    14. * *
    15. * You should have received a copy of the GNU General Public License *
    16. * along with this program; if not, write to the *
    17. * Free Software Foundation, Inc., *
    18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
    19. ***************************************************************************/
    20. #include "modelItem.h"
    21.  
    22. ModelItem::ModelItem( const QList<QString> &data, ModelItem* parent )
    23. {
    24. parentItem = parent;
    25. itemData = data;
    26. }
    27.  
    28. ModelItem::~ ModelItem()
    29. {
    30. qDeleteAll( childItems );
    31. }
    32.  
    33. void ModelItem::appendChild( ModelItem *item )
    34. {
    35. childItems.append( item );
    36. }
    37.  
    38. ModelItem *ModelItem::child( int row )
    39. {
    40. return childItems.value( row );
    41. }
    42.  
    43. int ModelItem::childCount() const
    44. {
    45. return childItems.count();
    46. }
    47.  
    48. int ModelItem::row() const
    49. {
    50. if ( parentItem != 0 ) {
    51. return parentItem->childItems.indexOf( const_cast<ModelItem*>( this ) );
    52. }
    53. return 0;
    54. }
    55.  
    56. int ModelItem::columnCount() const
    57. {
    58. return itemData.count();
    59. }
    60.  
    61. QVariant ModelItem::data( int column ) const
    62. {
    63. return itemData.value( column );
    64. }
    65.  
    66. ModelItem *ModelItem::parent()
    67. {
    68. return parentItem;
    69. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by Valheru; 13th October 2006 at 16:31.

  2. #2
    Join Date
    Aug 2006
    Posts
    163
    Thanks
    12
    Thanked 5 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Problem inserting child items into a QAbstractItemModel

    Ok, that's just plain weird. I just changed the code that controls the info that is passed the the child item when it is constructed, like so :

    Qt Code:
    1. ModelItem *item = new ModelItem( QStringList() << QString::number( i ) << QString::number( i + 1)
    2. << QString::number( i + 2 ) << QString::number( i + 3 )
    3. << QString::number( i + 4 ) << QString::number( i + 5) );
    4. rootItem->child( p )->appendChild( item );
    To copy to clipboard, switch view to plain text mode 
    It runs fine, but the moment I click on a "+" to expand an entry, the program segfaults. GDB point to line 50 of modelItem.cpp ( the custom model item class ) as the cause of the segfault :

    Qt Code:
    1. int ModelItem::row() const
    2. {
    3. if ( parentItem != 0 ) { ///<--- This is where it segfaults according to GDB
    4. return parentItem->childItems.indexOf( const_cast<ModelItem*>( this ) );
    5. }
    6. return 0;
    7. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. Program received signal SIGSEGV, Segmentation fault.
    2. [Switching to Thread -1217018192 (LWP 13634)]
    3. 0x08078c3d in ModelItem::row (this=0x0) at modelItem.cpp:50
    4. 50 if ( parentItem != 0 ) {
    5. (gdb) bt
    6. #0 0x08078c3d in ModelItem::row (this=0x0) at modelItem.cpp:50
    7. #1 0x080769d5 in ArticleModel::parent (this=0x8143a50, index=@0x81cd660) at articleModel.cpp:114
    8. #2 0xb7e75646 in QTreeView::indexRowSizeHint () from /opt/qt4/lib/libQtGui.so.4
    9. #3 0xb7e75a47 in QTreeView::indexRowSizeHint () from /opt/qt4/lib/libQtGui.so.4
    10. #4 0xb7e787c6 in QTreeView::drawTree () from /opt/qt4/lib/libQtGui.so.4
    11. #5 0xb7e7abcc in QTreeView::paintEvent () from /opt/qt4/lib/libQtGui.so.4
    12. #6 0xb7b3b90e in QWidget::event () from /opt/qt4/lib/libQtGui.so.4
    13. #7 0xb7d8e914 in QFrame::event () from /opt/qt4/lib/libQtGui.so.4
    14. #8 0xb7df729c in QAbstractScrollArea::viewportEvent () from /opt/qt4/lib/libQtGui.so.4
    15. #9 0xb7e4a092 in QAbstractItemView::viewportEvent () from /opt/qt4/lib/libQtGui.so.4
    16. #10 0xb7df8785 in QAbstractScrollArea::setViewport () from /opt/qt4/lib/libQtGui.so.4
    17. #11 0xb7af9561 in QApplicationPrivate::notify_helper () from /opt/qt4/lib/libQtGui.so.4
    18. #12 0xb7aff167 in QApplication::notify () from /opt/qt4/lib/libQtGui.so.4
    19. #13 0xb7b4356e in QApplicationPrivate::createEventDispatcher () from /opt/qt4/lib/libQtGui.so.4
    20. #14 0xb7c159b1 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    21. #15 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    22. #16 0xb7c1529d in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    23. #17 0xb7c1529d in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    24. #18 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    25. #19 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    26. #20 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    27. #21 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    28. #22 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    29. #23 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    30. #24 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    31. #25 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    32. #26 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    33. #27 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    34. #28 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    35. #29 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    36. #30 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    37. #31 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    38. #32 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    39. #33 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    40. #34 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    41. #35 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    42. #36 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    43. #37 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    44. #38 0xb7c1529d in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    45. #39 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    46. #40 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    47. #41 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    48. #42 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    49. #43 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    50. #44 0xb7c153df in QWidget::update () from /opt/qt4/lib/libQtGui.so.4
    51. #45 0xb7c155e7 in QWidgetPrivate::drawWidget () from /opt/qt4/lib/libQtGui.so.4
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Aug 2006
    Posts
    163
    Thanks
    12
    Thanked 5 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Problem inserting child items into a QAbstractItemModel

    Just noticed something else : when selecting an root-level item, all other instances of that item which have been erroniously added as children to other root-items also become selected. This is definitely a problem then that some sort of index is not being set for the children items, and the modelview is becoming confused and assigning parent items to as children when the view asks for them to render. What index and how to set it remains the problem, however. I would guess that the internal pointer is not being maintained for them, but I don't know if I'm right.

    /edit : clicking on one of the children does not select the child, instead it selects the root-item(s) with the same data as that child item. This is driving me nuts.

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

    Default Re: Problem inserting child items into a QAbstractItemModel

    Why don't you just use QStandardItemModel as your model? From what I've seen you are simply keeping strings in your model. The standard model can do that for you as well...

    Qt Code:
    1. QStandardItemModel model(0, 6);
    2. model.insertRows(model.rowCount(), 1, QModelIndex()); // adds an item at level "0"
    3. QModelIndex ind = model.index(model.rowCount()-1, 0);
    4. model.setData(ind, "From field data", Qt::DisplayRole);
    5. model.insertRows(0, 1, ind); // adds a child to the previous item
    6. model.insertColumns(0, 4, ind); // adds a child to the previous item
    7. QModelIndex chldind = model.index(0, 0, ind);
    8. model.setData(chldind, "From field data in child item", Qt::DisplayRole);
    To copy to clipboard, switch view to plain text mode 

    and so on...

    As for your code I guess you have something in the parent-child traversal/relationship messed up. I'd suggest using the standard model if you can (and I think you can) - there is no need reinventing the wheel.

  5. #5
    Join Date
    Aug 2006
    Posts
    163
    Thanks
    12
    Thanked 5 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Problem inserting child items into a QAbstractItemModel

    I think I may have found the problem already. It lies with creating the index before appending it to a child. If you look at the Simple Tree Model then you see that they buffer the data into a QList< QVariant > before creating the child :

    Qt Code:
    1. rootItem->addChild( new ItemModel( QList< QVariant >, rootItem )
    To copy to clipboard, switch view to plain text mode 
    I think that that was the whole problem, by creating the item beforehand it messes up the unique index that the model gives the item.

    Wysota, I would use the QStandardItemModel, but the calls of setData bring a large amount of overhead. Some newsgroups, such as alt.binaries.boneless, have an obscene amount of articles in them. If you were to list it ( the download if the headers takes about 30 minutes on my 20 MBit connection, although that depends on how stressed the server is ) I think it would take an inordinate amount of time to add them to the view.

    /edit : I feel so stupid. Really. The problem was, as it normally is, a really dumb mistake. On line 63 of the ArticleModel.cpp I was passing the header of the TreeView as the parent, while it should have been
    Qt Code:
    1. rootItem->child( p )
    To copy to clipboard, switch view to plain text mode 
    Now everything is working fine. And to think I spend about 6 hours on this >
    Last edited by Valheru; 14th October 2006 at 11:03.

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

    Default Re: Problem inserting child items into a QAbstractItemModel

    Quote Originally Posted by Valheru View Post
    Wysota, I would use the QStandardItemModel, but the calls of setData bring a large amount of overhead. Some newsgroups, such as alt.binaries.boneless, have an obscene amount of articles in them. If you were to list it ( the download if the headers takes about 30 minutes on my 20 MBit connection, although that depends on how stressed the server is ) I think it would take an inordinate amount of time to add them to the view.
    Who says you have to add headers all at the time with single calls to insertRows/setData? You can subclass the model and provide your own methods for adding items.

Similar Threads

  1. Problem inserting in QTableWidget
    By DPinLV in forum Qt Programming
    Replies: 2
    Last Post: 2nd August 2006, 00:10
  2. Problem with inserting text into QTextEdit
    By xorrr in forum Qt Programming
    Replies: 0
    Last Post: 6th February 2006, 11:45

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.