如何在 Qt 的 QTableView 中显示一个简单的 QMap?
Posted
技术标签:
【中文标题】如何在 Qt 的 QTableView 中显示一个简单的 QMap?【英文标题】:How to display a simple QMap in a QTableView in Qt? 【发布时间】:2014-05-06 01:22:21 【问题描述】:我有一个名为map
的QMap
。我用数据库中的几行数据初始化了这个map
。现在我将这个map
发送到另一个包含 GUI 类的类。在我的 GUI 中,我有一个 TableView 项目。我需要在这个 TableView 中以任何顺序显示这个map
。
我见过几个例子,但它们都是针对一个只有一个字段的向量。他们使用另一个类来形成视图。我想知道是否有人以前这样做过并且可以帮助我。
【问题讨论】:
【参考方案1】:将QMap
包装在QAbstractTableModel
的子类中并将其设置为视图。下面是一个基本的功能示例:
文件“mapmodel.h”
#ifndef MAPMODEL_H
#define MAPMODEL_H
#include <QAbstractTableModel>
#include <QMap>
class MapModel : public QAbstractTableModel
Q_OBJECT
public:
enum MapRoles
KeyRole = Qt::UserRole + 1,
ValueRole
;
explicit MapModel(QObject *parent = 0);
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
inline void setMap(QMap<int, QString>* map) _map = map;
private:
QMap<int, QString>* _map;
;
#endif // MAPMODEL_H
文件“mapmodel.cpp”
#include "mapmodel.h"
MapModel::MapModel(QObject *parent) :
QAbstractTableModel(parent)
_map = NULL;
int MapModel::rowCount(const QModelIndex& parent) const
if (_map)
return _map->count();
return 0;
int MapModel::columnCount(const QModelIndex & parent) const
return 2;
QVariant MapModel::data(const QModelIndex& index, int role) const
if (!_map)
return QVariant();
if (index.row() < 0 ||
index.row() >= _map->count() ||
role != Qt::DisplayRole)
return QVariant();
if (index.column() == 0)
return _map->keys().at(index.row());
if (index.column() == 1)
return _map->values().at(index.row());
return QVariant();
使用示例:
// ...
QMap<int, QString> map;
map.insert(1, "value 1");
map.insert(2, "value 2");
map.insert(3, "value 3");
MapModel mapmodel;
mapmodel.setMap(&map);
YourTableView.setModel(&mapmodel);
// ...
它将显示如下填充的表格视图:
【讨论】:
你会想要在setMap
中执行beginModelReset()
和endModelReset()
我永远不建议这样做。 .keys() 和 .values() 的使用使得这非常非常低效。这两种方法都会创建一个新容器,然后将 all 数据复制到这个新容器中。更糟糕的是,这个新容器是一个 QList,它本身并不是一个有效的容器,只适用于少数类型。然后,您对经常调用的 data() 的每次调用执行此操作。所以请不要。高效的项目模型需要一个随机访问容器来支持它们。 std::vector 是您的首选。
@André,Bernard 正在寻找一种在 QTableView 中显示 QMap 的方法,这就是答案。我同意你在使用 .keys() 和 .values() 所引入的时间损失方面的观点,但这就是你在 QMap 中所拥有的一切。 QList 对于随机访问一点也不低效,QList 与 std::list 不同,它确实是基于常量时间索引的访问,如 std::vector。注意使用 at() 而不是 [] 以保证更好的性能。
@mhcuervo 不,这不是你所拥有的。您可以将数据复制到一个连续的容器中。您还可以在 QMap 中使用迭代器并将其推进到正确的行(并可能优化它以不总是从 begin() 开始,而是从最后使用的 begin() 或 end() 开始,具体取决于哪个最接近或类似的东西)。不理想,但比使用 .keys() 和 .values() 好得多。对于大多数类型,QList 是 pointers_to 堆分配值的连续容器。那根本没有有效。它正被 Qt6 逐步淘汰。
LOL @André 如果有人问如何折叠纸飞机,你告诉他们如何折叠纸飞机。极端地告诉他们最好用钢等其他材料制成,这样你就可以把人放进去有点过分了。所以我仍然相信 mhcuervo 为这个问题提供了一个非常简洁的答案被问到。记住这是一个分享和帮助的社区,而不是让其他人按照你希望他们做的方式做事。有时简单更好,即你不需要任何设计模式来制作一个 hello world 应用程序。做一个开发者分享不要强迫【参考方案2】:
正如@André 所说,依赖QMap
keys()
和values()
方法的解决方案根本没有效率,不应该使用。
您应该使用迭代器!
所以使用相同的 .h
#ifndef MAPMODEL_H
#define MAPMODEL_H
#include <QAbstractTableModel>
#include <QMap>
class MapModel : public QAbstractTableModel
Q_OBJECT
public:
enum MapRoles
KeyRole = Qt::UserRole + 1,
ValueRole
;
explicit MapModel(QObject *parent = 0);
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
void setMap(QMap<int, QString>* map);
private:
QMap<int, QString>* _map;
;
#endif // MAPMODEL_H
cpp 应该是这样的:
#include "mapmodel.h"
MapModel::MapModel(QObject *parent) :
QAbstractTableModel(parent), _map(nullptr)
void MapModel::setMap(QMap<int, QString>* map)
beginModelReset();
_map = map;
endModelReset();
int MapModel::rowCount(const QModelIndex& parent) const
if (_map)
return _map->count();
return 0;
int MapModel::columnCount(const QModelIndex & parent) const
return 2;
QVariant MapModel::data(const QModelIndex& index, int role) const
if (!_map || !index.isValid() || index.row() >= _map->count() || role != Qt::DisplayRole)
return QVariant();
auto it = _map.cbegin();
it += index.row();
if (index.column() == 0)
return it.key();
if (index.column() == 1)
return it.value();
return QVariant();
主要变化是在MapModel::data
中使用迭代器,正如@Claudiu 评论的那样,您必须在MapModel::setMap
中使用beginModelReset
和endModelReset
。 (让您能够更改模型上的地图并发出您的视图)
如果你想要一些例子,我已经在FamilyModel2
上为QAbstractListModel
完成了它。这里是the header、here the cpp。它使用了 Map 的包装器,您可以找到 here。
检查连接外部信号的构造函数FamilyModel2::FamilyModel2
,以便管理条目的插入,并在数据更新时发出dataChanged
;)
【讨论】:
以上是关于如何在 Qt 的 QTableView 中显示一个简单的 QMap?的主要内容,如果未能解决你的问题,请参考以下文章
如何在QTableView Qt C ++中将sqlite db数据显示为多列视图?
如何强制调整 indexWidgets 的大小以适合 Qt5 QTableView 的单元格