2

I have subclassed a QAbstractTableModel to represent data from a QMap. This QMap has QLists of QSqlRecords and this map is modified by some other part of my code. I want to use this model with a QTableView to display the sql records in this map for each key. Here is my code.

//mymodel.h

class MyModel : public QAbstractTableModel
{
Q_OBJECT

public:
    MyModel(QObject *parent = 0);
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role) const;
    void setRecordMap(QMap<int, QList<QSqlRecord>> *map);
    void setSelectedSerMsgIndex(QModelIndex *index);

private:
    QMap<int, QList<QSqlRecord>> *recordMap;
    QModelIndex *selectedSerendibMsgIndex;
};

//mymodel.cpp

MyModel::MyModel(QObject *parent) : QAbstractTableModel(parent)
{

}

int MyModel::rowCount(const QModelIndex &parent) const
{
    if(recordMap->isEmpty())
        return 0;

    int row = selectedSerendibMsgIndex->row();
    return recordMap->value(row).size();
}

int MyModel::columnCount(const QModelIndex &parent) const
{
    if(recordMap->isEmpty())
        return 0;

    int row = selectedSerendibMsgIndex->row();
    return recordMap->value(row).at(0).count();
}

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if(recordMap->isEmpty())
        return QVariant();

    if (!index.isValid())
        return QVariant();

    int row = selectedSerendibMsgIndex->row();
    if (index.row() >= recordMap->value(row).size())
        return QVariant();

    if (role == Qt::DisplayRole) 
    {
        return  recordMap->value(row).value(index.row()).value(index.column()); /* QVariant("hello");*/
    } 
    else 
    {
        return QVariant();
    }
}

void MyModel::setRecordMap(QMap<int, QList<QSqlRecord>> *map)
{
    recordMap = map;
}

void MyModel::setSelectedSerMsgIndex(QModelIndex *index)
{
    selectedSerendibMsgIndex = index;
}

Sorry for the huge post. But the problem is, I cannot see the data from the map. I am guessing it is because there's something wrong with my implementation of the data() method. But I can't figure out what it is. Please be kind enough to help me. Thank you.

kasper360
  • 367
  • 2
  • 4
  • 14
  • Have you debugged what happens in your data method, i.e. if the recordMap->value(...) part is ever reached? Also, where do you get that QModelIndex pointer from (selectedSenredibMsgIndex)? QModelIndexes shouldn't be stored by pointer, they are always passed by value/const ref. The objects might become invalid anytime. You could just store int row here. (Same for QMap btw - no need to pass it around by pointer) – Frank Osterfeld Apr 19 '11 at 06:32
  • Thanks Frank. I used the debugger on data() method, but strangely, it's never even called. Is there a particular reason for this? – kasper360 Apr 19 '11 at 09:24
  • 2
    Then I would check if rowCount and columnCount return the expected values (>0). Also call reset() after replacing the map in setRecordMap(). – Frank Osterfeld Apr 19 '11 at 09:55
  • I checked both rowCount() and columnCount() and they return correct values. I also called reset() after replacing the map. But still it's the same. :( – kasper360 Apr 19 '11 at 10:19
  • 2
    As you pass the map by value, does the map change after you pass it to the model? – Frank Osterfeld Apr 19 '11 at 11:10
  • 2
    Another thing to check, just to be sure: have you set the model on the view? – Caleb Huitt - cjhuitt Apr 19 '11 at 16:33
  • 1
    No need to use pointers to QMap, either. Unfortunately, I don't think this is the issue. :( I'd suggest delegating to `QSqlTableModel` or `QSqlQueryModel` instead of mapping directly to `QSqlRecord`. Indexing, view refreshing and selection logic might break. – andref Apr 19 '11 at 18:11
  • @Frank: yes, the map is being changed according to GUI interactions. And i need to display these changes in a view. – kasper360 Apr 20 '11 at 03:07
  • @Caleb: yes, I set the model on a view. – kasper360 Apr 20 '11 at 03:09
  • @Andref: I tried using both these models but what I want is to display the content of this QMap. Usage of this QMap is not optional, so I had to implement my own model to do that. If I need to display the content of this QMap with all the dynamic changes happening to it, how can I achieve this without using a pointer? Plese explain. Thank you – kasper360 Apr 20 '11 at 03:13
  • 2
    kasper360: It won't work, as you can't observe a map for changes (there is no notification mechanism). And the model has to insert/remove rows and columns as data is inserted/removed into the map. You either need a private data structure that is controlled by the model (note that using maps there is rather inefficient - you want O(1) lookup), or a notification from the outside that the shared map has changed (and how). – Frank Osterfeld Apr 20 '11 at 05:41
  • Thank you very much Frank,Just because you asked that question earlier, I got suspicious and did some reading. And I figured out that in order to use the model with a dynamic data structure, I have to re-implement insertRows() and removeRows(). After doing that, my model works like a charm! Btw, maps turn out to be rather inefficient here since after inserting some rows, the whole thing becomes slow to interact. If i used a Hashmap instead, would it be faster since QHash can be optimized to O(1) lookup? – kasper360 Apr 20 '11 at 06:02

1 Answers1

2

try changing this:

void MyModel::setRecordMap(QMap<int, QList<QSqlRecord>> *map)
{
    recordMap = map;
}

to this:

void MyModel::setRecordMap(QMap<int, QList<QSqlRecord>> *map)
{
    beginResetModel();
    recordMap = map;
    endResetModel();
}
Jonathon
  • 21
  • 2