核心代码如下 1、复选列属性定义
//可复选列的属性 struct stCheckbleColumnSettings{ bool canTristate; //是否支持三态 QString text; //显示的文本 Qt::Alignment al; //对齐方式 stCheckbleColumnSettings(){ canTristate = false; al = Qt::AlignCenter; } stCheckbleColumnSettings(bool canTristate, const QString& text, Qt::Alignment al = Qt::AlignLeft | Qt::AlignVCenter) : canTristate(canTristate), text(text), al(al){} };2、重写QHeaderView的mouseRelease事件,用来判断点击
void CheckbleHeaderView::mouseReleaseEvent(QMouseEvent *e) { QHeaderView::mouseReleaseEvent(e); if(e->button() != Qt::LeftButton) return ; int nIdx = logicalIndexAt(e->pos()); Q_D(CheckbleHeaderView); if(!d->m_mapColumn2Data.contains(nIdx)) { return ; } auto& columnData = d->m_mapColumn2Data[nIdx]; //判断是否在checkbox的点击范围内 if(!d->contains(nIdx, e->pos())) { d->m_nCurrentPressColumn = -1; return; } if(columnData.canTristate) { if(columnData.state == Qt::Unchecked) { columnData.state = Qt::PartiallyChecked; } else { columnData.state = columnData.state == Qt::Checked ? Qt::Unchecked : Qt::Checked; } } else { columnData.state = columnData.state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked; } d->m_nCurrentPressColumn = -1; //更新界面 updateSection(nIdx); emit sigStateChanged(nIdx, columnData.state); }3、判断是否在checkbox点击范围内
bool contains(int nCol, const QPoint& pos) { if(!m_mapColumn2Data.contains(nCol)) { return false; } Q_Q(CheckbleHeaderView); int nX = q->sectionPosition(nCol); int size = q->sectionSize(nCol); QRect rc(nX, 0, size, q->height()); QCheckBox check; QStyleOptionButton opt = getStyleOption(&check, nCol, m_mapColumn2Data.value(nCol), rc); QRect rcIndicator = q->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &opt, &check); return rcIndicator.contains(pos); }4、获取绘制的styleoption
QStyleOptionButton getStyleOption(QCheckBox* check, int logicalIndex, const stColumnData& columnData, const QRect& rect)const { const Q_Q(CheckbleHeaderView); QStyleOptionButton opt; opt.initFrom(check); opt.rect = rect; opt.text = columnData.strText; if(m_nCurrentPressColumn == logicalIndex) { opt.state |= QStyle::State_Sunken; } if(columnData.state == Qt::PartiallyChecked) { opt.state |= QStyle::State_NoChange; } else { opt.state |= columnData.state == Qt::Checked ? QStyle::State_On : QStyle::State_Off; } if(q->testAttribute(Qt::WA_Hover) && q->underMouse()) { opt.state |= QStyle::State_MouseOver; } //根据对齐方式重新计算rect reCalcOptRect(check, columnData.al, opt); return opt; }5、最后是绘制的代码
const Q_D(CheckbleHeaderView); painter->save(); QHeaderView::paintSection(painter, rect, logicalIndex); painter->restore(); //判断该列是否支持复选 if(!d->m_mapColumn2Data.contains(logicalIndex)) { return; } const auto& columnData = d->m_mapColumn2Data.value(logicalIndex); QCheckBox check((QWidget*)this); QStyleOptionButton opt = d->getStyleOption(&check, logicalIndex, columnData, rect); style()->drawControl(QStyle::CE_CheckBox, &opt, painter, &check);使用方法
QTableWidget w; w.setColumnCount(2); w.setRowCount(2); CheckbleHeaderView view(Qt::Horizontal); view.setCheckbleColumn({{0, {true, "1", Qt::AlignCenter}}}); w.setHorizontalHeader(&view); w.show();效果图