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 view
和 the issue is the use of map.value(index.row())
不应该关联吗?以上是关于Qt5:如何改变表格中一行的背景颜色,使其在排序时自动移动?的主要内容,如果未能解决你的问题,请参考以下文章