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

我有一个名为mapQMap。我用数据库中的几行数据初始化了这个map。现在我将这个map 发送到另一个包含 GUI 类的类。在我的 GUI 中,我有一个 TableView 项目。我需要在这个 TableView 中以任何顺序显示这个map

我见过几个例子,但它们都是针对一个只有一个字段的向量。他们使用另一个类来形成视图。我想知道是否有人以前这样做过并且可以帮助我。

【问题讨论】:

    标签: c++ mysql qt user-interface qtableview


    【解决方案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 headerhere the cpp。它使用了 Map 的包装器,您可以找到 here。 检查连接外部信号的构造函数FamilyModel2::FamilyModel2,以便管理条目的插入,并在数据更新时发出dataChanged;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-13
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多