QT的TableView实现多级表头

article/2025/8/26 11:29:55

QT的TableView实现多级表头

在这里插入图片描述

最近项目需要支持多级表头,QT本身不支持。可重写QHeaderView表头实现。
demo如下:

FSItemDelegate.h

#pragma once/*
自定义委托类
*/
#include <QItemDelegate>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QStandardItemModel>
#include <QLineEdit>
#include <QDebug>#define FS_WHITE_BRUSH QBrush((QColor(255, 255, 255)))
#define FS_RED_BRUSH QBrush((QColor(255, 0, 0)))
#define FS_GREEN_BRUSH QBrush((QColor(0, 255, 0)))enum class DELEGATE_TYPE
{READONLY,     //只读委托EDIDTEXT,     //可修改文本框委托COMBOBOX,     //组合框PASSWDLINE,   //密码修改框};
//  只读委托
class ReadOnlyDelegate : public QItemDelegate
{Q_OBJECTpublic:ReadOnlyDelegate(QObject *parent = 0) : QItemDelegate(parent) { }QWidget *createEditor(QWidget*parent, const QStyleOptionViewItem &option,const QModelIndex &index) const{return nullptr;}
};

MultistageHeader.h

#pragma once#include <QtWidgets/QMainWindow>
#include "ui_MultistageHeader.h"
#include "RbTableHeaderView.h"
#include "FSItemDelegate.h"
#include <QTableView>
#include <QHBoxLayout>
#include <QStandardItemModel>
#include "string"
#include <QString>
class MultistageHeader : public QWidget
{Q_OBJECTpublic:MultistageHeader(QWidget *parent = Q_NULLPTR);private:Ui::MultistageHeaderClass ui;RbTableHeaderView* m_pHeader;QStandardItemModel* m_pDataModel;QList<QStandardItem*> m_pVecItems;QTableView * m_pView;QHBoxLayout* m_pLayout = nullptr;QHBoxLayout* m_Hlayout;};

RbTableHeaderView.h

#ifndef RBTABLEHEADERVIEW_H_
#define RBTABLEHEADERVIEW_H_
#include <QHeaderView>
#include <QAbstractTableModel>
#include <QModelIndex>
#include <QHash>
#include <QPair>enum eRbHeaderRole
{COLUMN_SPAN_ROLE = Qt::UserRole + 1,ROW_SPAN_ROLE,COLUMN_SIZE_ROLE,ROW_SIZE_ROLE,
};class RbTableHeaderItem
{
public:RbTableHeaderItem(RbTableHeaderItem* parent = nullptr);RbTableHeaderItem(int arow, int acolumn, RbTableHeaderItem* parent = 0);virtual ~RbTableHeaderItem();// interfaceRbTableHeaderItem* insertChild(int row, int col);const RbTableHeaderItem* child(int row, int col) const;RbTableHeaderItem* child(int row, int col);void setData(const QVariant& data, int role);QVariant data(int role = Qt::UserRole + 1) const;inline int column() const { return column_prop; }inline int row() const { return row_prop; }RbTableHeaderItem* parent() { return parent_item; }void setText(const QString& text);void clear();private:// propertiesint row_prop;                                              //当前表格在表头中所在行int column_prop;                                           //当前表格在表头中所在行// inherent featuresRbTableHeaderItem* parent_item;QHash<QPair<int, int>, RbTableHeaderItem*> child_items;QHash<int, QVariant> role_datas;                           //
};class RbTableHeaderModel : public QAbstractTableModel
{Q_OBJECT
public:RbTableHeaderModel(int rows, int cols, QObject* parent = 0);virtual ~RbTableHeaderModel();public:// overridevirtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const Q_DECL_OVERRIDE;virtual int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE { Q_UNUSED(parent); return row_count_prop; }virtual int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE { Q_UNUSED(parent); return column_count_prop; }virtual QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) Q_DECL_OVERRIDE;virtual Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;private:// propertiesint row_count_prop;                    //表头行总数int column_count_prop;                 //表头列总数// inherent featuresRbTableHeaderItem* root_item;          //表头视图模型的根节点
};class RbTableHeaderView : public QHeaderView
{Q_OBJECT
public:RbTableHeaderView(Qt::Orientation orientation, int rows, int columns, QWidget* parent = 0);virtual ~RbTableHeaderView();void setRowHeight(int row, int rowHeight);void setColumnWidth(int col, int colWidth);void setSpan(int row, int column, int rowSpanCount, int columnSpanCount);void setCellBackgroundColor(const QModelIndex& index, const QColor&);void setCellForegroundColor(const QModelIndex& index, const QColor&);protected:// overridevirtual void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE;virtual QModelIndex indexAt(const QPoint&);virtual void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const Q_DECL_OVERRIDE;virtual QSize sectionSizeFromContents(int logicalIndex) const Q_DECL_OVERRIDE;// inherent featuresQModelIndex columnSpanIndex(const QModelIndex& currentIndex) const;QModelIndex rowSpanIndex(const QModelIndex& currentIndex) const;int columnSpanSize(int row, int from, int spanCount) const;int rowSpanSize(int column, int from, int spanCount) const;int getSectionRange(QModelIndex& index, int* beginSection, int* endSection) const;protected slots:void onSectionResized(int logicalIdx, int oldSize, int newSize);signals:void sectionPressed(int from, int to);
};#endif /* RBTABLEHEADERVIEW_H_ */

MultistageHeader.cpp

#include "MultistageHeader.h"MultistageHeader::MultistageHeader(QWidget *parent): QWidget(parent)
{ui.setupUi(this);m_pView = new QTableView(this);m_pView->setContextMenuPolicy(Qt::CustomContextMenu);connect(m_pView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tableContextMenuRequested(QPoint)));m_pHeader = new RbTableHeaderView(Qt::Horizontal, 3, 8, m_pView);QAbstractItemModel* pHeaderModel = m_pHeader->model();m_pHeader->setSpan(0, 0, 1, 4);m_pHeader->setSpan(0, 4, 1, 4);m_pHeader->setSpan(1, 0, 1, 2);m_pHeader->setSpan(1, 2, 1, 2);m_pHeader->setSpan(1, 4, 1, 2);m_pHeader->setSpan(1, 6, 1, 2);for (int i = 0; i < 8; i++){m_pHeader->setSpan(2, i, 1, 1);}//一级pHeaderModel->setData(pHeaderModel->index(0, 0), QString(u8"横向尺寸"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(0, 4), QString(u8"纵向尺寸"), Qt::DisplayRole);//二级pHeaderModel->setData(pHeaderModel->index(1, 0), QStringLiteral("极耳宽度"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(1, 2), QStringLiteral("极耳高度"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(1, 4), QStringLiteral("极片宽度"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(1, 6), QStringLiteral("极耳间距"), Qt::DisplayRole);//三级pHeaderModel->setData(pHeaderModel->index(2, 0), QStringLiteral("CCD测量值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 1), QStringLiteral("真值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 2), QStringLiteral("CCD测量值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 3), QStringLiteral("真值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 4), QStringLiteral("CCD测量值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 5), QStringLiteral("真值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 6), QStringLiteral("CCD测量值"), Qt::DisplayRole);pHeaderModel->setData(pHeaderModel->index(2, 7), QStringLiteral("真值"), Qt::DisplayRole);m_pHeader->setMinimumHeight(90);m_pHeader->setRowHeight(0, 30); m_pHeader->setRowHeight(1, 30);m_pHeader->setRowHeight(2, 30);//m_pHeader->setMinimumHeight(60);int a = m_pHeader->height();m_pHeader->setSectionsClickable(false);m_pHeader->setCellBackgroundColor(pHeaderModel->index(0, 0), 0xcfcfcf);m_pHeader->setCellBackgroundColor(pHeaderModel->index(0, 4), 0xcfcfcf);m_pHeader->setCellBackgroundColor(pHeaderModel->index(1, 0), 0xcfcfcf);m_pHeader->setCellBackgroundColor(pHeaderModel->index(1, 2), 0xcfcfcf);m_pHeader->setCellBackgroundColor(pHeaderModel->index(1, 4), 0xcfcfcf);m_pHeader->setCellBackgroundColor(pHeaderModel->index(1, 6), 0xcfcfcf);for (int i = 0; i < 8; i++){m_pHeader->setCellBackgroundColor(pHeaderModel->index(2, i), 0xcfcfcf);}int rowCount = 10;m_pDataModel = new QStandardItemModel;for (int i = 0; i < rowCount; i++){QList<QStandardItem*> items;for (int j = 0; j < 8; j++){items.append(new QStandardItem);m_pVecItems.append(items[j]);}m_pDataModel->appendRow(items);}m_pView->setModel(m_pDataModel);m_pView->setHorizontalHeader(m_pHeader);ReadOnlyDelegate *readonlydelegate = new ReadOnlyDelegate();m_pView->setItemDelegateForColumn(0, readonlydelegate);m_pView->setItemDelegateForColumn(2, readonlydelegate);m_pView->setItemDelegateForColumn(4, readonlydelegate);m_pView->setItemDelegateForColumn(6, readonlydelegate);if (!m_pLayout){m_pLayout = new QHBoxLayout(this);this->setLayout(m_pLayout);}m_pLayout->addWidget(m_pView);
}

