QTableView/QTableWidget表头添加复选框
核心代码如下
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();
效果图