====== Модель-представление ====== ===== Модель (данных) ===== {{ :develop:qt:qt-model_0.png?direct&600 |}} Содержатся такие свойства как **index()**, **ItemDataRole()**, **flags()**, **match()**\\ **DataRole**- содержит много разных вариантов ролей данных\\ **ListModel**- простой, одномерный список\\ **StandartItemModel**- гораздо более сложная структура, каждая запись является отдельным итемом, с возможностью его настройки со-но.\\ Для использования, абстрактные классы необходимо наследовать, для работы необходимо определить как минимум три функции: **rowCount()**, **ColumnCount()** и **data()**.\\ Для хранения данных, внутри собственного класса, похоже нужно создавать собственные структуры данных, контейнеры и т.д. и сосбна обрабатывать их.\\ ==== QModelIndex ==== Используется в качестве индекса в моделях, используется представлениями, делегатами, моделям выбора и поиска элементов.\\ Новые объекты создаются с помощью функции **QAbstractItemModel::createIndex()**, недействительный может быть построен с помощью конструктора **QModelIndex()**, недействительные часто используются в качестве родительских индексов, верхнего уровня.\\ Индексы относятся к элементам и содержат всю информацию, необходимую для определения их местоположения.\\ **QAbstractItemModel::index()**- возвращает индекс на существующий элемент.\\ | bool **isValid()** | true если индекс принадлежит модели и имеет неотрицательные номера столбцов/строк | | QModelIndex **sibling()** | возвращает "родственника" в указанной позиции оО | | QVariant **data()** | возвращает данные для указанной роли | ===== Представление (данных) ===== {{ :develop:qt:qt-view_0.png?direct&600 |}} В представлении содержатся функции рисования/отображения, выбор, выделение записей.\\ ===== Примеры ===== ==== Таблица ====
:!: Простая таблица, минимум функций+ вставка/удаление строк/столбцов :?: В ф-ции **beginInsertColumn**/**beginInsertRow**, нужно передавать корректные индексы, если передавать нули, то происходит вставка только одной записи, если не корректные цифры то все вообще по п*зде идет.\\ :?: Вставлять элементы можно как сразу в объект хранения (вектор/лист) так и ф-ями **insertColumn**/**insertRow**.\\ class VectorTableModel; class MWin : public QMainWindow { Q_OBJECT VectorTableModel *VModelTab; QTableView *VViewTab; QLineEdit *editDataForWrite; QPushButton *butAddRecord, *butAddColumn, *butDelRecord, *butDelColumn; public: MWin(QWidget *parent = nullptr); public slots: void slotInsertNewRecord(); void slotInsertNewColumn(); void slotDeleteSelectedRecord(); void slotDeleteSelectedColumn(); }; class VectorTableModel: public QAbstractTableModel { Q_OBJECT QVector *> *LisIsData; QVector *HeadersList; public: VectorTableModel(QObject *parent= nullptr); ~VectorTableModel(); // Минимальные QVariant data(const QModelIndex &index, int role= Qt::DisplayRole) const; int rowCount(const QModelIndex &parent= QModelIndex()) const; int columnCount(const QModelIndex &parent= QModelIndex()) const; // Переопределенные QVariant headerData(int section, Qt::Orientation orientation, int role) const; bool setData(const QModelIndex &index, const QVariant &value, int role); // Собственные void addRow(const QVector &vValues); void addColumn(qint32 vCount); void delRow(const qint32 &vNumberRow); void delColumn(const qint32 &vNumberCol); }; #include "mwin.h" MWin::MWin(QWidget *parent): QMainWindow(parent) { VModelTab= new VectorTableModel(this); VViewTab= new QTableView(this); VViewTab->setModel(VModelTab); VViewTab->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows); editDataForWrite= new QLineEdit(this); butAddRecord= new QPushButton("Новая запись", this); butAddColumn= new QPushButton("Новый столбец", this); QHBoxLayout *layCtrls= new QHBoxLayout(); layCtrls->addWidget(editDataForWrite, 1); layCtrls->addWidget(butAddRecord, 0); layCtrls->addWidget(butAddColumn, 0); butDelRecord= new QPushButton("Удалить строку", this); butDelColumn= new QPushButton("Удалить столбец", this); QHBoxLayout *laySecondCtrls= new QHBoxLayout(); laySecondCtrls->addWidget(butDelRecord); laySecondCtrls->addWidget(butDelColumn); QVBoxLayout *layMain= new QVBoxLayout(); layMain->addWidget(VViewTab, 2); layMain->addLayout(layCtrls); layMain->addLayout(laySecondCtrls); QWidget *myWindow= new QWidget(); myWindow->setLayout(layMain); setCentralWidget(myWindow); connect(butAddRecord, &QPushButton::clicked, this, &MWin::slotInsertNewRecord); connect(butAddColumn, &QPushButton::clicked, this, &MWin::slotInsertNewColumn); connect(butDelRecord, &QPushButton::clicked, this, &MWin::slotDeleteSelectedRecord); connect(butDelColumn, &QPushButton::clicked, this, &MWin::slotDeleteSelectedColumn); } void MWin::slotInsertNewRecord() { if(editDataForWrite->text().isEmpty()) { QMessageBox::information(this, "Text", "Please input text"); return; } VModelTab->addDataRow(editDataForWrite->text().split(";", Qt::SkipEmptyParts)); editDataForWrite->clear(); editDataForWrite->setFocus(); } void MWin::slotInsertNewColumn() { if(editDataForWrite->text().isEmpty()) { QMessageBox::information(this, "Text", "Please input count"); return; } VModelTab->addColumn(editDataForWrite->text().toInt()); editDataForWrite->clear(); editDataForWrite->setFocus(); } void MWin::slotDeleteSelectedRecord() { VModelTab->delRow(VViewTab->currentIndex().row()); } void MWin::slotDeleteSelectedColumn() { VModelTab->delColumn(VViewTab->currentIndex().column()); } //*********************************************************************| //*********************************************************************| VectorTableModel::VectorTableModel(QObject *parent): QAbstractTableModel(parent) { LisIsData= new QVector* >; HeadersList= new QVector; } VectorTableModel::~VectorTableModel() { while(!LisIsData->isEmpty()) delete LisIsData->takeFirst(); delete LisIsData; delete HeadersList; } QVariant VectorTableModel::data(const QModelIndex &index, int role) const { if(role== Qt::DisplayRole) return LisIsData->at(index.row())->at(index.column()); return QVariant(); } int VectorTableModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return LisIsData->count(); } int VectorTableModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return LisIsData->isEmpty() ? 0:LisIsData->at(0)->count(); } QVariant VectorTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if(role!= Qt::DisplayRole) return QVariant(); if(orientation== Qt::Horizontal) return HeadersList->count() > section ? HeadersList->at(section):""; else return QString::number(section +1); } bool VectorTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if(index.isValid() && role== Qt::EditRole) { LisIsData->at(index.row())->replace(index.column(), value.toString()); emit dataChanged(index, index); return true; } return false; } void VectorTableModel::addRow(const QVector &vValues) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); QVector *vNewRow= new QVector(vValues); // Подгоняем кол-во столбцов, к большему, либо в гриде (векторе) либо в новой строке if(columnCount() > vNewRow->count()) vNewRow->resize(this->columnCount()); else if(columnCount() < vNewRow->count()) { beginInsertColumns(QModelIndex(), columnCount(), columnCount()+ (vNewRow->count()- columnCount()) -1); for(qint32 i= 0; i < LisIsData->count(); i++) LisIsData->at(i)->resize(vNewRow->count()); endInsertColumns(); } LisIsData->append(vNewRow); endInsertRows(); } void VectorTableModel::addColumn(qint32 vCount) { beginInsertColumns(QModelIndex(), columnCount(), columnCount()+ vCount -1); while(vCount--) this->insertColumn(columnCount()); endInsertColumns(); } void VectorTableModel::delRow(const qint32 &vNumberRow) { beginInsertRows(QModelIndex(), vNumberRow, vNumberRow); if(LisIsData->count() > vNumberRow) LisIsData->remove(vNumberRow); endInsertRows(); } void VectorTableModel::delColumn(const qint32 &vNumberCol) { beginInsertColumns(QModelIndex(), vNumberCol, vNumberCol); if(HeadersList->count() > vNumberCol) HeadersList->remove(vNumberCol); for(qint32 i= 0; i < LisIsData->count(); i++) LisIsData->at(i)->remove(vNumberCol); endInsertColumns(); }