Results 1 to 20 of 20

Thread: Help with getting my custom model working

  1. #1
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Help with getting my custom model working

    Greetings,

    I've been reading over Qt's model/view stuff overt the last week and have been looking at examples and such. I've been trying to get my custom model up and running. The problem I have is that I'm not sure how to set the data. The class expects the data to come in as a QVariant. Well, how would I send it data if the data consisted of a struct?

    So If I had part of the model defined like this:
    Qt Code:
    1. class ConnectionListModel public QAbstractTableModel{
    2. //...
    3. private:
    4. struct connectionData {
    5. QString name;
    6. QString hostAddress;
    7. QString username;
    8. QString password;
    9. int port;
    10. sessionTypesEnum sessionType;
    11. };
    12. QList<customType> _data;
    13. public:
    14. void init_data();
    15. };
    To copy to clipboard, switch view to plain text mode 

    Now I'm really unsure of how to do my setData function. I had this:
    Qt Code:
    1. bool ConnectionListModel::setData(const QModelIndex &index, const QVariant &value, int role)
    2. {
    3. if (index.isValid() && role == Qt::DisplayRole)
    4. {
    5. int row = index.row();
    6. //Lets cast our QVariant so we can get the data out
    7. connectionData newData = qvariant_cast<connectionData>( value );
    8.  
    9. connectionList[row].name = newData.name;
    10. connectionList[row].hostAddress = newData.hostAddress;
    11. connectionList[row].username = newData.username;
    12. connectionList[row].password = newData.password;
    13. connectionList[row].port = newData.port;
    14. connectionList[row].sessionType = newData.sessionType;
    15.  
    16. emit dataChanged(index, index);
    17. return true;
    18. }
    19. return false;
    20. }
    To copy to clipboard, switch view to plain text mode 
    But the cast doesn't work since QVariant doesn't know what my connectionData object is. How do I set it?

    Thanks,
    Paul

  2. #2
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Help with getting my custom model working

    You can either register your structure to the meta object system (through Q_DECLARE_METATYPE if I remember well) or (recommended) use roles. Assign a role (integer value, higher than Qt::UserRole) to each member of your structure so that you can set/get properties one at a time which fits better into the model view infrastructure...

    Also, I believe that what you're trying to do is having a collection of connectionData structure inside your model, each one representing a row. Is that true? In this case you must not do it as you tried but instead setup an underlying data structure (e.g. a list of connection data) without using setData() and using them to feed the view through data()...
    Current Qt projects : QCodeEdit, RotiDeCode

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

    Default Re: Help with getting my custom model working

    I would represent every field as a column and add two convenience methods that would operate on whole structs:
    Qt Code:
    1. class ConnectionListModel : public QAbstractTableModel
    2. {
    3. ...
    4. enum Column
    5. {
    6. Name,
    7. HostAddress,
    8. Port,
    9. Username,
    10. Password,
    11. SessionType
    12. };
    13. ...
    14. // below index points to a certain field in certain connection
    15. bool setData( const QModelIndex & index, const QVariant & value, int role );
    16. ...
    17. bool setConnection( int row, const ConnectionData & conn );
    18. const ConnectionData & connection( int row ) const;
    19. ...
    20. };
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Quote Originally Posted by fullmetalcoder View Post
    Also, I believe that what you're trying to do is having a collection of connectionData structure inside your model, each one representing a row. Is that true? In this case you must not do it as you tried but instead setup an underlying data structure (e.g. a list of connection data) without using setData() and using them to feed the view through data()...
    Yes, I was going for a list of items stored in a QList and each item in the QList represents an item in my ListView. This is what I currently have:
    Qt Code:
    1. class ConnectionListModel : public QAbstractListModel
    2. {
    3. Q_OBJECT
    4.  
    5. enum sessionTypesEnum {
    6. secureShell,
    7. remoteFileBrowser
    8. };
    9.  
    10. struct connectionData {
    11. QString name;
    12. QString hostAddress;
    13. QString username;
    14. QString password;
    15. int port;
    16. sessionTypesEnum sessionType;
    17. };
    18.  
    19. public:
    20. ConnectionListModel(QObject *parent = 0);
    21.  
    22. ~ConnectionListModel();
    23.  
    24. //Required items to make this model work
    25. int rowCount(const QModelIndex &parent = QModelIndex()) const;
    26. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    27.  
    28. //required items to be able to edit items
    29. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    30. Qt::ItemFlags flags(const QModelIndex &index) const;
    31.  
    32.  
    33. //Required to be able to resize the model (add & remove shit)
    34. bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
    35. bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
    36.  
    37. private:
    38. QList<connectionData> connectionList;
    39. };
    40.  
    41. ConnectionListModel::ConnectionListModel(QObject *parent)
    42. {
    43. }
    44.  
    45.  
    46. ConnectionListModel::~ConnectionListModel()
    47. {
    48. }
    49.  
    50. int ConnectionListModel::rowCount(const QModelIndex &parent) const
    51. {
    52. return connectionList.count();
    53. }
    54.  
    55. Qt::ItemFlags ConnectionListModel::flags(const QModelIndex &index) const
    56. {
    57. if (!index.isValid())
    58. return Qt::ItemIsEnabled;
    59.  
    60. return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    61. }
    62.  
    63. QVariant ConnectionListModel::data(const QModelIndex &index, int role) const
    64. {
    65. if ( ! index.isValid())
    66. return QVariant();
    67.  
    68. int row = index.row();
    69. if ( row < 0 || row >= connectionList.count() ) //Is the row invalid?
    70. return QVariant();
    71.  
    72. if (role == Qt::DisplayRole)
    73. {
    74. switch( index.column() ){
    75. case 0: return connectionList[row].name;
    76. case 1: return connectionList[row].hostAddress;
    77. case 2: return connectionList[row].username;
    78. case 3: return connectionList[row].password;
    79. case 4: return connectionList[row].port;
    80. case 5: return connectionList[row].sessionType;
    81. return QVariant();
    82. }
    83. }
    84. else
    85. return QVariant();
    86. }
    87.  
    88. bool ConnectionListModel::setData(const QModelIndex &index, const QVariant &value, int role)
    89. {
    90. if (index.isValid() && role == Qt::DisplayRole)
    91. {
    92. int row = index.row();
    93. //Lets cast our QVariant so we can get the data out
    94.  
    95. const connectionData *newData = qvariant_cast<connectionData>( value );
    96.  
    97. //get a pointer to the list item so we can change its contents
    98. connectionList[row].name = newData.name;
    99. connectionList[row].hostAddress = newData.hostAddress;
    100. connectionList[row].username = newData.username;
    101. connectionList[row].password = newData.password;
    102. connectionList[row].port = newData.port;
    103. connectionList[row].sessionType = newData.sessionType;
    104.  
    105. emit dataChanged(index, index);
    106. return true;
    107. }
    108. return false;
    109. }
    110.  
    111.  
    112. bool ConnectionListModel::insertRows(int row, int count, const QModelIndex &parent)
    113. {
    114. beginInsertRows(parent, row, row +count-1);
    115. //Not finished!
    116. endInsertRows();
    117. }
    118.  
    119. bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &parent)
    120. {
    121. beginRemoveRows(parent, row, row+count+1);
    122. //Not finished!
    123. endRemoveRows();
    124. }
    To copy to clipboard, switch view to plain text mode 
    The problem that I have though is that the qvariant_cast<connectionData> doesn't work. I'm not really sure how to pass in the connectionData object using a QVariant.

    Paul

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

    Default Re: Help with getting my custom model working

    Quote Originally Posted by thomaspu View Post
    The problem that I have though is that the qvariant_cast<connectionData> doesn't work. I'm not really sure how to pass in the connectionData object using a QVariant.
    As fullmetalcoder wrote, use Q_DECLARE_METATYPE.

  6. #6
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    OK, I declared my custom datatype outside the class and now that seems to work so that I can set items that are in my QList<connectionData> list.
    Qt Code:
    1. class ConnectionListModel : public QAbstractListModel
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. struct connectionData {
    7. QString name;
    8. QString hostAddress;
    9. QString username;
    10. QString password;
    11. int port;
    12. sessionTypesEnum sessionType;
    13. };
    14.  
    15. ConnectionListModel(QObject *parent = 0);
    16. ~ConnectionListModel();
    17.  
    18. private:
    19. QList<connectionData> connectionList;
    20. };
    21. Q_DECLARE_METATYPE(ConnectionListModel::connectionData);
    To copy to clipboard, switch view to plain text mode 
    But now I'm lost as to how to add data to it. I understand that I have to do my own insertRows function. Is the purpose of the insertRows function just to insert a row, but not add the data to it?

    In other words, to insert a row, I'd be expected to do something like this to the model:
    Qt Code:
    1. conenctionData addMe;
    2. //set items in addMe
    3. myModel.insertRows(1, 1, QModelIndex ????); // <-what do i do here?
    4. myModel.setData(QModelIndex ???, addMe);
    To copy to clipboard, switch view to plain text mode 

    Paul

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

    Default Re: Help with getting my custom model working

    Quote Originally Posted by thomaspu View Post
    myModel.insertRows(1, 1, QModelIndex ????); // <-what do i do here?
    You can use the default value for the last parameter (i.e. QModelIndex()). Your items don't have a parent, since you have a flat list. If you had a tree, then you would have to specify it to add items below the root.

    Quote Originally Posted by thomaspu View Post
    myModel.setData(QModelIndex ???, addMe);
    Here you need a model index that points to that empty row, you have added in previous line. You can get it using the index() method:
    Qt Code:
    1. myModel.setData( myModel.index( 0 ), addMe);
    To copy to clipboard, switch view to plain text mode 

  8. #8
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    I'm making slow progress here. Understanding this stuff is frustrating. Now I can put stuff in the model (I think) but it doesn't show up in my associated view. I think I've got the setData() dataChanged signal all messed up. It keeps giving me comipler errors.

    Qt Code:
    1. bool ConnectionListModel::setData(const QModelIndex &index, const QVariant &value, int role)
    2. {
    3. if (index.isValid() && role == Qt::DisplayRole)
    4. {
    5. int row = index.row();
    6. //Lets cast our QVariant so we can get the data out
    7.  
    8. connectionData newData = value.value<connectionData>();
    9.  
    10. //get a pointer to the list item so we can change its contents
    11. connectionList[row].name = newData.name;
    12. connectionList[row].hostAddress = newData.hostAddress;
    13. connectionList[row].username = newData.username;
    14. connectionList[row].password = newData.password;
    15. connectionList[row].port = newData.port;
    16. connectionList[row].sessionType = newData.sessionType;
    17.  
    18. emit dataChanged( index(row, 0), index(row, 0));
    19. return true;
    20. }
    21. return false;
    22. }
    To copy to clipboard, switch view to plain text mode 

    What am I doing wrong now?
    Paul

  9. #9
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Alright, I was able to fix my compile problems by changing the dataChanged signal call to
    Qt Code:
    1. emit dataChanged( createIndex(row, 0), createIndex(row, 0));
    To copy to clipboard, switch view to plain text mode 
    Now the problem that I have is when I add an item to my model, it doesn't show up in the view. I'm

    So I'm adding in the data to my list model class like this:
    Qt Code:
    1. ConnectionListModel::connectionData addMe;
    2.  
    3. m_pSessionModel->insertRows(0, 1);
    4. m_pSessionModel->setData( m_pSessionModel->index(0), &addMe);
    To copy to clipboard, switch view to plain text mode 
    Adn in my list model, I'm adding the new row through the insertRows:
    Qt Code:
    1. bool ConnectionListModel::insertRows(int row, int count, const QModelIndex &parent)
    2. {
    3. beginInsertRows(parent, row, row +count-1);
    4.  
    5. //Let's add a new connectionData item to our list
    6. connectionData newItem;
    7. connectionList.insert(row, newItem);
    8.  
    9. endInsertRows();
    10. emit dataChanged( createIndex(row, 0), createIndex(row, 0));
    11. printf("There are now %d items in the list\n", connectionList.count() );
    12. return true;
    13. }
    To copy to clipboard, switch view to plain text mode 

    I thought that thats all I needed to do. Any ideas?
    Paul

  10. #10
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Help with getting my custom model working

    You need to reimplement some more functions :
    Qt Code:
    1. ConnectionListModel::rowCount(QModelIndex &idx)
    2. {
    3. return idx.isValid() ? 0 : connectionList.count();
    4. }
    5.  
    6. QVariant ConnectionListModel::data(QModelIndex &idx, int role) const
    7. {
    8. if ( role == Qt::DisplayRole )
    9. return idx.isValid() ? connectionList.at(idx.row()).<field corresponding to column value> : <header data>;
    10. // maybe return other values for other fileds (e.g. Qt::DecorationRole)
    11. return QVariant();
    12. }
    To copy to clipboard, switch view to plain text mode 
    Current Qt projects : QCodeEdit, RotiDeCode

  11. #11
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Thanks for the replies, cause I've really been struggling with this. I think I have reimplemented all needed functions. Here's whats in my header file so far and that I have defined in my source file.
    Qt Code:
    1. ConnectionListModel(QObject *parent = 0);
    2. ~ConnectionListModel();
    3.  
    4. //Required items to make this model work
    5. int rowCount(const QModelIndex &index = QModelIndex()) const;
    6. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    7.  
    8. //required items to be able to edit items
    9. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    10. Qt::ItemFlags flags(const QModelIndex &index) const;
    11.  
    12. //Required to be able to resize the model (add & remove shit)
    13. bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
    14. bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
    15.  
    16. private:
    17. QList<connectionData> connectionList;
    To copy to clipboard, switch view to plain text mode 
    One thing that I noticed when stepping through my code while trying to add an item was that I'm never calling my setData funciton with a valid index, so it always skips over the code and never emits the signal that the data changed.

    So now my question is how do I get a valid index? I thought that calling index(0) would give me the index for the item that I just inserted at the front of the list, but that isn't the case.

    Here's the calling code
    Qt Code:
    1. //where m_pSessoinModel is a connectionlistmodel
    2. ConnectionListModel::connectionData addMe;
    3.  
    4. m_pSessionModel->insertRows(0, 1); //inserting 1 row before row #0
    5. m_pSessionModel->setData( m_pSessionModel->index(0), &addMe);
    To copy to clipboard, switch view to plain text mode 

    Any ideas? The examples online are not very helpful here.
    Paul

  12. #12
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Quote Originally Posted by thomaspu View Post
    So now my question is how do I get a valid index? I thought that calling index(0) would give me the index for the item that I just inserted at the front of the list, but that isn't the case.
    index(0) shouldn't even compile AFAIK... it should be index(0, 0) (or index(0, 1) and so on...). An index obtained through the index() method represents a single cell, not a whole row...

    besides, your header is slightly wrong... The default role for the setData() function should be Qt:isplayRole as well or am I missing something?
    Current Qt projects : QCodeEdit, RotiDeCode

  13. #13
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    The QAbstractListModel defines a default for the column:
    Qt Code:
    1. virtual QModelIndex index ( int row, int column = 0, const QModelIndex & parent = QModelIndex() ) const
    To copy to clipboard, switch view to plain text mode 
    But when do you ever get a valid QModelIndex? When I'm calling the insertRows function, I don't know the parent at all. The description in the function reads
    Returns the index of the data in row and column with parent.
    So If I never have the parent... thats probably why it doesn't work?

    Yeah, the role should have just been Qt:isplayRole

    Paul

  14. #14
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Quote Originally Posted by thomaspu View Post
    When I'm calling the insertRows function, I don't know the parent at all. The description in the function reads So If I never have the parent... thats probably why it doesn't work?l
    The point is that you never HAVE any parents anywhere since you're using a table and not a hierarchical (i.e. tree) model. When no parent is involved the parent is the header node which is represented by an invalid parent (which is the default parent passed to all methods that require a parent BTW... )
    Current Qt projects : QCodeEdit, RotiDeCode

  15. #15
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Ok, that makes sense since this is just a flat model. So any ideas why nothing shows up on my QListView after I add an item to my model?

    Paul

  16. #16
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Help with getting my custom model working

    May I ask for the full code?
    Current Qt projects : QCodeEdit, RotiDeCode

  17. #17
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Sure, let me put it together. Just a few min...

  18. #18
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Ok, all you need is attached.

    Paul
    Attached Files Attached Files

  19. #19
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Ok I found the bug... You messed up the rowCount() function... The point in this one is to return the number of connections when the parent passed is the root node (so an invalid index) and to return 0 (no child) when the parent is valid (i.e. one of the connection...)

    Note that before I found that I added a columnCount() function so you may also need to add it so as to have your model working properly...
    Current Qt projects : QCodeEdit, RotiDeCode

  20. The following user says thank you to fullmetalcoder for this useful post:

    thomaspu (29th July 2007)

  21. #20
    Join Date
    Nov 2006
    Posts
    86
    Thanks
    6
    Thanked 14 Times in 5 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Help with getting my custom model working

    Ah, yes, that was it! Yeah, you return the number of connections when the parent is invalid. Which in my case is always cause my list is flat and doesn't have a parent.

    Thanks for all the help, I think I'm good to go for a bit!
    Paul

Similar Threads

  1. hierarchical model in a flat view
    By gniking in forum Qt Programming
    Replies: 4
    Last Post: 10th November 2009, 20:17
  2. Coin3d + Qt: SIGLNALs and SLOTs
    By vonCZ in forum Newbie
    Replies: 26
    Last Post: 15th May 2009, 07:34
  3. Custom Model Class
    By mattjgalloway in forum Qt Programming
    Replies: 12
    Last Post: 4th June 2007, 17:30
  4. Treeview and custom model
    By steg90 in forum Qt Programming
    Replies: 8
    Last Post: 15th May 2007, 13:54
  5. TreeView custom model
    By steg90 in forum Newbie
    Replies: 1
    Last Post: 9th May 2007, 10:06

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.