Создаем модель для QTableView - Работа с моделями в Qt для отображения данных в виджетах. Часть 7
Сегодня мы рассмотрим создание модели в Qt для виджета QTableView. В отличии от QListView у данного компонента есть не только строки, но и столбцы.
Так же у таблицы есть и заголовки столбцов, так что мы реализуем необходимый для их отображения метод.
Создаем проект
Создадим новый проект Qt Widgets Application с именем QTableViewModel.
Добавим на главную форму виджет QTableView.
Создадим класс для хранения наших данных – CountryFlag
Заголовок
#ifndef COUNTRYFLAG_H
#define COUNTRYFLAG_H
#include <QString>
class CountryFlag
{
public:
CountryFlag();
CountryFlag(int id, QString name, QString icon);
QString getIcon() const;
void setIcon(const QString &value);
QString getName() const;
void setName(const QString &value);
int getId() const;
void setId(int value);
private:
int id;
QString icon;
QString name;
};
#endif // COUNTRYFLAG_H
Реализация
#include "countryflag.h"
CountryFlag::CountryFlag()
{
}
CountryFlag::CountryFlag(int id, QString name, QString icon)
{
this->id = id;
this->name = name;
this->icon = icon;
}
QString CountryFlag::getIcon() const
{
return icon;
}
void CountryFlag::setIcon(const QString &value)
{
icon = value;
}
QString CountryFlag::getName() const
{
return name;
}
void CountryFlag::setName(const QString &value)
{
name = value;
}
int CountryFlag::getId() const
{
return id;
}
void CountryFlag::setId(int value)
{
id = value;
}
Создаем модель для таблицы
Создадим класс модели для таблицы - QTableViewModel.
Заголовок:
#ifndef QTABLEVIEWMODEL_H
#define QTABLEVIEWMODEL_H
#include "countryflag.h"
#include <QModelIndex>
class QTableViewModel : public QAbstractListModel
{
public: QTableViewModel(QObject *parent=nullptr);
int rowCount(const QModelIndex &) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
void populate(QList<CountryFlag> *newValues);
private:
QList<CountryFlag> *values;
};
#endif // QTABLEVIEWMODEL_H
Реализация:
#include "qtableviewmodel.h"
#include <QModelIndex>
#include <QDebug>
#include <QPixmap>
QTableViewModel::QTableViewModel(QObject *parent)
:QAbstractListModel(parent)
{
values = new QList<CountryFlag>();
}
int QTableViewModel::rowCount(const QModelIndex &) const
{
return values->count();
}
int QTableViewModel::columnCount(const QModelIndex &) const
{
return 3;
}
QVariant QTableViewModel::data( const QModelIndex &index, int role ) const
{
QVariant value;
switch ( role )
{
case Qt::DisplayRole: //string
{
switch (index.column()) {
case 0: {
value = this->values->at(index.row()).getId();
break;
}
case 1: {
value = this->values->at(index.row()).getName();
break;
}
case 2: {
value = this->values->at(index.row()).getIcon();
break;
}
}
}
break;
case Qt::UserRole: //data
{
value = this->values->at(index.row()).getId();
}
break;
default:
break;
}
return value;
}
void QTableViewModel::populate(QList<CountryFlag> *newValues)
{
int idx = this->values->count();
this->beginInsertRows(QModelIndex(), 1, idx);
this->values = newValues;
endInsertRows();
}
По сравнению с QComboBox, в модели для таблицы добавился еще один метод – columnCount() указывающий количество столбцов.
Так же в методе data() мы проверяем текущий столбец с помощью:
index.column()
и, в зависимости от номера столбца, возвращаем значение.
Обратите внимание, что метод data() вызывается для каждой строки и каждого столбца этой строки соответственно!
Добавим код в конструктор главной формы, чтобы наполнить таблицу данными:
values = new QList<CountryFlag>;
values->append(CountryFlag(1," Russia", "russia.png"));
values->append(CountryFlag(11, "Belarus", "belarus.png"));
values->append(CountryFlag(22, "Slovakia", "slovakia.png"));
values->append(CountryFlag(33, "Slovenia", "slovenia.png"));
values->append(CountryFlag(44, "China", "china.png"));
values->append(CountryFlag(55, "Mongolia","mongolia.png"));
model = new QTableViewModel();
model->populate(values);
this->ui->tableView->setModel(model);
Запустим:
Добавляем методы для работы с данными в таблице
Давайте доработаем модель, добавив методы для добавления и удаления строк.
В заголовок модели добавим:
void append(CountryFlag value);
void update(int idx, CountryFlag value);
void deleteRow(int idx);
void insertAt(int idx, CountryFlag value);
В реализацию:
void QTableViewModel::append(CountryFlag value)
{
int newRow = this->values->count()+1;
this->beginInsertRows(QModelIndex(), newRow, newRow);
values->append(value);
endInsertRows();
}
void QTableViewModel::update(int idx, CountryFlag value)
{
(*this->values)[idx] = value;
QModelIndex item_idx_s = this->index(idx,0);
QModelIndex item_idx_e = this->index(idx,this->columnCount(QModelIndex()));
emit this->dataChanged(item_idx_s ,item_idx_e );
}
void QTableViewModel::deleteRow(int idx)
{
this->beginRemoveRows(QModelIndex(), idx,idx);
(*this->values).removeAt(idx);
this->endRemoveRows();
}
void QTableViewModel::insertAt(int idx, CountryFlag value)
{
int newRow = idx;
this->beginInsertRows(QModelIndex(), newRow, newRow);
values->insert(newRow,value);
endInsertRows();
}
Обратите внимание, по сравнению с моделями для QComboBox и QListView изменился метод update(). Для того, чтобы обновить все столбцы, мы вычисляем индексы первого и последнего столбцов, и потом обновляем все столбцы обновляемой строки!
Добавляем кнопки для управления строками таблицы
Добавим кнопки на главную форму:
Добавим слоты для кнопок:
void MainWindow::on_pushButton_clicked()
{
newidx++;
QString strIdx = QString().number(newidx);
model->append(CountryFlag(newidx, "new country " + strIdx, "russia.png"));
}
void MainWindow::on_pushButton_2_clicked()
{
model->update(ui->tableView->currentIndex().row(), CountryFlag(66, "Japan", "japan.png"));
}
void MainWindow::on_pushButton_3_clicked()
{
model->deleteRow(0);
}
void MainWindow::on_pushButton_4_clicked()
{
model->insertAt(0, CountryFlag(66, "Japan", "japan.png"));
}
Добавим приватное поле для главной формы:
int newidx;
И в конец конструктора формы инициализацию:
newidx = 100;
Запустим:
Кнопки работают и строки обновляются.
Добавляем названия столбцов
До сих пор вместо названий столбцов у нас были цифры, пришла пора добавить им нормальные значения.
В модель добавим новый метод:
QVariant QTableViewModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
switch (section) {
case 0:
return QString("ID");
case 1:
return QString("Name");
case 2:
return QString("Icon");
}
}
return QVariant();
}
Он работает так же как и метод data() только вызывается один раз для каждого столбца.
Запускаем
Вот мы и создали модель для QTableView. Хочу отметить, что данная модель подойдет только данных, которые хранятся в виде строк. Если у вас есть матрица или массив чисел, потребуется модернизация модели, но об этом мы поговорим в следующей статье.
Заключение
Сегодня мы создали модель для QTableView.
Мы добавили новый метод columnCount() указывающий количество столбцов в таблице.
Обновили метод update(), для работы с таблицей.
Добавили метод headerData() для отображения заголовков столбцов.
В следующей статье мы поговорим о том, как использовать модель с массивами.
Исходный код проекты вы можете найти на GitFlic.
Добавить комментарий