• Qt之QTableView添加复选框(QAbstractTableModel)


    简述

    使用QTableView,经常会遇到复选框,要实现一个好的复选框,除了常规的功能外,还应注意以下几点:

    1. 三态:不选/半选/全选
    2. 自定义风格(样式)

    下面我们介绍一下常见的实现方式:

    • 编辑委托。
      方式:利用委托重载createEditor(),激活QCheckBox。
      特点:必须双击/选中,才能显示CheckBox控件。一般不满足实际中的直接显示的需要。

    • 使用QTableView的setIndexWidget(const QModelIndex &index, QWidget *widget)来实现。
      此功能用来显示可视区域内对应一个数据项的静态内容。如果想显示自定义的动态内容或执行自定义编辑器部件,子类化QItemDelegate代替。也就是说,这只适合做静态数据的显示,不适合做一些插入、更新、删除操作的数据显示。

    • 自定义模型QAbstractTableModel,通过flags()函数来实现。
      方式:通过将flags()设置为Qt::ItemIsUserCheckable实现可选中,然后配合setData()与data()来实现。
      特点:直接显示,可定义样式,默认左对齐,很难实现居中、右对齐。

    • 自定义委托QAbstractItemDelegate,通过paint()函数来实现。
      方式:通过控制editorEvent()实现鼠标的点击进行全选/半选/不选,然后由paint()实时绘制。
      特点:这种方式比较复杂,但适合扩展,除了可以嵌入复选框,还可以绘制其它控件-按钮、图片等。

    效果

    这里写图片描述

    下面我们来介绍如何利用QAbstractTableModel的flags()函数来实现复选功能。

    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:
        {
            if (nColumn == CHECK_BOX_COLUMN)
            {
                record.bChecked = (value.toInt() == Qt::Checked);
    
                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::CheckStateRole:
        {
            if (nColumn == CHECK_BOX_COLUMN)
                return record.bChecked ? Qt::Checked : Qt::Unchecked;
        }
        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;
        if (index.column() == CHECK_BOX_COLUMN)
            flags |= Qt::ItemIsUserCheckable;
    
        return flags;
    }

    接口说明

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

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

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

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

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

    样式

    QSS不仅可以设置表格、表格项样式(背景、文本等),也可以通过indicator来设置复选框的样式:

    QTableView {
            border: 1px solid rgb(50, 50, 50);
            background: rgb(57, 58, 60);
            gridline-color: rgb(60, 60, 60);
    }
    QTableView::item {
            border: none;
            border-bottom: 1px solid rgb(50, 50, 50);
    }
    QTableView::item:selected {
            background: rgb(0, 160, 230);
    }
    QTableView::indicator {
            width: 17px;
            height: 17px;
    }
    QTableView::indicator:enabled:unchecked {
            image: url(:/Images/checkBox);
    }
    QTableView::indicator:enabled:unchecked:hover {
            image: url(:/Images/checkBoxHover);
    }
    QTableView::indicator:enabled:unchecked:pressed {
            image: url(:/Images/checkBoxPressed);
    }
    QTableView::indicator:enabled:checked {
            image: url(:/Images/checkBoxChecked);
    }
    QTableView::indicator:enabled:checked:hover {
            image: url(:/Images/checkBoxCheckedHover);
    }
    QTableView::indicator:enabled:checked:pressed {
            image: url(:/Images/checkBoxCheckedPressed);
    }
    QTableView::indicator:enabled:indeterminate {
            image: url(:/Images/checkBoxIndeterminate);
    }
    QTableView::indicator:enabled:indeterminate:hover {
            image: url(:/Images/checkBoxIndeterminateHover);
    }
    QTableView::indicator:enabled:indeterminate:pressed {
            image: url(:/Images/checkBoxIndeterminatePressed);
    }

    使用

    QTableView *pTableView = new QTableView(this);
    TableModel *pModel = new TableModel(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);
    
    // 加载数据、更新界面
    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);
  • 相关阅读:
    Token ,Cookie和Session的区别
    极致Web性能 —— SPA性能指南
    关于前端数据&逻辑的思考
    移动端Retina屏boder 1px显示为2px或3px的解决方法
    Java连载8-基本数据类型2
    HTML连载25-通配符选择器&选择器综合练习
    Python连载25-函数tell&write&writeline$&持久化
    Python连载24-函数list&read&seek
    Java连载7-变量&数据类型
    HTML连载24-属性选择器(下)
  • 原文地址:https://www.cnblogs.com/itrena/p/5938381.html
Copyright © 2020-2023  润新知