Qt-QTableView委托视图学习1——样式委托类实现

前言:使用委托模型时需根据自身需求进行模型和委托类进行选择如:数据量小,且需要显示的内容并不复杂时建议直接选用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;
}

  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的QT视图模型委托项目案例: 假设有一个表格,其中一列显示了用户的年龄,我们想要让年龄小于18岁的行以红色显示,而年龄大于等于18岁的行以绿色显示。我们可以通过使用QT视图模型委托实现此目的。 首先,我们需要定义一个自定义的委托,该继承自QStyledItemDelegate。在该中,我们将实现一个paint()函数,该函数将会在每次需要绘制表格项时被调用。 ```cpp class AgeDelegate : public QStyledItemDelegate { public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { // 获取年龄值 int age = index.data(Qt::DisplayRole).toInt(); // 设置画笔颜色 if (age < 18) { painter->setPen(QColor("red")); } else { painter->setPen(QColor("green")); } // 调用基的paint()函数进行绘制 QStyledItemDelegate::paint(painter, option, index); } }; ``` 接下来,我们需要在主窗口中创建一个表格,并为其设置一个QStandardItemModel模型。然后,我们将会为该模型的第二列(即年龄列)设置我们刚刚定义的委托。 ```cpp // 创建表格和模型 QTableView *tableView = new QTableView(this); QStandardItemModel *model = new QStandardItemModel(4, 2, this); // 设置表头 model->setHeaderData(0, Qt::Horizontal, tr("Name")); model->setHeaderData(1, Qt::Horizontal, tr("Age")); // 设置模型数据 model->setData(model->index(0, 0), "John Doe"); model->setData(model->index(0, 1), 25); model->setData(model->index(1, 0), "Jane Smith"); model->setData(model->index(1, 1), 17); model->setData(model->index(2, 0), "Bob Johnson"); model->setData(model->index(2, 1), 30); model->setData(model->index(3, 0), "Mary Williams"); model->setData(model->index(3, 1), 16); // 为模型的第二列设置委托 tableView->setItemDelegateForColumn(1, new AgeDelegate(this)); // 将模型设置给表格 tableView->setModel(model); ``` 现在,我们运行程序,就可以看到表格中年龄小于18岁的行以红色显示,而年龄大于等于18岁的行以绿色显示。这就是通过QT视图模型委托实现的。 注意:本示例并不完整,只是为了演示视图模型委托的基本用法。在实际应用中,您可能需要对上述代码进行进一步的修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值