【问题标题】:Qt: How to set header on child tables in QAbstractItemModel?Qt:如何在 QAbstractItemModel 的子表上设置标题?
【发布时间】:2015-05-13 17:20:41
【问题描述】:

QAbstractItemModel 有一个 setHeaderData(int section, .....) 方法,该方法根据标题方向采用行或列的部分。我有一个模型,其中包含几个表,这些表都是顶级项目的子项。也就是说,我的模型层次结构的第一级(在不可见的根下)由 8 行组成,每行都有一个子元素,它是一个表(当然总共 8 个表)。看来 setHeaderData 将为视图提供第一级的标题,但是如何为这些子表指定标题数据? QTableView 有一个 setRootIndex() 方法,因此它可以深入模型层次结构并显示这些子表中的数据,我希望 setHeaderData 也采用根索引,但事实并非如此。我可以在 QTableView 上手动设置表头,但是这样比较麻烦——有没有更好的解决方案?

【问题讨论】:

    标签: qt


    【解决方案1】:

    很遗憾,模型 API 并没有提供很好的方法来做到这一点。最简单的解决方案是让您的模型根据当前使用的根索引返回不同的headerData。但是,这意味着模型需要知道视图的状态(更具体地说,是根索引),这不是您通常想要的。

    我认为设置代理模型可能是解决此问题的一种优雅方法。以下是它的实现方式:

    class ChildHeadersProxy : public QSortFilterProxyModel {
    public:
      static const int HorizontalHeaderRole = Qt::UserRole + 1;
      static const int VerticalHeaderRole = Qt::UserRole + 2;
    
      void setRootIndex(const QModelIndex& index) {
        m_rootIndex = index;
        if (sourceModel()) {
          emit headerDataChanged(Qt::Horizontal, 0, sourceModel()->columnCount(m_rootIndex));
          emit headerDataChanged(Qt::Vertical, 0, sourceModel()->rowCount(m_rootIndex));
        }
      }
    
      QVariant headerData(int section, Qt::Orientation orientation, 
                          int role = Qt::DisplayRole) const {
        if (sourceModel() && m_rootIndex.isValid()) {
          int role = orientation == Qt::Horizontal ? HorizontalHeaderRole : VerticalHeaderRole;
          QStringList headers = sourceModel()->data(m_rootIndex, role).toStringList();
          if (section >= 0 && section < headers.count()) {
            return headers[section];
          }
        }
        return QSortFilterProxyModel::headerData(section, orientation, role);
      }
    
    private:
      QModelIndex m_rootIndex;
    
    };
    

    此代理模型使用源模型通过两个自定义角色提供的标头。比如你使用QStandardItemModel,设置headers就这么简单:

    model.item(0, 1)->setData(QStringList() << "h1" << "h2", 
      ChildHeadersProxy::HorizontalHeaderRole);
    model.item(0, 1)->setData(QStringList() << "vh1" << "vh2", 
      ChildHeadersProxy::VerticalHeaderRole);
    

    其中model.item(0, 1) 是对应的根项。设置视图如下所示:

    QTableView view;
    ChildHeadersProxy proxy;
    proxy.setSourceModel(&model);
    view.setModel(&proxy);
    

    更改根索引将如下所示:

    view.setRootIndex(proxy.mapFromSource(model.index(0, 1)));
    proxy.setRootIndex(model.index(0, 1));
    

    【讨论】:

    • 我没有尝试过,但您的解决方案看起来不错——非常灵活。我认为对于我的应用程序,由于模型非常严格,因此只为表视图返回一个单独的标题模型会更简单。不过,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 2012-01-25
    • 1970-01-01
    • 2012-03-19
    相关资源
    最近更新 更多