目录
- qtableview 委托
- QStyledItemDelegate
- QAbstractItemDelegate
- CheckBoxItemDelegate
- 使用
- qtableview控制列宽,行高,隐藏
- 拖拽行列
qtableview 委托
//设置单元格委托
void setItemDelegate(QAbstractItemDelegate *delegate);
QAbstractItemDelegate *itemDelegate() const;
//设置列委托
void setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate);
QAbstractItemDelegate *itemDelegateForColumn(int column) const;
//设置行委托
void setItemDelegateForRow(int row, QAbstractItemDelegate *delegate);
QAbstractItemDelegate *itemDelegateForRow(int row) const;
QStyledItemDelegate
查看qtableview源码会发现itemdelegate默认就是QStyledItemDelegate
如果要自己写自定义的委托请尽量参考QStyledItemDelegate
显示事件
void QStyledItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
QStyle *style = widget ? widget->style() : QApplication::style();
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
}
初始化绘制参数配置
void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option,
const QModelIndex &index) const
{
QVariant value = index.data(Qt::FontRole);
if (value.isValid() && !value.isNull()) {
option->font = qvariant_cast<QFont>(value).resolve(option->font);
option->fontMetrics = QFontMetrics(option->font);
}
value = index.data(Qt::TextAlignmentRole);
if (value.isValid() && !value.isNull())
option->displayAlignment = Qt::Alignment(value.toInt());
value = index.data(Qt::ForegroundRole);
if (value.canConvert<QBrush>())
option->palette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
option->index = index;
value = index.data(Qt::CheckStateRole);
if (value.isValid() && !value.isNull()) {
option->features |= QStyleOptionViewItem::HasCheckIndicator;
option->checkState = static_cast<Qt::CheckState>(value.toInt());
}
value = index.data(Qt::DecorationRole);
if (value.isValid() && !value.isNull()) {
option->features |= QStyleOptionViewItem::HasDecoration;
switch (value.type()) {
case QVariant::Icon: {
option->icon = qvariant_cast<QIcon>(value);
QIcon::Mode mode;
if (!(option->state & QStyle::State_Enabled))
mode = QIcon::Disabled;
else if (option->state & QStyle::State_Selected)
mode = QIcon::Selected;
else
mode = QIcon::Normal;
QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
QSize actualSize = option->icon.actualSize(option->decorationSize, mode, state);
// For highdpi icons actualSize might be larger than decorationSize, which we don't want. Clamp it to decorationSize.
option->decorationSize = QSize(qMin(option->decorationSize.width(), actualSize.width()),
qMin(option->decorationSize.height(), actualSize.height()));
break;
}
case QVariant::Color: {
QPixmap pixmap(option->decorationSize);
pixmap.fill(qvariant_cast<QColor>(value));
option->icon = QIcon(pixmap);
break;
}
case QVariant::Image: {
QImage image = qvariant_cast<QImage>(value);
option->icon = QIcon(QPixmap::fromImage(image));
option->decorationSize = image.size() / image.devicePixelRatio();
break;
}
case QVariant::Pixmap: {
QPixmap pixmap = qvariant_cast<QPixmap>(value);
option->icon = QIcon(pixmap);
option->decorationSize = pixmap.size() / pixmap.devicePixelRatio();
break;
}
default:
break;
}
}
value = index.data(Qt::DisplayRole);
if (value.isValid() && !value.isNull()) {
option->features |= QStyleOptionViewItem::HasDisplay;
option->text = displayText(value, option->locale);
}
option->backgroundBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));
// disable style animations for checkboxes etc. within itemviews (QTBUG-30146)
option->styleObject = 0;
}
当然有些列子https://blog.csdn.net/c1s2d3n4cs/article/details/143203486
行委托一般用来作为背景委托
列委托与单元格委托是一组,就是简单的优先级
列委托优先级》单元格委托
QAbstractItemDelegate
那么为了自定义qtableview 需要使用到这个QAbstractItemDelegate委托类
很遗憾,官方没给我们提供checkboxitemdelegate或者comboboxdelegate之类的委托
那么我们就需要自己去写一个
请参考https://blog.csdn.net/Gerald_Jones/article/details/106594052
CheckBoxItemDelegate
继承QItemDelegate需要实现一下几个虚函数
编辑模式,因为我们使用qsqlquerymodel 只读模型 所以可以不用写
// 创建编辑器
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
// 设置编辑器数据
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
// 更新编辑器集合属性
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
// 设置模型数据
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
//如果是只读的组件那么我们只需要以下两个方法
CheckBoxItemDelegate.h
#ifndef CHECKBOXITEMDELEGATE_H
#define CHECKBOXITEMDELEGATE_H
#include <QObject>
#include <QItemDelegate>
#include <QStyledItemDelegate>
#include <QCheckBox>
#include <QStylePainter>
#include <QDebug>
#include <QStyleOptionButton>
class CheckBoxItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit CheckBoxItemDelegate(QObject *parent = nullptr);
~CheckBoxItemDelegate();
//---只读
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;
//---编辑模式
// 创建编辑器 ---- 返回组件
// QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
// // 设置编辑器数据 ---- 初始化组件数据
// void setEditorData(QWidget *editor, const QModelIndex &index) const override;
// // 更新编辑器集合属性 --- 设置位置
// void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
// // 设置模型数据 ---- 修改数据模型数据
// void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
signals:
protected:
void initStyleOption(QStyleOptionButton *option,
const QStyleOptionViewItem *copy,
const QModelIndex &index) const;
private:
bool m_checked = false;
};
#endif // CHECKBOXITEMDELEGATE_H
CheckBoxItemDelegate.cpp
#include "CheckBoxItemDelegate.h"
#include <QApplication>
CheckBoxItemDelegate::CheckBoxItemDelegate(QObject *parent) : QItemDelegate(parent)
{
qDebug()<< __FUNCTION__;
}
CheckBoxItemDelegate::~CheckBoxItemDelegate()
{
qDebug()<< __FUNCTION__;
}
void CheckBoxItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyleOptionButton opt;
initStyleOption(&opt, &option, index);
const QWidget *widget = option.widget;
QStyle *style = widget ? widget->style() : QApplication::style();
style->drawControl(QStyle::CE_CheckBox, &opt, painter, widget);
}
bool CheckBoxItemDelegate::editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
//选中或者取消选中
m_checked = true;
return false;
}
//QWidget *CheckBoxItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
//{
// return new QCheckBox(parent);
//}
//void CheckBoxItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
//{
// QCheckBox *cb = static_cast<QCheckBox *>(editor);
// cb->setChecked(true);
//}
//void CheckBoxItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
//{
// editor->setGeometry(option.rect);
//}
//void CheckBoxItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
//{
// // QCheckBox *cb = static_cast<QCheckBox *>(editor);
// // model->setData(index, cb->isChecked());
//}
void CheckBoxItemDelegate::initStyleOption(QStyleOptionButton *option,
const QStyleOptionViewItem *copy,
const QModelIndex &index) const
{
QRect boxRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator,option);
option->rect = copy->rect;
option->rect.setLeft(copy->rect.left()+(copy->rect.width()-boxRect.width())/2); //居中
//option->rect.setTop(copy->rect.top()+(copy->rect.height()-option->rect.height())/2);
option->state = m_checked? QStyle::State_On: QStyle::State_Off;
}
至于初始化选中状态由外部的section管理器来决定来决定
所以我们需要
实现一个选择管理器(支持单选,多选,跨页选)
我好想又看到qml有一个TableViewSelection.qml
至于c++有没有这个选择管理器还得自己去实现
使用
部分操作需要基于model之后,否则无效
如对行列隐藏,宽高设置等
qtableview控制列宽,行高,隐藏
QTableView *view = new QTableView(this);
view->setModel(model);
view->move(0,400);
//修改布局样式需要放到model之后设置
CheckBoxItemDelegate* cb_delegate = new CheckBoxItemDelegate(this);
view->setItemDelegateForColumn(0,cb_delegate);
view->setColumnHidden(1,true);
view->setColumnWidth(0,120);
view->setRowHidden(0,true);
view->setRowHeight(0,60);
而至于为什么view可以操作行列, 实际要查看Qheaderview.cpp
setColumnHidden -> setSectionHidden -> setVisualIndexHidden
inline void setVisualIndexHidden(int visual, bool hidden) {
sectionItems[visual].isHidden = hidden;
}
而至于sectionItems怎么来的就跟我们上面的setmodel有关
他们之间有个信号槽,model 的信号 columnsInserted触发headerview中的sectionsInserted槽
sectionsInserted执行了sectionItems的添加操作
QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(sectionsInserted(QModelIndex,int,int)));
行的管理-------是同上的
拖拽行列
请参考https://blog.csdn.net/pyc_01/article/details/123346957
view->setSelectionBehavior(QAbstractItemView::SelectRows); //选择方式:单元格选择、行选择、列选择
view->setSelectionMode(QAbstractItemView::SingleSelection); //选择模式: 多选,单选
view->horizontalHeader()->setSectionsMovable(true); //表头支持拖动
view->setDragEnabled(true); //启用拖拽
view->setAcceptDrops(true); //接受放置
view->setDragDropMode(QAbstractItemView::InternalMove); //拖放范围:内部
view->setEditTriggers(QAbstractItemView::NoEditTriggers); //禁用编辑功能
view->setCursor(Qt::ClosedHandCursor);
//解下来需要重写拖放等相关事件,这需要重写一个DragTableView控件