如何在 Qt 的 QTableView 中显示一个简单的 QMap?

Posted

技术标签:

【中文标题】如何在 Qt 的 QTableView 中显示一个简单的 QMap?【英文标题】:How to display a simple QMap in a QTableView in Qt? 【发布时间】:2014-05-06 01:22:21 【问题描述】:

我有一个名为mapQMap。我用数据库中的几行数据初始化了这个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 中使用beginModelResetendModelReset。 (让您能够更改模型上的地图并发出您的视图)

如果你想要一些例子,我已经在FamilyModel2 上为QAbstractListModel 完成了它。这里是the header、here the cpp。它使用了 Map 的包装器,您可以找到 here。 检查连接外部信号的构造函数FamilyModel2::FamilyModel2,以便管理条目的插入,并在数据更新时发出dataChanged;)

【讨论】:

以上是关于如何在 Qt 的 QTableView 中显示一个简单的 QMap?的主要内容,如果未能解决你的问题,请参考以下文章

如何在QTableView Qt C ++中将sqlite db数据显示为多列视图?

Qt:QTableView如何添加一行?

如何强制调整 indexWidgets 的大小以适合 Qt5 QTableView 的单元格

如何在 QTableView 的列中显示下拉列表并根据下拉列表进行过滤

QT中QTableview表中内容修改?

QT中QTableview表中内容修改?