【问题标题】:Overriding QAbstractItemModel::index and accessing std::map覆盖 QAbstractItemModel::index 并访问 std::map
【发布时间】:2011-05-08 09:29:25
【问题描述】:

在我的程序中,我想将视图/模型模式与 view = QListView 和我自己的模型(我从 QAbstractListModel 子类化)一起使用。我的数据类看起来像

class Avtomat
{
...
 map<QString, State *> states;
...
};

在我的模型类中

class AvtomatModel : public QAbstractListModel
{
    ...
    Avtomat a;
    ...
};

我正在尝试重载 QAbstractItemView::index 函数,以便能够提供用于编辑数据映射的界面。 由于索引函数采用 int row 参数,我通过提供以下内容解决了该问题

State* Avtomat::pStateFromIndex(int index) const
{
    map<QString, State *>::const_iterator i;
    int count = 0;
    for (i = states.begin(); i != states.end() && count != index; ++i)
        ++count;
    return (*i).second;
}

所以在我的索引函数中我确实喜欢这样

return createIndex(row, column, a.pStateFromIndex(row));

但这看起来很丑,因为我有 O(n)。你能帮我设计一个更好的方法来使用 int index 访问我的地图吗?

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    这是一个基本的数据建模问题。您需要检索数据的主要方式是什么?按键还是按索引?

    如果您只通过索引(包括在模型中)访问它,那么您只是使用了不合适的数据结构,应该切换到其他东西,比如列表。

    如果您也确实需要按键查询,那么您有多种选择。如果效率不是一个巨大的驱动因素,那么你已经在做的事情没有错,尤其是在数据集很小的情况下。或者,您还可以维护与基础数据的键和索引映射。这是一个简单而有效的解决方案,但它意味着您必须承担管理两者之间一致性的责任,并且如果您的数据集很大,那么内存开销可能会很大。或者,您可以使用直接通过键和索引提供访问的数据结构。最终,这取决于您的具体情况和您正在使用的数据域。

    文档中有一个很好的 Qt 容器类(以及 std 容器)summary。 algorithmic complexity 部分可能对您来说特别有趣。

    【讨论】:

      【解决方案2】:

      另一种选择是使用向量将数据保存在键值对中。然后可以通过索引或键访问向量。 这样做的缺点是插入向量相对于 std::map 的开销很大。

      typedef std::pair<QString, State*> StateP;
      typedef std::vector<StateP> States;
      States states;
      

      然后根据比较第一个元素的谓词保持向量的排序顺序。您可以通过 O(1) 中的索引或 O(log n) 中的键来查找项目。

      struct StatePCompare {
          bool operator()(StateP const& lhs, StateP const& rhs) const {
              return (lhs.first < rhs.first);
          }
      };
      
      void Avtomat::insert(QString key, State* state) 
      {
          States::iterator i = std::lower_bound(states.begin(), states.end(), StatePCompare());
          if ((i != states.end() && (i->first == key)) {
              // key already exists, set the element
              i->second = state;
          }
          else {
              states.insert(i, state);
          }
      }
      
      State* Avtomat::find(QString key) 
      {
          States::iterator i = std::lower_bound(states.begin(), states.end(), StatePCompare());
          if ((i != states.end() && (i->first == key)) {
              return i->second;
          }
          return NULL;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        • 1970-01-01
        • 2012-03-07
        • 2022-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多