前言:使用委托模型时需根据自身需求进行模型和委托类进行选择如:数据量小,且需要显示的内容并不复杂时建议直接选用QtableWidget之类的控件直接填充数据即可。
1、创建委托类
class CQuestionDelegete : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit CQuestionDelegete(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
bool editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index) Q_DECL_OVERRIDE;
private:
int _type;
};
QStyledItemDelegate类官方解释:
QStyledItemDelegate类为来自模型的数据项提供显示和编辑工具。
当在Qt项视图(例如QTableView)中显示模型数据时,单个项是由委托绘制的。 另外,当一个项目被编辑时,它提供了一个编辑器小部件,在进行编辑时,该小部件被放置在项目视图的顶部。 QStyledItemDelegate是所有Qt项目视图的默认委托,并在它们创建时安装在它们上面。
QStyledItemDelegate类是模型/视图类之一,是Qt模型/视图框架的一部分。 委托允许独立于模型和视图来开发项的显示和编辑。
选择继承QStyledItemDelegate类是因为QStyledItemDelegate是所有Qt项目视图的默认委托,这样可以更灵活的去定义我们想要数据显示
注意:通常我们进行委托类设计时都会对一下几个虚函数进行实现来实现我们想要的功能
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
createEditor函数实现后我们可以在这创建一下我们常用的控件如:QPushButton,QLineEdit等
例:
QWidget *TextDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 1)
{
QTextEdit *editor = new QTextEdit(parent);
return editor;
}
if(index.row() == 1)
{
QTextEdit *editor = new QTextEdit(parent);
return editor;
}
else
{
QLineEdit *editor = new QLineEdit(parent);
QRegExp regExp("[0-9]{0,10}");
editor->setValidator(new QRegExpValidator(regExp, parent));
return editor;
}
}
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
这两个函数则可以结合上面例子中创建的QlineEdit进行数据传输
例:
void TextDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QLineEdit *lineEdit = static_cast <QLineEdit*>(editor);
lineEdit->setText(text);
}
void TextDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QLineEdit *lineEdit = static_cast <QLineEdit*>(editor);
QString text = lineEdit->text();
model->setData(index, text, Qt::EditRole);
}
void TextDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
sizeHint该函数则可以重新定义item的大小。
当单一的控件无法满足我们的功能需求和数据显示时,我们可以采用自绘的方式去绘制我们需要的数据和功能按键
(1)、paint函数自绘控件
注意:在绘制item内容时,rect的高度需要小于ui->tableView->verticalHeader()->setDefaultSectionSize(80);此处设置的默认高度,否则会出现刷新paint时显示不全或者显示消失的情况!
void CQuestionDelegete::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
int row = index.row();
// 此处为最上方空3行,避免出现滑动时大屏幕过高无法点击的情况,可视个人具体情况进行修改
if(row < 3)
{
painter->fillRect(viewOption.rect, QBrush(QColor(255, 255, 255)));
return;
}
// 点击选中行更换背景色
if (option.state & QStyle::State_Selected)
{
painter->fillRect(viewOption.rect, QBrush(QColor(255, 249, 243)));
}
QFont font = painter->font();
font.setWeight(50);
// DelegatePrivate该类为按钮委托的友元类,用于绘制按钮和预加载一下图标文件和提示文本等
DelegatePrivate *pImages = qobject_cast<DelegatePrivate *>(parent());
if(pImages == NULL){
return;
}
for (int i = 0; i < 2; i++)
{
// 绘制按钮,QStyleOptionButton该类可以绘制正常按钮,但对部分按钮样式无法完整绘制,具体请看该类帮助文档
QStyleOptionButton button;
button.rect = QRect(option.rect.right() - 180 - i * 180,
option.rect.top() + 32, 150, 46);
button.state |= QStyle::State_Enabled;
if (button.rect.contains(pImages->_mousePoint))
{
// _type为标识按钮状态用,可根据具体情况使用
if (_type == 0)
{
button.state |= QStyle::State_MouseOver;
}
else if (_type == 1)
{
button.state |= QStyle::State_Sunken;
}
}
QWidget *pWidget = NULL;
switch(i)
{
case 0:
{
// 如需要在按钮上显示文本则需要使用button.text,注意如果要改变文本颜色则需要在按钮样式中进行修改
button.text = QString("讲解模式作答");
pWidget = pImages->_btnExplainMode.data();
break;
}
case 1:
{
button.text = QString("正常模式作答");
pWidget = pImages->_btnNormalMode.data();
break;
}
}
font.setPixelSize(20);
painter->setFont(font);
pWidget->style()->drawControl(QStyle::CE_PushButton, &button, painter, pWidget);
}
// 显示文本数据和文件图标
if(!pImages->_fileIcon.isNull())
{
QRect iconRect = QRect(option.rect.x() + 30, option.rect.y() + 29, 50, 50);
painter->drawPixmap(iconRect, pImages->_fileIcon);
}
int textY = 0;
QRect textRect;
if(1)
{
textY = 29;
font.setPixelSize(18);
painter->setFont(font);
painter->setPen(QColor(255, 94, 94));
textRect = QRect(option.rect.x() + 109, option.rect.y() + 63, 360, 23);
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignHCenter, QString("该题型中含有主观题,不可在校牌上进行作答"));
}
else
{
textY = 43;
}
textRect = QRect(option.rect.x() + 89, option.rect.y() + textY, 497, 30);
font.setPixelSize(24);
painter->setFont(font);
painter->setPen(QColor(94, 94, 94));
QFontMetrics fm = QFontMetrics(font);
QString str = QString("《CSDN博客》课后练习题和类文阅读题");
QString strName = fm.elidedText(str, Qt::ElideRight, textRect.width());
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignHCenter, strName);
textRect = QRect(option.rect.x() + 675, option.rect.y() + 43, 497, 30);
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignHCenter, QString("题目:15 存档时间:2024-03-08 21:09:23"));
}
(2)、委托按钮友元类实现:
class DelegatePrivate : public QObject
{
Q_OBJECT
public:
DelegatePrivate(QObject *parent = nullptr);
private:
QPoint _mousePoint; // 鼠标位置
QPixmap _fileIcon; // 文件图标
QScopedPointer<QPushButton> _btnNormalMode;
QScopedPointer<QPushButton> _btnExplainMode;
friend class CQuestionDelegete;
};
DelegatePrivate::DelegatePrivate(QObject *parent) :
QObject(parent),
_btnNormalMode(new QPushButton()),
_btnExplainMode(new QPushButton())
{
_fileIcon.load(":/image/CQuestionWidget/fileIcon.png");
_btnNormalMode->setStyleSheet("QPushButton {background: #0082F1;border-radius: 6px;color: #FFFFFF;}");
_btnExplainMode->setStyleSheet("QPushButton {background: #00D65B;border-radius: 6px;color: #FFFFFF;}");
}
(3)、按钮按下的数据交互实现
需要实现bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) Q_DECL_OVERRIDE;
bool CQuestionDelegete::editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
bool bRepaint = false;
if(index.column() == 0)
{
DelegatePrivate *pImages = qobject_cast<DelegatePrivate *>(parent());
if(pImages == NULL){
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
_type = -1;
QMouseEvent* e =(QMouseEvent*)event;
pImages->_mousePoint = e->pos();
for (int i=0; i < 2; i++)
{
QStyleOptionButton button;
button.rect = QRect(option.rect.right() - 180 - i * 180,
option.rect.top() + 32, 150, 46);
// 鼠标位于按钮之上
if (!button.rect.contains(pImages->_mousePoint))
{
continue;
}
bRepaint = true;
switch (event->type())
{
// 鼠标滑过
case QEvent::MouseMove:
{
_type = 0;
break;
}
// 鼠标按下
case QEvent::MouseButtonPress:
{
_type = 1;
model->setData(index, i, Qt::UserRole);
break;
}
// 鼠标释放
case QEvent::MouseButtonRelease:
{
break;
}
default:
break;
}
}
}
return bRepaint;
}