Как настроить источник данных для представления списка, чтобы содержать пользовательские данные? (и связать с QTableView)

Я пытаюсь совместить просмотр списка и просмотр таблицы.

Представление списка должно использоваться для отображения, представление таблицы должно использоваться для редактирования данных. Представление таблицы создается по запросу во всплывающем виджете (и оно может никогда не понадобиться).

При запуске я заполняю представление списка из текстового файла - каждая строка представляет собой строку с двумя записями, разделенными вкладкой. Легко.

Табличное представление должно будет редактировать 2 столбца отдельно... также, по щелчку по списку, я должен быть в состоянии получить первую часть разделения...

Я создал модель подкласса 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);

где

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();
    }
};

EditRole отображается правильно, остальные отображают пустые строки.

Кажется, что QStringListModel неспособен хранить что-либо кроме EditRole,

Таким образом, у меня есть 2 варианта - либо делить на каждый выбор, а также при создании представления таблицы, или - что я хотел бы попробовать, но не знаю как - создать QStandardItemModel он может выступать в качестве источников данных как для просмотра списка, так и для просмотра таблицы, и может легко извлекать частичные данные, которые мне требуются, по щелчку.

Я думал, что могу просто использовать это, чтобы установить данные на просмотр списка (как они делают здесь).

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)));

Но это только установит первую строку в списке, мне действительно нужны оба, и я до сих пор не знаю, как получить данные

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

Или же...
В разделе загрузки попробуйте:

    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;
    }

Это работает - отображается нормально и получает правильное содержимое по клику - но кажется непригодным для просмотра таблицы.
(И, кажется, я делаю вдвое больше работы, с setItem а также setItemData - так что технически хранить контент 3 раза).

Как я могу получить в своем списке просмотра источник данных с двумя строковыми элементами, показать оба, иметь возможность установить его в виде таблицы и получить первый элемент по щелчку?

2 ответа

Решение

Я нашел способ поделиться источником данных между просмотром списка и просмотром таблицы:

Я создаю 3 столбца - столбец 0 с объединенными компонентами и столбцы 1 и 2 с разделенными компонентами.

Представление списка будет отображать только столбец 0. Для представления таблицы я буду скрывать столбец 0.

Данные, которые мне требуются для обработки, будут храниться в столбцах 1 и 2. Пользовательское редактирование данных в виде таблицы потребует, после принятия изменений, редактирования соответствующего столбца 0.

Если вы не можете или не хотите изменять исходную модель, вы можете использоватьQIdentityProxyModel. Когда вы переопределяетеdataфункция, она будет работать как преобразователь между вашей исходной моделью и ожидаемой для другого представления.

Допустим, наша исходная модель является производным классом от withFirstNameиLastNameстолбцы.
Мы хотим передать QListView эту модель, объединив имя и фамилию (с пробелом между ними).

Тогда наш прокси будет выглядеть примерно так:

      class RegistrationListModel : public QIdentityProxyModel {
public:
    QVariant data(const QModelIndex &index, int role) const override {
        if(role == Qt::DisplayRole) {
            return QString("%1 %2").arg(
                sourceModel()->data({index.row(), CLM_FIRST_NAME}, role),
                sourceModel()->data({index.row(), CLM_LAST_NAME}, role));
        }
        return sourceModel()->data(index, role);
    };
};

Для большей ясности я упростил вызов «получить данные». Это было бы что-то sourceModel()->data(sourceModel()->index(index.row(), CLM_FIRST_NAME), role).toString()потому что мы не можем создать индекс самостоятельно.

Использование такого прокси в вашем виджете (предположим,proxyModelявляется указателем на членMyWidget):

      MyWidget::MyWidget(QWidget* parent) :
    QWidget(parent)
{
    proxyModel = new RegistrationListModel();
    auto listView = new QListView(this);
    listView->setModel(proxyModel);
}

void MyWidget::setSharedModel(QAbstractItemModel *model)
{
    proxyModel->setSourceModel(model);   
}

Осталось только позвонитьsetSharedModelна нашем виджете с соответствующимQAbstractTableModel.

Другие вопросы по тегам