问:如何在QAbstractItemModel中设置子表的标题?

Sco*_*ott 5 qt

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

Pav*_*hov 6

不幸的是,模型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;

};
Run Code Online (Sandbox Code Playgroud)

此代理模型使用源模型通过两个自定义角色提供的标头.例如,如果您使用QStandardItemModel,设置标题就像这样简单:

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

model.item(0, 1)对应的根项目在哪里.设置视图将如下所示:

QTableView view;
ChildHeadersProxy proxy;
proxy.setSourceModel(&model);
view.setModel(&proxy);
Run Code Online (Sandbox Code Playgroud)

并且更改根索引将如下所示:

view.setRootIndex(proxy.mapFromSource(model.index(0, 1)));
proxy.setRootIndex(model.index(0, 1));
Run Code Online (Sandbox Code Playgroud)