Возможно, данная тема обсуждалась большое количество раз, но я не смог найти однозначного ответа и рабочей реализации задачи.
Имеется модель, унаследованная от QAbstractTableModel
. Модель редактируемая. Пользователь может изменять некоторые данные в ней, так же добавлять/удалять строки.
Источником данных выступает класс Scanner
для каждой строки. Данные в объекте изменяются внутри. Вообще это отображение данных api запросов
, но для примера написал некий счетчик, который обновляется по таймеру.
Scanner::Scanner(QObject * parent)
: QObject (parent)
{
auto timer = new QTimer();
connect(timer, &QTimer::timeout, this, [this] {
this->setDifference(getDifference() + 1);
emit dataChanged();
});
timer->start(1000);
}
Для каждой строки в view
создается отдельный объект Scanner
.
bool ScanningModel::insertRows(int position, int rows, const QModelIndex &parent)
{
beginInsertRows(parent, position, position + rows - 1);
for (int row = 0; row < rows; row++) {
auto scanner = new Scanner();
connect(scanner, &Scanner::dataChanged, this, [this] {
emit beginResetModel();
emit endResetModel();
}, Qt::QueuedConnection);
m_scanners.insert(position, scanner);
}
endInsertRows();
return true;
}
Собственно вопрос: как уведомить модель о том, что данные в Scanner
изменились и нужно их отобразить в view
?
Вариант с beginResetModel
и endResetModel
работает. Но при этом модель сбрасывается и выделенная строка в view
тоже. Т.е, чтобы внести изменения в строку через интерфейс, пользователю нужно успеть это сделать.
Для данной задачи предназначен сигнал в модели dataChanged
. Но для него нужно передавать QModelIndex
, которого нет в Scanner
и сам index
может изменится в любой момент (когда пользователь удалил/добавил новые строки).
В вашем коде вы уведомили модель о том, что данные изменились: вы соединили сигнал Scanner::dataChanged
с лямбда-слотом модели. Тут всё правильно. Стало быть, ваш вопрос в том, как уведомить представление о том, что данные изменились. И опять вы сами же ответили: сигналом dataChanged
модели. Осталось понять, как сформировать левый верхний и правый нижний индексы.
Сигнал dataChanged
имеет следующие параметры:
void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = ...)
Одним из способов решения (не буду утверждать, что самым оптимальным) будет добавить в класс Scanner
числовое поле, показывающее номер строки. Например, так:
class Scanner : public QObject {
Q_OBJECT
int m_rowNumber;
public:
int rowNumber();
void setRowNumber();
};
В модели при добавлении и удалении строк вам нужно будет правильно заполнять номер строк у созданных объектов, а также обновлять номера существующих объектов при их изменении. Когда вы это сделаете, у вас будут все необходимые данные для создания индекса. Тогда вы можете переписать ваш слот следующим образом:
connect(scanner, &Scanner::dataChanged, this, [this] {
Scanner *scanner = sender();//Возвращает объект, который отправил сигнал
dataChanged(index(scanner->rowNumber(), 0), index(scanner->rowNumber(), columnCount()));
}, Qt::QueuedConnection);
Я не проверял, будет ли работать метод sender
в лямбда-функции. Но если не будет, вы можете вынести её в отдельный слот.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Продолжаю пробовать перегружать операторы, и вновь не могу вызвать перегрузкуНапример, есть класс List:
Вызываю функцию которая рисует круги и почему то дорисовывает одну точку из центра и не как избавиться от этого "явления" не могу
Нужно получить клик только по контейнеруЕсли я произвожу клик по элементам внутри контейнера, то они тоже засчитываются
Подскажите пожалуйста как реализовать подобную структуру на django+jquery? modelspy