Qt: How to set the header for child tables in QAbstractItemModel?

QAbstractItemModel has a setHeaderData (int section, .....) method that accepts a section that is either a row or a column depending on the orientation of the header. I have a model containing several tables that are children of the top element. That is, the first level of my model hierarchy (under an invisible root) consists of 8 rows, each row has a child element, which is a table (a total of 8 tables, of course). SetHeaderData seems to provide heading views for the first level, but how to specify header data for these child tables? QTableView has a setRootIndex () method, so it can expand into the model hierarchy and display the data in these child tables, and I would expect setHeaderData to also get the root index, but that is not the case. I can set the title manually to QTableView,but this is much messy - is there a better solution?

+4
source share
1 answer

Unfortunately, the API model does not provide a good way to do this. The simplest solution is to make your model return different headerDatadepending on the root index used. However, this means that the model must know the state of the view (more precisely, the root index), which is not what you usually want.

I think installing a proxy model might be an elegant solution to this problem. Here's how to do it:

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;

};

This proxy model uses the headers provided by the source model through two user roles. For example, if you use QStandardItemModel, the header settings are simple:

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

where model.item(0, 1)is the corresponding root element. The view setup will look like this:

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

:

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

All Articles