zoukankan      html  css  js  c++  java
  • Qt之QTableView添加复选框(QAbstractItemDelegate)

    简述

    上节分享了使用自定义模型QAbstractTableModel来实现复选框。下面我们来介绍另外一种方式:
    自定义委托-QAbstractItemDelegate。

    效果

    这里写图片描述

    QAbstractTableModel

    源码

    table_model.cpp

    #define CHECK_BOX_COLUMN 0
    #define File_PATH_COLUMN 1
    
    TableModel::TableModel(QObject *parent)
        : QAbstractTableModel(parent)
    {
    
    }
    
    TableModel::~TableModel()
    {
    
    }
    
    // 更新表格数据
    void TableModel::updateData(QList<FileRecord> recordList)
    {
        m_recordList = recordList;
        beginResetModel();
        endResetModel();
    }
    
    // 行数
    int TableModel::rowCount(const QModelIndex &parent) const
    {
        return m_recordList.count();
    }
    
    // 列数
    int TableModel::columnCount(const QModelIndex &parent) const
    {
        return 2;
    }
    
    // 设置表格项数据
    bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        if (!index.isValid())
            return false;
    
        int nColumn = index.column();
        FileRecord record = m_recordList.at(index.row());
        switch (role)
        {
        case Qt::DisplayRole:
        {
            if (nColumn == File_PATH_COLUMN)
            {
                record.strFilePath = value.toString();
    
                m_recordList.replace(index.row(), record);
                emit dataChanged(index, index);
                return true;
            }
        }
        case Qt::CheckStateRole:
        case Qt::UserRole:
        {
            if (nColumn == CHECK_BOX_COLUMN)
            {
                record.bChecked = value.toBool();
    
                m_recordList.replace(index.row(), record);
                emit dataChanged(index, index);
                return true;
            }
        }
        default:
            return false;
        }
        return false;
    }
    
    // 表格项数据
    QVariant TableModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid())
            return QVariant();
    
        int nRow = index.row();
        int nColumn = index.column();
        FileRecord record = m_recordList.at(nRow);
    
        switch (role)
        {
        case Qt::TextColorRole:
            return QColor(Qt::white);
        case Qt::TextAlignmentRole:
            return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
        case Qt::DisplayRole:
        {
            if (nColumn == File_PATH_COLUMN)
                return record.strFilePath;
            return "";
        }
        case Qt::UserRole:
        {
            if (nColumn == CHECK_BOX_COLUMN)
                return record.bChecked;
        }
        default:
            return QVariant();
        }
    
        return QVariant();
    }
    
    // 表头数据
    QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
        switch (role)
        {
        case Qt::TextAlignmentRole:
            return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
        case Qt::DisplayRole:
        {
            if (orientation == Qt::Horizontal)
            {
                if (section == CHECK_BOX_COLUMN)
                    return QStringLiteral("状态");
    
                if (section == File_PATH_COLUMN)
                    return QStringLiteral("文件路径");
            }
        }
        default:
            return QVariant();
        }
    
        return QVariant();
    }
    
    // 表格可选中、可复选
    Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
    {
        if (!index.isValid())
            return QAbstractItemModel::flags(index);
    
        Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    
        return flags;
    }

    接口说明

    • updateData
      主要用于更新数据,刷新界面。

    • data
      用来显示数据,根据角色(颜色、文本、对齐方式、选中状态等)判断需要显示的内容。

    • setData
      用来设置数据,根据角色(颜色、文本、对齐方式、选中状态等)判断需要设置的内容。

    • headerData
      用来显示水平/垂直表头的数据。

    • flags
      用来设置单元格的标志(可用、可选中、可复选等)。

    QStyledItemDelegate

    源码

    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;
            QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &checkBox);
        }
    }
    
    // 响应鼠标事件,更新数据
    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);
    }

    接口说明

    • paint
      用来设置表格样式,绘制复选框-状态、大小、显示区域等。

    • editorEvent
      用来设置数据,响应鼠标事件,判断当前选中状态,互相切换。

    样式

    复选框样式:

    QCheckBox{
            spacing: 5px;
            color: white;
    }
    QCheckBox::indicator {
            width: 17px;
            height: 17px;
    }
    QCheckBox::indicator:enabled:unchecked {
            image: url(:/Images/checkBox);
    }
    QCheckBox::indicator:enabled:unchecked:hover {
            image: url(:/Images/checkBoxHover);
    }
    QCheckBox::indicator:enabled:unchecked:pressed {
            image: url(:/Images/checkBoxPressed);
    }
    QCheckBox::indicator:enabled:checked {
            image: url(:/Images/checkBoxChecked);
    }
    QCheckBox::indicator:enabled:checked:hover {
            image: url(:/Images/checkBoxCheckedHover);
    }
    QCheckBox::indicator:enabled:checked:pressed {
            image: url(:/Images/checkBoxCheckedPressed);
    }
    QCheckBox::indicator:enabled:indeterminate {
            image: url(:/Images/checkBoxIndeterminate);
    }
    QCheckBox::indicator:enabled:indeterminate:hover {
            image: url(:/Images/checkBoxIndeterminateHover);
    }
    QCheckBox::indicator:enabled:indeterminate:pressed {
            image: url(:/Images/checkBoxIndeterminatePressed);
    }

    使用

    QTableView *pTableView = new QTableView(this);
    TableModel *pModel = new TableModel(this);
    CheckBoxDelegate *pDelegate = new CheckBoxDelegate(this);
    
    // 设置单行选中、最后一列拉伸、表头不高亮、无边框等
    pTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    pTableView->horizontalHeader()->setStretchLastSection(true);
    pTableView->horizontalHeader()->setHighlightSections(false);
    pTableView->verticalHeader()->setVisible(false);
    pTableView->setShowGrid(false);
    pTableView->setFrameShape(QFrame::NoFrame);
    pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    pTableView->setModel(pModel);
    pTableView->setItemDelegate(pDelegate);
    
    // 加载数据、更新界面
    QList<FileRecord> recordList;
    for (int i = 0; i < 5; ++i)
    {
        FileRecord record;
        record.bChecked = false;
        record.strFilePath = QString("E:/Qt/image_%1.png").arg(i + 1);
        recordList.append(record);
    }
    pModel->updateData(recordList);
  • 相关阅读:
    【前端】常用总结(二)
    【Golang】爬虫笔记
    ubuntu16.04安装SSH服务
    windows下配置pytorch环境
    使用VNC连接ubuntu16.4错误Authentication Failure问题
    window使用VNC远程ubuntu16.04
    ubuntu16.04安装nvidia显卡驱动
    python批量读取并显示图片,处理异常。
    将nii文件CT图像更改窗宽窗位之后保存成nii文件
    yaml.load与yaml.dump的用法
  • 原文地址:https://www.cnblogs.com/itrena/p/5938380.html
Copyright © 2011-2022 走看看