qtlistviewqlistviewqmodelindex

How to set data source for a list view to contain custom data ? (and associate with QTableView)


I am trying to get listview and tableview working together.

The listview must be used for display, the tableview must be used for editing data. The tableview is created on demand in a popup widget (and it may never be needed).

I populate the listview, on start, from a text file - each row a line, with 2 entries separated by a tab. Easy.

The tableview will have to edit 2 columns separately... also, on listview click, I must be able to retrieve the first part of the split...

I have created a model subclass of QStringListModel.

QListView *m_myView = new QListView();
StringList *m_myList = new StringList();
QTextStream in(&myFile); 
while (!in.atEnd())
{
    QString temp = in.readLine();
    if(!temp.isEmpty())
        m_myList->append(temp);
}
myFile.close();
m_myView->setModel(m_myList);

where

class StringList : public QStringListModel
{
public:
    void append (const QString& string)
    {
        insertRows(rowCount(), 1);
        QModelIndex m = index(rowCount() - 1);
        setData(m, string, Qt::EditRole);
        QStringList splist = string.split('\t');
        setData(m, splist.at(0), Qt::ToolTipRole);
        if(splist.size() > 1)
            setData(m, splist.at(1), Qt::StatusTipRole);
        else
            setData(m, "", Qt::StatusTipRole);

        qDebug() << data(m, Qt::EditRole).toString()
                 << data(m, Qt::ToolTipRole).toString()
                 << data(m, Qt::StatusTipRole).toString();
    }
};

The EditRole displays correctly, the others display empty strings.

It seems that QStringListModel is incapable of storing anything except EditRole.

So I am left with 2 options - either do the split on each selection, and also when creating the table view, or - what I would like to try but don't know how - create a QStandardItemModel that can act as data sources for both the listview and the tableview, and can easily retrieve the partial data I require on click.

I thought I can simply use it to set the data on listview (like they do here).

QListView *m_myView = new QListView();
QStandardItemModel *m_myList = new QStandardItemModel();
QTextStream in(&myFile); 
int r = 0;
while (!in.atEnd())
{
    QString temp = in.readLine();
    if(!temp.isEmpty())
    {
        QStringList splist = temp.split('\t'); // assume I know there will be 2 strings always
        QStandardItem *item = new QStandardItem(splist.at(0));
        m_myList->setItem(r, 0, item);
        QStandardItem *item1 = new QStandardItem(splist.at(1));
        m_myList->setItem(r, 1, item1);
        ++r;
    }
}
myFile.close();
m_myView->setModel(m_myList);

connect(m_myListView, SIGNAL(clicked(QModelIndex)),
        this, SLOT(listChangedSlot(QModelIndex)));

But this will only set the first string in the listview, I really need both, and I still don't know how to retrieve the data

void listChangedSlot(QModelIndex index)
{
    qDebug() << m_myList->item(index.row(), 0)->data().toString()
             << m_myList->item(index.row(), 1)->data().toString();
} // shows empty strings

Or...
In the loading section, try:

    if(!temp.isEmpty())
    {
        QStringList splist = temp.split('\t');
        splist.append(QString()); // so I don't need to test
        QStandardItem *item = new QStandardItem(temp);
        m_myList->setItem(r, 0, item);
        QModelIndex idx = m_myList->index(r, 0);
        QMap<int, QVariant> roles;
        roles.insert(Qt::UserRole + 1, QVariant(splist.at(0)));
        roles.insert(Qt::UserRole + 2, QVariant(splist.at(1)));
        roles.insert(Qt::DisplayRole, QVariant(temp));
        m_myList->setItemData(idx, roles);
        ++r;
    }

This works - displays fine and gets the correct content on click - but seems to be unusable for the tableview.
(And seems I am doing twice the work, with setItem and setItemData - so technically storing the content 3 times).

How can I get my listview have a datasource with 2 string items, show both, be able to set it on a tableview, and be able to retrieve the first item on click ?


Solution

  • I figured out a way to share the data source between the listview and tableview:

    I create 3 columns - column 0 with the combined components, and columns 1 and 2 with the separated components.

    The listview will display only column 0. For tableview, I will hide column 0.

    The data I require for processing will be stored in columns 1 and 2. user edit of the data in tableview will require, upon accepting changes, the edit of corresponding column 0.