通过实现QAbstractItemDelegate的paint()函数。
这种方法和《C++_GUI_Qt4_编程(第二版)》中第十章的自定义委托例子,画星星的作法是一样的,都是通过 QApplication::style()->drawControl(QStyle::CE_CheckBox,&check_box_style_option,painter);这个函数,只不过选择的元素是QCheckBox的。
#ifndef CCHECKBOXMODEL_H
#define CCHECKBOXMODEL_H
#include
#include
#include
#include
#include
class TableHeaderView :public QHeaderView
{
Q_OBJECT
public:
TableHeaderView(Qt::Orientation orientation, QWidget *parent);
~TableHeaderView();
protected:
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
bool event(QEvent *e) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE;
public slots:
void onStateChanged(int state);
signals:
void stateChanged(int state);
private:
bool m_bPressed;
bool m_bChecked;
bool m_bTristate;
bool m_bNoChange;
bool m_bMoving;
};
class CheckBoxDelegate :public QStyledItemDelegate
{
Q_OBJECT
public:
CheckBoxDelegate(QObject *parent);
~CheckBoxDelegate();
// painting
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
protected:
bool editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index);
};
#endif // TABLE_MODEL_H
#include "ccheckboxmodel.h"
#include
#include
#include
#include
#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif
#define CHECK_BOX_COLUMN 0
TableHeaderView::TableHeaderView(Qt::Orientation orientation, QWidget *parent)
: QHeaderView(orientation, parent),
m_bPressed(false),
m_bChecked(false),
m_bTristate(false),
m_bNoChange(false),
m_bMoving(false)
{
setSectionsClickable(true); // 响应鼠标
}
TableHeaderView::~TableHeaderView()
{
}
// 槽函数,用于更新复选框状态
void TableHeaderView::onStateChanged(int state)
{
if (state == Qt::PartiallyChecked) {
m_bTristate = true;
m_bNoChange = true;
}
else {
m_bNoChange = false;
}
m_bChecked = (state != Qt::Unchecked);
update();
}
// 绘制复选框
void TableHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
if (logicalIndex == CHECK_BOX_COLUMN)
{
QStyleOptionButton option;
option.initFrom(this);
if (m_bChecked)
option.state |= QStyle::State_Sunken;
if (m_bTristate && m_bNoChange)
option.state |= QStyle::State_NoChange;
else
option.state |= m_bChecked ? QStyle::State_On : QStyle::State_Off;
if (testAttribute(Qt::WA_Hover) && underMouse()) {
if (m_bMoving)
option.state |= QStyle::State_MouseOver;
else
option.state &= ~QStyle::State_MouseOver;
}
QCheckBox checkBox;
option.iconSize = QSize(20, 20);
option.rect = rect;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, &checkBox);
}
}
// 鼠标按下表头
void TableHeaderView::mousePressEvent(QMouseEvent *event)
{
int nColumn = logicalIndexAt(event->pos());
if ((event->buttons() & Qt::LeftButton) && (nColumn == CHECK_BOX_COLUMN))
{
m_bPressed = true;
}
else
{
QHeaderView::mousePressEvent(event);
}
}
// 鼠标从表头释放,发送信号,更新model数据
void TableHeaderView::mouseReleaseEvent(QMouseEvent *event)
{
if (m_bPressed)
{
if (m_bTristate && m_bNoChange)
{
m_bChecked = true;
m_bNoChange = false;
}
else
{
m_bChecked = !m_bChecked;
}
update();
Qt::CheckState state = m_bChecked ? Qt::Checked : Qt::Unchecked;
emit stateChanged(state);
updateSection(0);
}
else
{
QHeaderView::mouseReleaseEvent(event);
}
m_bPressed = false;
}
// 鼠标滑过、离开,更新复选框状态
bool TableHeaderView::event(QEvent *event)
{
updateSection(0);
if (event->type() == QEvent::Enter || event->type() == QEvent::Leave)
{
QMouseEvent *pEvent = static_cast<QMouseEvent *>(event);
int nColumn = logicalIndexAt(pEvent->x());
if (nColumn == CHECK_BOX_COLUMN)
{
m_bMoving = (event->type() == QEvent::Enter);
update();
return true;
}
}
return QHeaderView::event(event);
}
CheckBoxDelegate::CheckBoxDelegate(QObject *parent) :QStyledItemDelegate(parent)
{
}
CheckBoxDelegate::~CheckBoxDelegate()
{
}
// 绘制复选框
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
if (option.state.testFlag(QStyle::State_HasFocus))
viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
QStyledItemDelegate::paint(painter, viewOption, index);
if (index.column() == CHECK_BOX_COLUMN)
{
bool data = index.model()->data(index, Qt::UserRole).toBool();
QStyleOptionButton checkBoxStyle;
checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;
checkBoxStyle.state |= QStyle::State_Enabled;
checkBoxStyle.iconSize = QSize(20, 20);
checkBoxStyle.rect = option.rect;
QCheckBox checkBox;
checkBoxStyle.iconSize = QSize(20, 20);
checkBoxStyle.rect = option.rect;
QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &checkBox);
checkBox.setEnabled(false);
}
}
// 响应鼠标事件,更新数据
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
QRect decorationRect = option.rect;
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (event->type() == QEvent::MouseButtonPress && decorationRect.contains(mouseEvent->pos()))
{
if (index.column() == CHECK_BOX_COLUMN)
{
bool data = model->data(index, Qt::UserRole).toBool();
model->setData(index, !data, Qt::UserRole);
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include "ccheckboxmodel.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
private:
TableHeaderView *myHeader;
QStandardItemModel *model;
private:
void iniVar();
void iniUi();
void iniConnect();
void createItem(QStringList filename);
private slots:
void headerStateChangedSlot(int state);
void itemChangedSlot(QStandardItem* item);
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#ifdef _MSC_VER
#pragma execution_character_set("utf-8")
#endif
const QString headerStr = QObject::tr(" ,工况名");
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//--1 初始化
iniVar();
iniUi();
iniConnect();
//--2 创建表格项
QStringList workingConditionName;
workingConditionName<<tr("工况1")<<tr("工况2")<<tr("工况3");
createItem(workingConditionName);
}
Widget::~Widget()
{
delete ui;
}
void Widget::iniVar()
{
myHeader = new TableHeaderView(Qt::Horizontal, ui->tableView);
model = new QStandardItemModel(ui->tableView);
}
void Widget::iniUi()
{
ui->tableView->setHorizontalHeader(myHeader);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); //选中行
QStringList headerList = headerStr.split(",");
model->setHorizontalHeaderLabels(headerList);
model->setColumnCount(headerList.size());
CheckBoxDelegate *pCheckDelegate = new CheckBoxDelegate(this);
ui->tableView->setItemDelegateForColumn(0, pCheckDelegate);
ui->tableView->setModel(model);
}
void Widget::iniConnect()
{
connect(myHeader, &TableHeaderView::stateChanged, this, &Widget::headerStateChangedSlot);
connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(itemChangedSlot(QStandardItem*)));
}
void Widget::createItem(QStringList filename)
{
int rowCount = filename.size();
model->setRowCount(rowCount);
for(int i = 0; i < rowCount; ++i)
{
model->setItem(i,1,new QStandardItem(filename.at(i)));
}
}
void Widget::headerStateChangedSlot(int state)
{
int rowCount = model->rowCount();
if (state == 2)//全选
{
for (int j = 0; j<rowCount; j++)
{
QModelIndex index = model->index(j, 0, QModelIndex());
model->setData(index, true, Qt::UserRole);
}
}
else if (state == 0) //全不选
{
for (int j = 0; j<rowCount; j++)
{
QModelIndex index = model->index(j, 0, QModelIndex());
model->setData(index, false, Qt::UserRole);
}
}
}
void Widget::itemChangedSlot(QStandardItem *item)
{
int rowCount = model->rowCount();
int column = item->index().column();
if (column == 0) //第0列 checkbox
{
Qt::CheckState state = Qt::Unchecked;
int nSelectedCount = 0;
for (int i = 0; i< rowCount; i++)
{
if (model->index(i, 0).data(Qt::UserRole).toBool())
{
nSelectedCount++;
}
}
if (nSelectedCount >= rowCount)
{
state = Qt::Checked;
}
else if (nSelectedCount > 0)
{
state = Qt::PartiallyChecked;
}
myHeader->onStateChanged(state);
}
}