Как исправить баг с цветовой индикацией строк QML TableView
У меня есть TableView и модель C ++, я также использую прокси-модель. Я хочу выделить строки разными цветами в зависимости от содержимого. Это хорошо работает, пока я не попытаюсь отсортировать модель. После сортировки строки остаются окрашенными как по старому индексу, так и по новому. Но после того, как делегат строки со старым индексом исчезает из поля зрения, он перестает окрашиваться. Мне приходится пролистывать таблицу, чтобы скрыть делегатов и изменить их цвет. Может нужно обновить вид? Но я не нашел для этого никаких способов. Как исправить эту ошибку? Вот ссылка на мой репозиторий git с минимальным воспроизводимым примером. Я вырезал часть кода из основного проекта, удалил всё лишнее и убедился что ошибка воспроизводится. github.com/Felinor/TableViewQML
Как воспроизвести баг: дважды щелкните заголовок для сортировки (вы увидите, что сортировка завершена, но старые строки все еще окрашены), затем прокрутите таблицу вниз и вы найдете две цветные отсортированные строки, затем снова прокрутите вверх и вы увидите, что две строки по старому индексу ошибочно окрашенные приобрели правильный окрас. Я действительно не знаю где искать причину бага.
Вот функция которую я использую для окрашивания строк, но я не думаю что проблема в ней.
function colorNotify() {
var key = proxyModel.get(styleData.row).dataNotification
if (key === "parameter 1")
return gradientAttention
else if (key === "parameter 10")
return gradientWarning
else if (delegateRow.hovered)
return gradientCurrentRow
return gradientNormal
}
Вот прокси модель, может быть баг кроется в ней.
#ifndef PROXYMODEL_H
#define PROXYMODEL_H
#include <QtCore/qsortfilterproxymodel.h>
#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qjsvalue.h>
#include <QtQml>
#include "model.h"
class SortFilterProxyModel : public QSortFilterProxyModel, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QObject *source READ source WRITE setSource)
Q_PROPERTY(QByteArray sortRole READ sortRole WRITE setSortRole)
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder)
Q_PROPERTY(QByteArray filterRole READ filterRole WRITE setFilterRole)
Q_PROPERTY(QString filterString READ filterString WRITE setFilterString)
Q_PROPERTY(FilterSyntax filterSyntax READ filterSyntax WRITE setFilterSyntax)
Q_ENUMS(FilterSyntax)
public:
explicit SortFilterProxyModel(QObject *parent = 0);
QObject *source() const;
void setSource(QObject *source);
QByteArray sortRole() const;
void setSortRole(const QByteArray &role);
void setSortOrder(Qt::SortOrder order);
QByteArray filterRole() const;
void setFilterRole(const QByteArray &role);
QString filterString() const;
void setFilterString(const QString &filter);
enum FilterSyntax {
RegExp,
Wildcard,
FixedString
};
FilterSyntax filterSyntax() const;
void setFilterSyntax(FilterSyntax syntax);
int count() const;
Q_INVOKABLE QJSValue get(int index) const;
Q_INVOKABLE void reserve(const int ¤tIndex);
Q_INVOKABLE QModelIndex getIndex(const int ¤tIndex);
void classBegin();
void componentComplete();
signals:
void countChanged();
protected:
int roleKey(const QByteArray &role) const;
QHash<int, QByteArray> roleNames() const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private:
bool m_complete;
QByteArray m_sortRole;
QByteArray m_filterRole;
QMap<QPersistentModelIndex, QPersistentModelIndex> mapping;
};
#endif // PROXYMODEL_H
#include "proxyModel.h"
SortFilterProxyModel::SortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_complete(false)
{
connect(this, &QSortFilterProxyModel::rowsInserted, this, &SortFilterProxyModel::countChanged);
connect(this, &QSortFilterProxyModel::rowsRemoved, this, &SortFilterProxyModel::countChanged);
}
int SortFilterProxyModel::count() const
{
return rowCount();
}
QObject *SortFilterProxyModel::source() const
{
return sourceModel();
}
void SortFilterProxyModel::setSource(QObject *source)
{
setSourceModel(qobject_cast<QAbstractItemModel *>(source));
}
QByteArray SortFilterProxyModel::sortRole() const
{
return m_sortRole;
}
void SortFilterProxyModel::setSortRole(const QByteArray &role)
{
if (m_sortRole != role) {
m_sortRole = role;
if (m_complete)
QSortFilterProxyModel::setSortRole(roleKey(role));
}
}
void SortFilterProxyModel::setSortOrder(Qt::SortOrder order)
{
QSortFilterProxyModel::sort(0, order);
}
QByteArray SortFilterProxyModel::filterRole() const
{
return m_filterRole;
}
void SortFilterProxyModel::setFilterRole(const QByteArray &role)
{
if (m_filterRole != role) {
m_filterRole = role;
if (m_complete)
QSortFilterProxyModel::setFilterRole(roleKey(role));
}
}
QString SortFilterProxyModel::filterString() const
{
return filterRegExp().pattern();
}
void SortFilterProxyModel::setFilterString(const QString &filter)
{
setFilterRegExp(QRegExp(filter, filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(filterSyntax())));
}
SortFilterProxyModel::FilterSyntax SortFilterProxyModel::filterSyntax() const
{
return static_cast<FilterSyntax>(filterRegExp().patternSyntax());
}
void SortFilterProxyModel::setFilterSyntax(SortFilterProxyModel::FilterSyntax syntax)
{
setFilterRegExp(QRegExp(filterString(), filterCaseSensitivity(), static_cast<QRegExp::PatternSyntax>(syntax)));
}
QJSValue SortFilterProxyModel::get(int idx) const
{
QJSEngine *engine = qmlEngine(this);
QJSValue value = engine->newObject();
if (idx >= 0 && idx < count()) {
QHash<int, QByteArray> roles = roleNames();
for (auto it = roles.cbegin(), end = roles.cend(); it != end; ++it)
value.setProperty(QString::fromUtf8(it.value()), data(index(idx, 0), it.key()).toString());
}
return value;
}
void SortFilterProxyModel::classBegin()
{
}
void SortFilterProxyModel::componentComplete()
{
m_complete = true;
if (!m_sortRole.isEmpty())
QSortFilterProxyModel::setSortRole(roleKey(m_sortRole));
if (!m_filterRole.isEmpty())
QSortFilterProxyModel::setFilterRole(roleKey(m_filterRole));
}
int SortFilterProxyModel::roleKey(const QByteArray &role) const
{
return roleNames().key(role, -1);
}
QHash<int, QByteArray> SortFilterProxyModel::roleNames() const
{
if (QAbstractItemModel *source = sourceModel())
return source->roleNames();
return QHash<int, QByteArray>();
}
bool SortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QRegExp rx = filterRegExp();
if (rx.isEmpty())
return true;
QAbstractItemModel *model = sourceModel();
if (filterRole().isEmpty()) {
QHash<int, QByteArray> roles = roleNames();
for (auto it = roles.cbegin(), end = roles.cend(); it != end; ++it) {
QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
QString key = model->data(sourceIndex, it.key()).toString();
if (key.contains(rx))
return true;
}
return false;
}
QModelIndex sourceIndex = model->index(sourceRow, 0, sourceParent);
if (!sourceIndex.isValid())
return true;
QString key = model->data(sourceIndex, roleKey(filterRole())).toString();
return key.contains(rx);
}
void SortFilterProxyModel::reserve(const int ¤tIndex)
{
QModelIndex proxyIndex = index(currentIndex, 0);
QModelIndex sourceIndex = mapToSource(proxyIndex);
DataModel *dataModel = dynamic_cast<DataModel*>(sourceModel());
dataModel->reserve(sourceIndex.row());
}
QModelIndex SortFilterProxyModel::getIndex(const int ¤tIndex)
{
//QModelIndex proxyIndex = index(currentIndex, 0);
//QModelIndex sourceIndex = mapToSource(proxyIndex);
//return sourceIndex;
DataModel *dataModel = dynamic_cast<DataModel*>(sourceModel());
return dataModel->index(currentIndex);
}