在 QSqlQueryModel 中交换标题(转置表)
Posted
技术标签:
【中文标题】在 QSqlQueryModel 中交换标题(转置表)【英文标题】:Swapping headers in QSqlQueryModel (transpose table) 【发布时间】:2014-11-20 21:39:21 【问题描述】:我在正确转置从 db 收到的表时遇到问题。我遵循找到 here 的路径,并最终将 QAbstractProxyModel 子类化 - 就像描述的 here 一样。 不幸的是,它不能完全工作,问题出在:
我有什么:
X | A | B
----------
1 | A1 | B1
2 | A2 | B2
我想要什么:
X | 1 | 2
----------
A | A1 | A2
B | B1 | B2
我得到了什么:
X | 1 | 1
----------
A | A1 | A2
A | B1 | B2
如您所见,数据已正确转置,但标题变坏了......我真的需要它们:(
我尝试手动设置表头数据,也失败了:
origModel = new QSqlQueryModel; // set query and so on
transposedModel = new TransposeProxyModel;
transposedModel->setSourceModel(origModel );
for (int i = 0; i < origModel->columnCount(); i++)
qDebug() << "origModel->Qt::Horizontal(" << i << ")" << origModel->headerData(i, Qt::Horizontal, Qt::DisplayRole);
//transposedModel->setHeaderData(i, Qt::Vertical, origModel->headerData(i, Qt::Horizontal, Qt::DisplayRole), Qt::DisplayRole); //#try1
transposedModel->setHeaderData(i, Qt::Vertical, QVariant( "abc" ), Qt::DisplayRole); // #try2
无论我尝试 #1 还是 #2 - 调用 setHeaderData 的结果为 false...
有什么想法吗?
固定为@Vinícius Gobbo A. de Oliveira 指出的
【问题讨论】:
这里是深夜......但如果我没看错的话,你想要什么和你得到什么是一样的。也许你想检查一下;D 是的 - 我拼错了我实际取得的成绩。问题是,我在所有列(从第一列)和所有行(从第一行)中得到相同的标题。而且我无法更改它 - 甚至手动... 嘿,您帖子中的链接很遗憾已失效,您可以发布完整的工作代码以供将来参考吗? @i-know-nothing 查看已接受的答案 【参考方案1】:好吧,如果您使用链接的示例代码,您应该覆盖 TransposeProxyModel 类的 headerData 方法的默认定义,就像这样:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
return sourceModel()->headerData(section, (orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal), role);
忘记 setHeaderData 和 setData 方法吧:你想要一个依赖于原始模型的代理模型!
好吧,不知道到底出了什么问题,您使用的是哪个 Qt 版本?试试这段代码,它在这里完美运行:
#include <QtCore>
#include <QtWidgets>
class TransposeProxyModel: public QAbstractProxyModel
public:
TransposeProxyModel(QObject *p = 0):
QAbstractProxyModel(p)
QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const
return index(sourceIndex.column(), sourceIndex.row());
QModelIndex mapToSource ( const QModelIndex & proxyIndex ) const
return sourceModel()->index(proxyIndex.column(), proxyIndex.row());
QModelIndex index(int r, int c, const QModelIndex &ind=QModelIndex()) const
return createIndex(r,c);
QModelIndex parent(const QModelIndex&) const
return QModelIndex();
int rowCount(const QModelIndex &) const
return sourceModel()->columnCount();
int columnCount(const QModelIndex &) const
return sourceModel()->rowCount();
QVariant data(const QModelIndex &ind, int role) const
return sourceModel()->data(mapToSource(ind), role);
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const
return sourceModel()->headerData(section,
(orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal),
role);
;
int main(int argc, char *argv[])
QApplication a(argc, argv);
QStandardItemModel model(3,3);
model.setData(model.index(0,0), "1");
model.setData(model.index(0,1), "2");
model.setData(model.index(0,2), "3");
model.setData(model.index(1,0), "4");
model.setData(model.index(1,1), "5");
model.setData(model.index(1,2), "6");
model.setData(model.index(2,0), "7");
model.setData(model.index(2,1), "8");
model.setData(model.index(2,2), "9");
model.setHeaderData(0, Qt::Horizontal, "a");
model.setHeaderData(1, Qt::Horizontal, "b");
model.setHeaderData(2, Qt::Horizontal, "c");
TransposeProxyModel trans;
trans.setSourceModel(&model);
QSplitter split;
QTableView *t1 = new QTableView(&split);
t1->setModel(&model);
QTableView *t2 = new QTableView(&split);
t2->setModel(&trans);
split.show();
return a.exec();
大部分代码来自你提供的链接,我只是写了 headerData 方法。
【讨论】:
我试过这样做(写了相同的代码) - 没有帮助。我在里面放了一个刹车点——它永远不会触发。 天哪,我是个白痴...我的代码几乎相同...我在函数声明中错过了const
...【参考方案2】:
有趣的是 - doc 声明这是一个虚拟方法:
virtual QVariant headerData(int section, Qt::Orientationorientation, int 角色) const
(...)
QVariant QAbstractProxyModel::headerData(int section, Qt::Orientation 方向, int 角色) const [virtual]
从 QAbstractItemModel::headerData() 重新实现。
但在实际的标题中缺少virtual
关键字:
C:\Qt\Qt5.2.1\5.2.1\msvc2010\include\QtCore\qabstractproxymodel.h
(...)
QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const; //line76
QVariant headerData(int section, Qt::Orientation orientation, int role) const; //line77
我检查了正常的 Qt 目录,它也不见了:
C:\Qt\Qt5.2.1\5.2.1\Src\qtbase\src\corelib\itemmodels\qabstractproxymodel.h
(...)
QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
我做了一个测试:
sim = new QStandardItemModel (3,3);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++ )
sim->setData(sim->index(i,j), QString("%1%2").arg(QChar(j+65), QString().setNum(i+1)));
if (i==0)
sim->setHeaderData(j, Qt::Horizontal, QChar(j+65));
sim->setHeaderData(i, Qt::Vertical, i+1);
transposedModel = new TransposeProxyModel;
transposedModel->setSourceModel(sim);
QAbstractItemModel * aim = transposedModel;
QAbstractProxyModel *apm = transposedModel;
for (int i = 0; i < apm->rowCount(); i++)
qDebug() << "aim->Qt::Vertical(" << i << ")" << aim->headerData(i, Qt::Vertical, Qt::DisplayRole);
qDebug() << "apm->Qt::Vertical(" << i << ")" << apm->headerData(i, Qt::Vertical, Qt::DisplayRole);
qDebug() << "transposedModel->Qt::Vertical(" << i << ")" << transposedModel->headerData(i, Qt::Vertical, Qt::DisplayRole);
而调试是:
aim->Qt::Vertical( 0 ) QVariant(int, 1)
apm->Qt::Vertical( 0 ) QVariant(int, 1)
[ TransposeProxyModel::headerData ] //qDebug in TransposeProxyModel::headerData
transposedModel->Qt::Vertical( 0 ) QVariant(QChar, 'A')
aim->Qt::Vertical( 1 ) QVariant(int, 1)
apm->Qt::Vertical( 1 ) QVariant(int, 1)
[ TransposeProxyModel::headerData ] //qDebug in TransposeProxyModel::headerData
transposedModel->Qt::Vertical( 1 ) QVariant(QChar, 'B')
aim->Qt::Vertical( 2 ) QVariant(int, 1)
apm->Qt::Vertical( 2 ) QVariant(int, 1)
[ TransposeProxyModel::headerData ] //qDebug in TransposeProxyModel::headerData
transposedModel->Qt::Vertical( 2 ) QVariant(QChar, 'C')
所以我想这就是问题所在 - 该方法不是抽象的,这就是它不调用我的覆盖方法的原因。 Qt 错误?还是故意的?我也偷看了
C:\Qt\Qt5.2.1\5.2.1\Src\qtbase\src\corelib\itemmodels\qabstractproxymodel.cpp
/*!
\reimp
*/
QVariant QAbstractProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
Q_D(const QAbstractProxyModel);
int sourceSection;
if (orientation == Qt::Horizontal)
const QModelIndex proxyIndex = index(0, section);
sourceSection = mapToSource(proxyIndex).column();
else
const QModelIndex proxyIndex = index(section, 0);
sourceSection = mapToSource(proxyIndex).row();
return d->model->headerData(sourceSection, orientation, role);
我想它应该得到正确的标题 - 它调用 mapToSource,它是纯虚拟的,这应该获得正确的索引?
【讨论】:
在我的设置中,虚拟已经到位,来自 C:\Qt\Qt5.2.1\5.2.1\msvc2010_opengl\include\QtCore\qabstractitemmodel.h,第 188-189 行,它是:virtual QVariant headerData (int section, Qt::Orientationorientation, int role = Qt::DisplayRole) const... 非常好。 我拼错了文件名 - 请您检查一下 qabstractproxymodel.h 吗? 您好,它没有在 QAbstractProxyModel 中声明为 virtual,但它在 QAbstractItemModel 中,这是它的基类,所以一切都很好。 Didi,您尝试了我回答中的完整代码,我刚刚在这里检查了另一个 Qt 设置,它仍然可以正常工作。我认为你有正确的解决方案。 关于您的最后一个问题:默认实现在您的情况下无法正常工作,因为即使使用它的好方法来映射标题,就好像数据索引一样,它仍然在“搜索”原始模型与原始方向,而您必然需要交换水平和垂直数据寻址。以上是关于在 QSqlQueryModel 中交换标题(转置表)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 QSqlQueryModel 中获取硬编码 QCheckBoxes 的状态?
TableView 不会将 QSqlQueryModel 加载到其中
在带有 QSqlQueryModel 的 QListView 上使用 QStyledItemDelegate
编辑添加的数据到 sublcased QSqlQueryModel?