Qt5:如何改变table中一行的背景色,排序时自动移动?

Qt5: How to change background color of a row in a table and make it automatically move when sorting?

我有一个使用 QSqlTableModel 填充的 QTableView。
在此 table 中,我需要能够设置某些行的背景颜色(假设为黄色)(使用鼠标单击),以便在这些 "yellow-selected" 行上执行一些 post-processing。

我找到了一个看起来有点麻烦的解决方案...即我使用了一个代理模型并且我使用了 Qt::Background 角色来为行提供所需的背景颜色(黄色如果 "selected" 如果没有则为白色)。

它的工作可以接受(我注意到一些延迟 - 没什么大不了的),但我的实施存在问题:当我对 table 进行排序时(单击某些列 header) , "yellow-selected" 行不会根据排序操作改变它们的位置!...黄色行只是保持初始位置...

那么,有没有一种简单的方法可以做到这一点?也许使用代理模型不是最好的方法?!?如何/我该怎么做才能让它正确响应排序操作?

我是新手所以如果你也能提供一些代码就更好了,因为我是那种通过例子学习更好的人:)
我确实尝试了 2-3 天来解决这个问题,但我没能成功。不幸的是,互联网/谷歌搜索到目前为止没有帮助。

我在 Windows 7 下使用 Qt 5。

#include "keylistgenerator.h"
#include "ui_keylistgenerator.h"
#include "dataBase/database.h"


KeyListGenerator::KeyListGenerator(QWidget * parent) :
    QDialog(parent),
    ui(new Ui::KeyListGenerator)
{
    ui->setupUi(this);

    dbConnection = DataBase::instance()->openDataBaseConnection();

    model = new QSqlTableModel(this, QSqlDatabase::database(dbConnection));

    proxy = new ProxyModel(this);
    // unleash the power of proxy :)
    proxy->setSourceModel(model);

    model->setTable("MachineStatus");
    model->select();

    // display
    ui->tableView->setModel(proxy);
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tableView->setSelectionMode(QAbstractItemView::NoSelection);

    connect(ui->tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(toggleSelectCurrentRow(QModelIndex)));
    connect(ui->selectAllKeys, SIGNAL(clicked()), this, SLOT(setUpdateAllKeys()));
    connect(ui->cancelAllKeys, SIGNAL(clicked()), this, SLOT(cancelUpdateAllKeys()));
}

KeyListGenerator::~KeyListGenerator()
{
    delete ui;
}

void KeyListGenerator::toggleSelectCurrentRow(QModelIndex index)
{
    proxy->toggleRowSelection(index.row());
}

void KeyListGenerator::generateKeysListFile()
{
    // TODO...
}

void KeyListGenerator::setUpdateAllKeys()
{
    for(int i = 0; i < proxy->rowCount(); ++i)
    {
        proxy->setRowSelection(i);
    }
}

void KeyListGenerator::cancelUpdateAllKeys()
{
    for(int i = 0; i < proxy->rowCount(); ++i)
    {
        proxy->setRowSelection(i, false);
    }
}

好的,这是我的代理模型:

#include <QBrush>

#include "myproxymodel.h"


ProxyModel::ProxyModel(QObject * parent)
    : QAbstractProxyModel(parent)
{
}

ProxyModel::~ProxyModel()
{
}

int ProxyModel::rowCount(const QModelIndex & parent) const
{
    if(!parent.isValid())
        return sourceModel()->rowCount(QModelIndex());
    return 0;
}

int ProxyModel::columnCount(const QModelIndex & parent) const
{
    if(!parent.isValid())
        return sourceModel()->columnCount();
    return 0;
}

QModelIndex ProxyModel::index(int row, int column, const QModelIndex & parent) const
{
    if(!parent.isValid())
        return createIndex(row, column);
    return QModelIndex();
}

QModelIndex ProxyModel::parent(const QModelIndex & child) const
{
    return QModelIndex();
}

QModelIndex ProxyModel::mapToSource(const QModelIndex & proxyIndex) const
{
    if(!proxyIndex.isValid())
        return QModelIndex();
    return sourceModel()->index(proxyIndex.row(), proxyIndex.column());
}

QModelIndex ProxyModel::mapFromSource(const QModelIndex & sourceIndex) const
{
    if(!sourceIndex.isValid())
        return QModelIndex();
    return index(sourceIndex.row(), sourceIndex.column());
}

QVariant ProxyModel::data(const QModelIndex & index, int role) const
{
    if(role == Qt::BackgroundRole)
    {
        Qt::GlobalColor color = (map.value(index.row()) == true) ? Qt::yellow : Qt::white;
        QBrush background(color);
        return background;
    }

    return sourceModel()->data(mapToSource(index), role);
}

void ProxyModel::toggleRowSelection(int row)
{
    if(row < sourceModel()->rowCount())
    {
        // toggle status into ProxyModel for that row
        bool status = map.value(row) ^ 1;
        map.insert(row, status);

        QModelIndex first = createIndex(row, 0);
        QModelIndex last  = createIndex(row, sourceModel()->columnCount() - 1);

        emit dataChanged(first, last);
    }
}

void ProxyModel::setRowSelection(int row, bool selected)
{
    if(row < sourceModel()->rowCount())
    {
        // store selected status into ProxyModel for that row
        map.insert(row, selected);

        QModelIndex first = createIndex(row, 0);
        QModelIndex last  = createIndex(row, sourceModel()->columnCount() - 1);

        emit dataChanged(first, last);
    }
}

这是现在的样子...

你需要对模型的坚持。而您恰好使用了 QSqlTableModel... 因此,为了提供持久性,您需要修改模型(又名 MachineStatus table)以包含 "color" 属性.

正如你自己所说

in order to do some post-processing on these "yellow-selected" rows

您实际上正在对具有特定 属性 的项目进行一些 post 处理,并且您为它们着色这一事实意味着您正在修改名为 [=24] 的底层 属性 =]"will be post processed".

具体来说,这意味着放弃代理,将 QSqlTableModel 子类化为 QT QSqlTableModel - background color in a given data column 所描述的。此外,您还可以隐藏颜色栏。

您提出的解决方案是正确的,但存在一些问题。

排序由模型的 QSQLTableModel::sort() 以不保留索引的方式完成。即,sort() 重置模型,这意味着索引 are not valid anymore。您的代理人没有考虑到这一点。一旦 sort() 被视图调用,您的 map 就无效。

要解决该问题,您需要通过相关行的主键来跟踪选择。

QIdentityProxyModel 派生代理也更简单 - 然后您只需要覆盖 data() const 成员。

in this answer以及完整的工作示例

给出了使用主键作为选择索引的更多详细信息

如果您可以处理一个模型,该模型恰好提供了引用基础数据源的索引,尽管进行了排序。 QStringListModel就是这样的模型

#include <QApplication>
#include <QStringListModel>
#include <QTableView>

int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   auto data = QStringList() << "Foo" << "Baz" << "Bar" << "Car";
   QStringListModel model(data);
   QTableView view;

   view.setModel(&model);
   view.setEditTriggers(QAbstractItemView::NoEditTriggers);
   view.setSelectionMode(QAbstractItemView::MultiSelection);
   view.setSortingEnabled(true);

   app.setStyleSheet("QTableView { selection-background-color: yellow; selection-color: black; }");
   view.show();
   return app.exec();
}