Qt5:如何改变表格中一行的背景颜色,使其在排序时自动移动?

Posted

技术标签:

【中文标题】Qt5:如何改变表格中一行的背景颜色,使其在排序时自动移动?【英文标题】:Qt5: How to change background color of a row in a table and make it automatically move when sorting? 【发布时间】:2015-06-18 21:01:37 【问题描述】:

我有一个使用 QSqlTableModel 填充的 QTableView。 在此表中,我需要能够设置某些行的背景颜色(比如说黄色)(使用鼠标单击),以便对这些“黄色选择”行进行一些后期处理。

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

它可以正常工作(我注意到一些延迟 - 没什么大不了的),但我的实现存在问题:当我对表格进行排序时(单击某个列标题),“黄色选中”行不会根据排序操作改变它们的位置!...黄色的行只是保持初始位置...

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

我是新手,所以如果您也可以提供一些代码,那就太好了,因为我是那种从示例中学习得更好的人:) 我确实尝试了 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);
    

这是现在的样子...

【问题讨论】:

我认为您需要使用更简单的模型,例如QStringListModel,并发布一个完整的(单个文件)示例来演示该行为。请参阅 this answer 和 this one 以获取有关使用模型和视图的简短单文件测试用例的外观的灵感。 Here 我描述了模型所期望的语义——可能你的代理模型破坏了其中的一些,如果没有看到代码就很难分辨! 您的示例应该有大约 100 行! 嗨,值得一提的是,我使用了 QSqlTableModel,因为表视图填充了来自 SQL 数据库表的数据... 嗯,我试图发布代码,但这样做似乎真的很痛苦!!!...编辑器抱怨格式化和添加 4 个空格?!?!这是我第一次看到这样的事情......从来没有在其他网站/论坛上遇到过类似的问题:(呵呵,终于做到了,花了很长时间......火箭科学:) 我将您的问题更改为使用代码示例而不是代码片段。片段适用于 javasrcipt 等可运行代码:blog.***.com/2014/09/… 我已将我的答案更新为another answer 的链接到一个几乎与此问题重复的问题,并包含一个完整的工作示例。 【参考方案1】:

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

排序由模型的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();

【讨论】:

【参考方案2】:

您需要模型中的持久性。而您恰好使用了QSqlTableModel...所以要提供持久性,您需要修改模型(又名MachineStatus 表)以包含"color" 属性。

正如你自己所说的

为了对这些“黄选”行做一些后期处理

您实际上是在对具有特定属性的项目进行一些后期处理,而为它们着色这一事实意味着您正在修改名为 “将被后期处理”的底层属性

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

【讨论】:

嗯,所以你的意思是如果我 sbclass QSqlTableModel (你引用的例子是列......)它将解决排序问题。我的意思是:它会持久吗?! 我认为模型中的持久性不是问题。它看起来像是视图和代理的一些交互。毕竟排序是由视图完成的。 @KubaOber 问题是使用map.value(index.row()) @UmNyobe 否。问题在别处。我错了,排序是由模型完成的,但代理的行为好像不是这样。 @KubaOber Your map is invalid as soon as sort() is called by the viewthe issue is the use of map.value(index.row()) 不应该关联吗?

以上是关于Qt5:如何改变表格中一行的背景颜色,使其在排序时自动移动?的主要内容,如果未能解决你的问题,请参考以下文章

给定背景颜色,如何获得使其在背景颜色上可读的前景色?

excel 在下拉时,如何使单元格背景色不变?

jsp 更改表格某行背景颜色。

如何设置鼠标经过时,改变背景颜色?

pygtk 更改 gtkHBox 小部件的背景颜色

如何通过内联 CSS 使 HTML 表格行背景通过悬停改变