RbTableHeaderView.cpp

#include "RbTableHeaderView.h"
#include <QPainter>
#include <QStandardItem>
#include <QMouseEvent>
#include <QVariant>
#include <QBrush>
#include <qdrawutil.h>
#include <QList>
#include <QDebug>RbTableHeaderItem::RbTableHeaderItem(RbTableHeaderItem* parent):row_prop(0),column_prop(0),parent_item(parent)
{
}RbTableHeaderItem::RbTableHeaderItem(int arow, int acolumn, RbTableHeaderItem* parent):row_prop(arow),column_prop(acolumn),parent_item(parent)
{
}RbTableHeaderItem::~RbTableHeaderItem()
{qDebug() << "~RbTableHeaderItem()" << endl;clear();
}RbTableHeaderItem* RbTableHeaderItem::insertChild(int row, int col)
{RbTableHeaderItem* newChild = new RbTableHeaderItem(row, col, this);child_items.insert(QPair<int, int>(row, col), newChild);return newChild;
}const RbTableHeaderItem* RbTableHeaderItem::child(int row, int col) const
{QHash<QPair<int, int>, RbTableHeaderItem*>::const_iterator itr = child_items.find(QPair<int, int>(row, col));if (itr != child_items.end()) return itr.value();return nullptr;
}RbTableHeaderItem* RbTableHeaderItem::child(int row, int col)
{QHash<QPair<int, int>, RbTableHeaderItem*>::iterator itr = child_items.find(QPair<int, int>(row, col));if (itr != child_items.end()) return itr.value();return nullptr;
}void RbTableHeaderItem::setText(const QString& text)
{role_datas.insert(Qt::DisplayRole, text);
}void RbTableHeaderItem::clear()
{QList<RbTableHeaderItem*> items = child_items.values();foreach(RbTableHeaderItem* item, items){if (item) delete item;item = nullptr;}child_items.clear();
}QVariant RbTableHeaderItem::data(int role) const
{QHash<int, QVariant>::const_iterator itr = role_datas.find(role);if (itr != role_datas.end()) return itr.value();return QVariant();
}void RbTableHeaderItem::setData(const QVariant& data, int role)
{role_datas.insert(role, data);
}RbTableHeaderModel::RbTableHeaderModel(int rows, int cols, QObject* parent) :
QAbstractTableModel(parent),row_count_prop(rows),column_count_prop(cols),root_item(new RbTableHeaderItem())
{
}RbTableHeaderModel::~RbTableHeaderModel()
{qDebug() << "~RbTableHeaderModel()" << endl;root_item->clear();delete root_item;root_item = nullptr;
}QModelIndex RbTableHeaderModel::index(int row, int column, const QModelIndex & parent) const
{if (!hasIndex(row, column, parent)) return QModelIndex();RbTableHeaderItem* parentItem;if (!parent.isValid()) parentItem = root_item; // parent item is always the root_item on table modelelse parentItem = static_cast<RbTableHeaderItem*>(parent.internalPointer()); // no effectRbTableHeaderItem* childItem = parentItem->child(row, column);if (!childItem) childItem = parentItem->insertChild(row, column);return createIndex(row, column, childItem);return QModelIndex();
}QVariant RbTableHeaderModel::data(const QModelIndex& index, int role) const
{if (!index.isValid())return QVariant();if (index.row() >= row_count_prop || index.row() < 0 || index.column() >= column_count_prop || index.column() < 0)return QVariant();RbTableHeaderItem* item = static_cast<RbTableHeaderItem*>(index.internalPointer());return item->data(role);
}bool RbTableHeaderModel::setData(const QModelIndex & index, const QVariant & value, int role)
{if (index.isValid()){RbTableHeaderItem* item = static_cast<RbTableHeaderItem*>(index.internalPointer());if (role == COLUMN_SPAN_ROLE){int col = index.column();int span = value.toInt();if (span > 0) // span size should be more than 1, else nothing to do{if (col + span - 1 >= column_count_prop) // span size should be less than whole columns,span = column_count_prop - col;item->setData(span, COLUMN_SPAN_ROLE);}}else if (role == ROW_SPAN_ROLE){int row = index.row();int span = value.toInt();if (span > 0) // span size should be more than 1, else nothing to do{if (row + span - 1 >= row_count_prop)span = row_count_prop - row;item->setData(span, ROW_SPAN_ROLE);}}elseitem->setData(value, role);return true;}return false;
}Qt::ItemFlags RbTableHeaderModel::flags(const QModelIndex &index) const
{if (!index.isValid())return Qt::ItemIsEnabled;return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}RbTableHeaderView::RbTableHeaderView(Qt::Orientation orientation, int rows, int columns, QWidget* parent) :QHeaderView(orientation, parent)
{QSize baseSectionSize;if (orientation == Qt::Horizontal){baseSectionSize.setWidth(defaultSectionSize());baseSectionSize.setHeight(20);}else{baseSectionSize.setWidth(50);baseSectionSize.setHeight(defaultSectionSize());}// create header modelRbTableHeaderModel* headerModel = new RbTableHeaderModel(rows, columns);// set default size of itemfor (int row = 0; row < rows; ++row)for (int col = 0; col < columns; ++col)headerModel->setData(headerModel->index(row, col), baseSectionSize, Qt::SizeHintRole);setModel(headerModel);connect(this, SIGNAL(sectionResized(int, int, int)), this, SLOT(onSectionResized(int, int, int)));
}RbTableHeaderView::~RbTableHeaderView()
{qDebug() << "~RbTableHeaderView()" << endl;RbTableHeaderModel* md = qobject_cast<RbTableHeaderModel*>(model());if (md) delete md;setModel(nullptr);
}void RbTableHeaderView::setRowHeight(int row, int rowHeight)
{RbTableHeaderModel* md = qobject_cast<RbTableHeaderModel*>(model());const int cols = md->columnCount();for (int col = 0; col < cols; ++col){QSize sz = md->index(row, col).data(Qt::SizeHintRole).toSize();sz.setHeight(rowHeight);md->setData(md->index(row, col), sz, Qt::SizeHintRole);}if (orientation() == Qt::Vertical)resizeSection(row, rowHeight);
}void RbTableHeaderView::setColumnWidth(int col, int colWidth)
{RbTableHeaderModel* md = qobject_cast<RbTableHeaderModel*>(model());const int rows = md->rowCount();for (int row = 0; row < rows; ++row){QSize sz = md->index(row, col).data(Qt::SizeHintRole).toSize();sz.setWidth(colWidth);md->setData(md->index(row, col), sz, Qt::SizeHintRole);}if (orientation() == Qt::Horizontal)resizeSection(col, colWidth);
}void RbTableHeaderView::setSpan(int row, int column, int rowSpanCount, int columnSpanCount)
{RbTableHeaderModel* md = qobject_cast<RbTableHeaderModel*>(model());QModelIndex idx = md->index(row, column);if (rowSpanCount > 0)md->setData(idx, rowSpanCount, ROW_SPAN_ROLE);if (columnSpanCount)md->setData(idx, columnSpanCount, COLUMN_SPAN_ROLE);
}void RbTableHeaderView::setCellBackgroundColor(const QModelIndex& index, const QColor& color)
{RbTableHeaderModel* md = qobject_cast<RbTableHeaderModel*>(model());md->setData(index, color, Qt::BackgroundRole);
}void RbTableHeaderView::setCellForegroundColor(const QModelIndex& index, const QColor& color)
{RbTableHeaderModel* md = qobject_cast<RbTableHeaderModel*>(model());md->setData(index, color, Qt::ForegroundRole);
}void RbTableHeaderView::mousePressEvent(QMouseEvent* event)
{QHeaderView::mousePressEvent(event);QPoint pos = event->pos();QModelIndex index = indexAt(pos);const int OTN = orientation();if (index.isValid()){int beginSection = -1;int endSection = -1;int numbers = 0;numbers = getSectionRange(index, &beginSection, &endSection);if (numbers > 0){emit sectionPressed(beginSection, endSection);return;}else{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(this->model());const int LEVEL_CNT = (OTN == Qt::Horizontal) ? tblModel->rowCount() : tblModel->columnCount();int logicalIdx = (OTN == Qt::Horizontal) ? index.column() : index.row();int curLevel = (OTN == Qt::Horizontal) ? index.row() : index.column();for (int i = 0; i < LEVEL_CNT; ++i){QModelIndex cellIndex = (OTN == Qt::Horizontal) ? tblModel->index(i, logicalIdx) : tblModel->index(logicalIdx, i);numbers = getSectionRange(cellIndex, &beginSection, &endSection);if (numbers > 0){if (beginSection <= logicalIdx && logicalIdx <= endSection){int beginLevel = (OTN == Qt::Horizontal) ? cellIndex.row() : cellIndex.column();QVariant levelSpanCnt = cellIndex.data((OTN == Qt::Horizontal) ? ROW_SPAN_ROLE : COLUMN_SPAN_ROLE);if (!levelSpanCnt.isValid())continue;int endLevel = beginLevel + levelSpanCnt.toInt() - 1;if (beginLevel <= curLevel && curLevel <= endLevel){emit sectionPressed(beginSection, endSection);break;}}}}}}
}QModelIndex RbTableHeaderView::indexAt(const QPoint& pos)
{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(this->model());const int OTN = orientation();const int ROWS = tblModel->rowCount();const int COLS = tblModel->columnCount();int logicalIdx = logicalIndexAt(pos);if (OTN == Qt::Horizontal){int dY = 0;for (int row = 0; row < ROWS; ++row){QModelIndex cellIndex = tblModel->index(row, logicalIdx);dY += cellIndex.data(Qt::SizeHintRole).toSize().height();if (pos.y() <= dY) return cellIndex;}}else{int dX = 0;for (int col = 0; col < COLS; ++col){QModelIndex cellIndex = tblModel->index(logicalIdx, col);dX += cellIndex.data(Qt::SizeHintRole).toSize().width();if (pos.x() <= dX) return cellIndex;}}return QModelIndex();
}void RbTableHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIdx) const
{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(this->model());               //表头视图模型const int OTN = orientation();                                                                       //获取表头方向const int LEVEL_CNT = (OTN == Qt::Horizontal) ? tblModel->rowCount() : tblModel->columnCount();      //获取列数或者行数for (int i = 0; i < LEVEL_CNT; ++i){QModelIndex cellIndex = (OTN == Qt::Horizontal) ? tblModel->index(i, logicalIdx) : tblModel->index(logicalIdx, i);QSize cellSize = cellIndex.data(Qt::SizeHintRole).toSize();QRect sectionRect(rect);// set position of the cellif (OTN == Qt::Horizontal)sectionRect.setTop(rowSpanSize(logicalIdx, 0, i)); // distance from 0 to i-1 rowselsesectionRect.setLeft(columnSpanSize(logicalIdx, 0, i));sectionRect.setSize(cellSize);// check up span column or rowQModelIndex colSpanIdx = columnSpanIndex(cellIndex);QModelIndex rowSpanIdx = rowSpanIndex(cellIndex);if (colSpanIdx.isValid()){int colSpanFrom = colSpanIdx.column();int colSpanCnt = colSpanIdx.data(COLUMN_SPAN_ROLE).toInt();int colSpanTo = colSpanFrom + colSpanCnt - 1;int colSpan = columnSpanSize(cellIndex.row(), colSpanFrom, colSpanCnt);if (OTN == Qt::Horizontal)sectionRect.setLeft(sectionViewportPosition(colSpanFrom));else{sectionRect.setLeft(columnSpanSize(logicalIdx, 0, colSpanFrom));i = colSpanTo;}sectionRect.setWidth(colSpan);// check up  if the column span index has row spanQVariant subRowSpanData = colSpanIdx.data(ROW_SPAN_ROLE);if (subRowSpanData.isValid()){int subRowSpanFrom = colSpanIdx.row();int subRowSpanCnt = subRowSpanData.toInt();int subRowSpanTo = subRowSpanFrom + subRowSpanCnt - 1;int subRowSpan = rowSpanSize(colSpanFrom, subRowSpanFrom, subRowSpanCnt);if (OTN == Qt::Vertical)sectionRect.setTop(sectionViewportPosition(subRowSpanFrom));else{sectionRect.setTop(rowSpanSize(colSpanFrom, 0, subRowSpanFrom));i = subRowSpanTo;}sectionRect.setHeight(subRowSpan);}cellIndex = colSpanIdx;}if (rowSpanIdx.isValid()){int rowSpanFrom = rowSpanIdx.row();int rowSpanCnt = rowSpanIdx.data(ROW_SPAN_ROLE).toInt();int rowSpanTo = rowSpanFrom + rowSpanCnt - 1;int rowSpan = rowSpanSize(cellIndex.column(), rowSpanFrom, rowSpanCnt);if (OTN == Qt::Vertical)sectionRect.setTop(sectionViewportPosition(rowSpanFrom));else{sectionRect.setTop(rowSpanSize(logicalIdx, 0, rowSpanFrom));i = rowSpanTo;}sectionRect.setHeight(rowSpan);// check up if the row span index has column spanQVariant subColSpanData = rowSpanIdx.data(COLUMN_SPAN_ROLE);if (subColSpanData.isValid()){int subColSpanFrom = rowSpanIdx.column();int subColSpanCnt = subColSpanData.toInt();int subColSpanTo = subColSpanFrom + subColSpanCnt - 1;int subColSpan = columnSpanSize(rowSpanFrom, subColSpanFrom, subColSpanCnt);if (OTN == Qt::Horizontal)sectionRect.setLeft(sectionViewportPosition(subColSpanFrom));else{sectionRect.setLeft(columnSpanSize(rowSpanFrom, 0, subColSpanFrom));i = subColSpanTo;}sectionRect.setWidth(subColSpan);}cellIndex = rowSpanIdx;}// draw section with styleQStyleOptionHeader sectionStyle;initStyleOption(&sectionStyle);sectionStyle.textAlignment = Qt::AlignCenter;sectionStyle.iconAlignment = Qt::AlignVCenter;sectionStyle.section = logicalIdx;sectionStyle.text = cellIndex.data(Qt::DisplayRole).toString();sectionStyle.rect = sectionRect;// file background or foreground color of the cellQVariant bg = cellIndex.data(Qt::BackgroundRole);QVariant fg = cellIndex.data(Qt::ForegroundRole);if (bg.canConvert(QVariant::Brush)){sectionStyle.palette.setBrush(QPalette::Button, qvariant_cast<QBrush>(bg));sectionStyle.palette.setBrush(QPalette::Window, qvariant_cast<QBrush>(bg));}if (fg.canConvert(QVariant::Brush)){sectionStyle.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(fg));}painter->save();qDrawShadePanel(painter, sectionStyle.rect, sectionStyle.palette, false, 1, &sectionStyle.palette.brush(QPalette::Button));style()->drawControl(QStyle::CE_HeaderLabel, &sectionStyle, painter);painter->restore();}
}QSize RbTableHeaderView::sectionSizeFromContents(int logicalIndex) const
{const RbTableHeaderModel* tblModel = qobject_cast<const RbTableHeaderModel*>(this->model());const int OTN = orientation();const int LEVEL_CNT = (OTN == Qt::Horizontal) ? tblModel->rowCount() : tblModel->columnCount();QSize siz = QHeaderView::sectionSizeFromContents(logicalIndex);for (int i = 0; i < LEVEL_CNT; ++i){QModelIndex cellIndex = (OTN == Qt::Horizontal) ? tblModel->index(i, logicalIndex) : tblModel->index(logicalIndex, i);QModelIndex colSpanIdx = columnSpanIndex(cellIndex);QModelIndex rowSpanIdx = rowSpanIndex(cellIndex);siz = cellIndex.data(Qt::SizeHintRole).toSize();if (colSpanIdx.isValid()){int colSpanFrom = colSpanIdx.column();int colSpanCnt = colSpanIdx.data(COLUMN_SPAN_ROLE).toInt();int colSpanTo = colSpanFrom + colSpanCnt - 1;siz.setWidth(columnSpanSize(colSpanIdx.row(), colSpanFrom, colSpanCnt));if (OTN == Qt::Vertical) i = colSpanTo;}if (rowSpanIdx.isValid()){int rowSpanFrom = rowSpanIdx.row();int rowSpanCnt = rowSpanIdx.data(ROW_SPAN_ROLE).toInt();int rowSpanTo = rowSpanFrom + rowSpanCnt - 1;siz.setHeight(rowSpanSize(rowSpanIdx.column(), rowSpanFrom, rowSpanCnt));if (OTN == Qt::Horizontal) i = rowSpanTo;}}return siz;
}QModelIndex RbTableHeaderView::columnSpanIndex(const QModelIndex& currentIdx) const
{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(model());const int curRow = currentIdx.row();const int curCol = currentIdx.column();int i = curCol;while (i >= 0){QModelIndex spanIndex = tblModel->index(curRow, i);QVariant span = spanIndex.data(COLUMN_SPAN_ROLE);if (span.isValid() && spanIndex.column() + span.toInt() - 1 >= curCol)return spanIndex;i--;}return QModelIndex();
}QModelIndex RbTableHeaderView::rowSpanIndex(const QModelIndex& currentIdx) const
{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(model());const int curRow = currentIdx.row();const int curCol = currentIdx.column();int i = curRow;while (i >= 0){QModelIndex spanIndex = tblModel->index(i, curCol);QVariant span = spanIndex.data(ROW_SPAN_ROLE);if (span.isValid() && spanIndex.row() + span.toInt() - 1 >= curRow)return spanIndex;i--;}return QModelIndex();
}int RbTableHeaderView::columnSpanSize(int row, int from, int spanCount) const
{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(model());int span = 0;for (int i = from; i < from + spanCount; ++i){QSize cellSize = tblModel->index(row, i).data(Qt::SizeHintRole).toSize();span += cellSize.width();}return span;
}int RbTableHeaderView::rowSpanSize(int column, int from, int spanCount) const
{const RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(model());int span = 0;for (int i = from; i < from + spanCount; ++i){QSize cellSize = tblModel->index(i, column).data(Qt::SizeHintRole).toSize();span += cellSize.height();}return span;
}/*** @return section numbers*/
int RbTableHeaderView::getSectionRange(QModelIndex& index, int* beginSection, int* endSection) const
{// check up section range from the indexQModelIndex colSpanIdx = columnSpanIndex(index);QModelIndex rowSpanIdx = rowSpanIndex(index);if (colSpanIdx.isValid()){int colSpanFrom = colSpanIdx.column();int colSpanCnt = colSpanIdx.data(COLUMN_SPAN_ROLE).toInt();int colSpanTo = colSpanFrom + colSpanCnt - 1;if (orientation() == Qt::Horizontal){*beginSection = colSpanFrom;*endSection = colSpanTo;index = colSpanIdx;return colSpanCnt;}else{// check up  if the column span index has row spanQVariant subRowSpanData = colSpanIdx.data(ROW_SPAN_ROLE);if (subRowSpanData.isValid()){int subRowSpanFrom = colSpanIdx.row();int subRowSpanCnt = subRowSpanData.toInt();int subRowSpanTo = subRowSpanFrom + subRowSpanCnt - 1;*beginSection = subRowSpanFrom;*endSection = subRowSpanTo;index = colSpanIdx;return subRowSpanCnt;}}}if (rowSpanIdx.isValid()){int rowSpanFrom = rowSpanIdx.row();int rowSpanCnt = rowSpanIdx.data(ROW_SPAN_ROLE).toInt();int rowSpanTo = rowSpanFrom + rowSpanCnt - 1;if (orientation() == Qt::Vertical){*beginSection = rowSpanFrom;*endSection = rowSpanTo;index = rowSpanIdx;return rowSpanCnt;}else{// check up if the row span index has column spanQVariant subColSpanData = rowSpanIdx.data(COLUMN_SPAN_ROLE);if (subColSpanData.isValid()){int subColSpanFrom = rowSpanIdx.column();int subColSpanCnt = subColSpanData.toInt();int subColSpanTo = subColSpanFrom + subColSpanCnt - 1;*beginSection = subColSpanFrom;*endSection = subColSpanTo;index = rowSpanIdx;return subColSpanCnt;}}}return 0;
}void RbTableHeaderView::onSectionResized(int logicalIndex, int oldSize, int newSize)
{RbTableHeaderModel* tblModel = qobject_cast<RbTableHeaderModel*>(this->model());const int OTN = orientation();const int LEVEL_CNT = (OTN == Qt::Horizontal) ? tblModel->rowCount() : tblModel->columnCount();int pos = sectionViewportPosition(logicalIndex);int xx = (OTN == Qt::Horizontal) ? pos : 0;int yy = (OTN == Qt::Horizontal) ? 0 : pos;QRect sectionRect(xx, yy, 0, 0);for (int i = 0; i < LEVEL_CNT; ++i){QModelIndex cellIndex = (OTN == Qt::Horizontal) ? tblModel->index(i, logicalIndex) : tblModel->index(logicalIndex, i);QSize cellSize = cellIndex.data(Qt::SizeHintRole).toSize();// set position of cellif (OTN == Qt::Horizontal){sectionRect.setTop(rowSpanSize(logicalIndex, 0, i));cellSize.setWidth(newSize);}else{sectionRect.setLeft(columnSpanSize(logicalIndex, 0, i));cellSize.setHeight(newSize);}tblModel->setData(cellIndex, cellSize, Qt::SizeHintRole);QModelIndex colSpanIdx = columnSpanIndex(cellIndex);QModelIndex rowSpanIdx = rowSpanIndex(cellIndex);if (colSpanIdx.isValid()){int colSpanFrom = colSpanIdx.column();if (OTN == Qt::Horizontal)sectionRect.setLeft(sectionViewportPosition(colSpanFrom));else{sectionRect.setLeft(columnSpanSize(logicalIndex, 0, colSpanFrom));}}if (rowSpanIdx.isValid()){int rowSpanFrom = rowSpanIdx.row();if (OTN == Qt::Vertical)sectionRect.setTop(sectionViewportPosition(rowSpanFrom));elsesectionRect.setTop(rowSpanSize(logicalIndex, 0, rowSpanFrom));}QRect rToUpdate(sectionRect);rToUpdate.setWidth(viewport()->width() - sectionRect.left());rToUpdate.setHeight(viewport()->height() - sectionRect.top());viewport()->update(rToUpdate.normalized());}
}

main.cpp

#include "MultistageHeader.h"
#include <QtWidgets/QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MultistageHeader w;w.show();return a.exec();
}

http://chatgpt.dhexx.cn/article/3c1nSrAo.shtml

相关文章

QML类型:TableView

一、描述 TableView 显示从内置 QML 类型&#xff08;如 ListModel 和 XmlListModel&#xff09;创建的模型中的数据&#xff0c;这些模型仅填充 TableView 中的第一列。要创建具有多列的模型&#xff0c;请使用 TableModel 或继承 QAbstractItemModel 的 C 模型。 TableView…

QML TableView表格使用示例

前言 QML中实现表格可以使用多种方式&#xff0c;比如直接使用ListView&#xff0c;定义每一行delegate&#xff0c;或者自定义Rectangle&#xff0c;放到Flipable中组合使用。Qt Quick Control1中 从5.1版本开始就提供了表格控件&#xff0c;但是感觉不怎么好用&#xff0c;在…

Qt TableView的简单使用

软件环境&#xff1a; ubuntu -------------------------------------------------------------------------------------------------------- 最终效果图&#xff1a; --------------------------------------------------------------------------------------------------…

PyQt5 TableView组件

一、话不多说&#xff0c;先看图 本次要实现的是主窗口内添加widget组件&#xff0c;widget内设置成垂直盒布局&#xff0c;然后在布局中添加tableView、PushButton组件 二、看main函数 if __name__ __main__:app QApplication(sys.argv)# 现在这创建 主窗口 &#xff08;不然…

优雅的开发TableView

前言 UITableView&#xff08;UITableViewController&#xff09;是iOS开发使用频率最高的一个组件。 不管是使用UITableView还是还是UITableViewController&#xff0c;在开发的时候&#xff0c;我们都需要实现两个协议&#xff1a; UITableViewControllerDataSourceUITabl…

JavaFX控件——TableView

在JavaFX 应用中对创建表格最重要的是TableView, TableColumn和TableCell这三个类。 你可以通过实现数据模型&#xff08;data model&#xff09; 和 实现 单元格工厂(cell factory) 来填充表格。 表格类提供了表格列嵌入式的排序能力和必要时调整列宽度的功能。 下面开始学…

ios开发:多个Section的TableView

开发多个Section的tableView。 首先应该考虑到数据源该如何得到 我们这里可以通过两种方式:第一种是读取plist文件。第二种是通过代码进行数据存储以及读取。 多个Section需要的数据源是一个字典&#xff0c;字典里的内容是一个数组。在plist文件中可以这样去创建 在.h文件中…

tableview概述

转自&#xff1a;http://www.cnblogs.com/smileEvday/archive/2012/06/28/tableView.html                 下面分9个方面进行介绍&#xff1a; 一、UITableView概述 UITableView继承自UIScrollView&#xff0c;可以表现为Plain和Grouped两种风格&#xff0c;分…

ios tableView那些事(一)创建一个简单的tableView

工作也有半年多了&#xff01;几乎每个项目中的会用到tableview这个神奇而好用的控件&#xff0c;在学习和工作中都会看别人的博客&#xff01;对我有很大的帮助&#xff0c;就如同站在巨人的肩膀上的感觉吧 哈哈&#xff01;于是决定重新开始写博客&#xff0c;希望能帮助像我…

JavaFX TableView和ListView的点击事件

项目场景&#xff1a; 最近在用JavaFX做一个简易的商城界面&#xff0c;大概想实现这样的功能&#xff1a; 左边显示用户的最近五个购买的产品 使用ListView 点击ListView的项目会定位到相应的tablerow位置 方便用户快速查找中间显示所有可用产品 使用TableView 双击tablerow…

JavaFX【TableView使用详解】

目录 概述 组件 Student ObservableList TableView setCellValueFactory() TableColumn 1. Callback 2. PropertyValueFactory 增加到末行 1、tableView.getItems().add(Student s) 2、list.add(Student s) 删除指定行 1、tableView.getItems().remove(int i) 2、…

QT中TableView数据展示

QT中TableView数据展示 最近在学习QT,大量数据从数据库取出放入QT界面中展示&#xff0c;这时用到了tableView&#xff0c;一些简单的使用分享给大家。 创建数据模型 QStandardItemModel *modelnew QStandardItemModel(); QStandardItemModel是Qt库中的一个类&#xff0c;它…

JAVAFX的TableView基本用法

JAVAFX中的表格显示主要使用TableView 与TableView相关的类: TableColumn TableRow TableCell TablePosition TableViewFocusModel TableViewSelectionModel JavaFX TableView例子: import javafx.application.Application; import javafx.scene.Scene; import javafx.scene…

QT之Tableview

想要了解更多的tableview可以看这位博客Qt深入浅出&#xff08;十五&#xff09;QTableView​ 这里做了一个简单的学生系统查询功能显示Tableview&#xff1a; 表格视图控件QTableView&#xff0c;需要和QStandardItemModel, 配套使用&#xff0c;这套框架是基于MVC设计模式设…

QML TableView 使用详解

目录 一、—个简单的TableView实例 二、TableViewColumn 属性讲解 三、定制表格外观 3.1 itemDelegate3.2 rowDelegate3.3 headerDelegate3.4 定制表格外观后的示例 四、动态增删改查 TabelView TableView 就是 Qt Quick 为表格式呈现数据提供的组件。想必兄台用过 Excel…

QT控件之(TableView)的居中效果

T将tableView中的表头以及文本内容都进行居中处理 1、需要在构造函数中增加一句&#xff1a; //以下增加的是表头的效果 ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//布局排版是全部伸展开的效果2、就是直接对tableView的文本内…

QML学习十七:TableView的简单使用

若该文为原创文章&#xff0c;转载请注明原文出处 一、TableView TableView是Qt Quick为表格式呈现数据提供的组件。 TableView与ListView类似&#xff0c;相比之下多了滚动条、挑选、可调整尺寸的表头等特性&#xff0c;数据也是通过Model来提供&#xff0c;此篇使用的是内建…

JavaFX中TableView的使用

稍微说说JavaFX里面TableView怎么用&#xff0c;&#xff08;其实在JavaFX的源码中都有示例。。。&#xff09; 首先要了解TableView是用来做什么的&#xff0c;TableView是JavaFX的一个表视图&#xff0c;用来显示表格的&#xff0c;在TableView的类注释中写了 /*** see Tab…

Qt4实现TableView显示表格数据

最近又开始搞QT开发了&#xff0c;前面学的MVC啥的都忘得差不多了&#xff0c;重新整理一遍思路吧。 目前的需求是&#xff1a;读取文本文件&#xff0c;表格型数据&#xff0c;用tableview显示出来&#xff0c;最后画图。这涉及到三个问题&#xff0c;文件读写&#xff0c;数…

NAT模式下的虚拟机网络配置

原理 NAT模式&#xff0c;也叫地址转换模式&#xff0c; 当把我们的虚拟机的上网方式设置为NAT模式时&#xff0c;虚拟机、宿主机、各网卡之间的连接关系可用下图来表示&#xff1a; 具体配置流程 1 将本地以太网共享到v8适配器上 2 查看虚拟网络编辑中的NAT模式下的子网IP…