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();
}
我有一个使用 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();
}