需求:QTableView中指定列所有Item均为CheckBox项,要求CheckBox居中显示
显示效果如下:三种表现效果
实现方式:
-
系统控件QCheckBox
-
自绘制CheckBox
-
CheckBox的图片
实现代码:(原理:利用委托自绘的方式)
CheckBoxDelegate
#ifndef CHECKBOXDELETAGE_H
#define CHECKBOXDELETAGE_H
#include <QStyledItemDelegate>
class QPixmap;
class CheckBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
enum class CheckBoxPaintType : quint8
{
SysControl = 0, // 系统控件
OwnerDraw = 1, // 自绘CheckBox
DrawImage = 2, // 绘制图片
};
public:
explicit CheckBoxDelegate(CheckBoxPaintType type = CheckBoxPaintType::SysControl, QWidget *parent = nullptr);
~CheckBoxDelegate();
void initCheckBoxPixmaps(CheckBoxPaintType type);
void initCheckBoxPixmapBySysControl(const QString& key, bool checked);
void initCheckBoxPixmapByOwnerDraw(const QString& key, bool checked);
void initCheckBoxPixmapByDrawImage(const QString& key, bool checked);
// 虚函数
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
signals:
private:
QPixmap* mCheckedPix = nullptr;
QPixmap* mUnCheckedPix = nullptr;
};
#endif // CHECKBOXDELETAGE_H
#include "checkboxdeletage.h"
#include <QCheckBox>
#include <QApplication>
#include <QMouseEvent>
#include <QPixmapCache>
#include <QPainter>
CheckBoxDelegate::CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType type, QWidget *parent)
: QStyledItemDelegate(parent)
{
initCheckBoxPixmaps(type);
}
CheckBoxDelegate::~CheckBoxDelegate()
{
delete mCheckedPix;
delete mUnCheckedPix;
}
void CheckBoxDelegate::initCheckBoxPixmaps(CheckBoxDelegate::CheckBoxPaintType type)
{
switch (type)
{
case CheckBoxPaintType::SysControl:
initCheckBoxPixmapBySysControl("checked", true);
initCheckBoxPixmapBySysControl("unchecked", false);
break;
case CheckBoxPaintType::OwnerDraw:
initCheckBoxPixmapByOwnerDraw("checked", true);
initCheckBoxPixmapByOwnerDraw("unchecked", false);
break;
case CheckBoxPaintType::DrawImage:
initCheckBoxPixmapByDrawImage("checked", true);
initCheckBoxPixmapByDrawImage("unchecked", false);
break;
default:
break;
}
}
void CheckBoxDelegate::initCheckBoxPixmapBySysControl(const QString &key, bool checked)
{
QPixmap* pix = new QPixmap(13,13);
QPainter painter(pix);
QStyleOptionToolButton style;
style.iconSize = QSize(13, 13);
style.state = checked ? QStyle::State_On : QStyle::State_Off;
style.state |= QStyle::State_Enabled;
style.rect = QRect(0,0, 13,13);
QCheckBox box;
QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &style, &painter, &box);
if (checked)
mCheckedPix = pix;
else
mUnCheckedPix = pix;
}
void CheckBoxDelegate::initCheckBoxPixmapByOwnerDraw(const QString &key, bool checked)
{
QPixmap* pix = new QPixmap(13,13);
QPainter painter(pix);
painter.setPen(QColorConstants::Green);
QRect rect(0,0,13,13);
// 抗锯齿
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(QBrush(QColorConstants::White));
painter.drawRect(rect);
if (checked)
{
QPointF points[3] = {
QPointF(rect.x() + rect.width() * 2 / 11, rect.y() + rect.height() * 6 / 11),
QPointF(rect.x() + rect.width() * 4 / 11, rect.y() + rect.height() * 8 / 11),
QPointF(rect.x() + rect.width() * 9 / 11, rect.y() + rect.height() * 3 / 11),
};
painter.setPen(QPen(QBrush(QColorConstants::Green),2));
painter.drawPolyline(points, 3);
}
if (checked)
mCheckedPix = pix;
else
mUnCheckedPix = pix;
// 也可直接放入QPixmapCache中去,此处就简单处理更高效些
//QPixmapCache::insert(key, pix);
}
void CheckBoxDelegate::initCheckBoxPixmapByDrawImage(const QString &key, bool checked)
{
QPixmap* pix = new QPixmap(checked ? ":/image/checked.png" : ":/image/unchecked.png");
if (checked)
mCheckedPix = pix;
else
mUnCheckedPix = pix;
}
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
if (viewOption.state.testFlag(QStyle::State_HasFocus))
viewOption.state ^= QStyle::State_HasFocus;
QStyledItemDelegate::paint(painter, option, index);
bool checked = index.data(Qt::UserRole).toBool();
QPixmap* pix = checked? mCheckedPix : mUnCheckedPix;
if (pix)
{
// 居中显示
QRect rect = pix->rect();
int offsetX = option.rect.width() / 2 - rect.width() / 2;
int offsetY = option.rect.height() / 2 - rect.height() / 2;
rect.translate(option.rect.x() + offsetX, option.rect.y() + offsetY);
painter->drawPixmap(rect, *pix);
}
}
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick)
{
// 鼠标单双击切换选中状态
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
if (option.rect.contains(mouseEvent->pos()))
{
model->setData(index, !model->data(index, Qt::UserRole).toBool(), Qt::UserRole);
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
使用:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTabWidget>
#include <QSplitter>
#include <QTableView>
#include <QStandardItemModel>
#include "checkboxdeletage.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTabWidget* tabWidget = new QTabWidget(this);
QSplitter* splitter = new QSplitter(Qt::Orientation::Horizontal, this);
QTableView* tableView = new QTableView(this);
QStandardItemModel* model = new QStandardItemModel(2,3,this);
tableView->setModel(model);
tableView->setItemDelegateForColumn(0, new CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType::SysControl, this));
tableView->setItemDelegateForColumn(1, new CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType::OwnerDraw, this));
tableView->setItemDelegateForColumn(2, new CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType::DrawImage, this));
// 不可编辑
tableView->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers);
// 整行选中
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
// 多行可选
tableView->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);
splitter->addWidget(tableView);
tabWidget->addTab(splitter, "CheckBox");
setCentralWidget(tabWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
QTableView如果实现指定项不可编辑状态方法:
-
重写Model的虚函数flags,指定index下的item的flags去除Qt::ItemIsEditable标志
-
重写Delegate的createEditor,实现返回空的editor即可