• Qt之QHeaderView添加复选框


    简述

    前面分享了QTableView中如何添加复选框。本节主要介绍QTableView中的表头-QHeaderView添加复选框的功能,下面以水平表头为例,垂直表头类似!

    效果

    这里写图片描述

    QHeaderView

    源码

    TableHeaderView::TableHeaderView(Qt::Orientation orientation, QWidget *parent)
        : QHeaderView(orientation, parent),
          m_bPressed(false),
          m_bChecked(false),
          m_bTristate(false),
          m_bNoChange(false),
          m_bMoving(false)
    {
        // setStretchLastSection(true);
        setHighlightSections(false);
        setMouseTracking(true);
    
        // 响应鼠标
        setSectionsClickable(true);
    }
    
    // 槽函数,用于更新复选框状态
    void TableHeaderView::onStateChanged(int state)
    {
        if (state == Qt::PartiallyChecked) {
            m_bTristate = true;
            m_bNoChange = true;
        } else {
            m_bNoChange = false;
        }
    
        m_bChecked = (state != Qt::Unchecked);
        update();
    }
    
    // 绘制复选框
    void TableHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
    {
        painter->save();
        QHeaderView::paintSection(painter, rect, logicalIndex);
        painter->restore();
    
        if (logicalIndex == CHECK_BOX_COLUMN)
        {
            QStyleOptionButton option;
            option.initFrom(this);
    
            if (m_bChecked)
                option.state |= QStyle::State_Sunken;
    
            if (m_bTristate && m_bNoChange)
                option.state |= QStyle::State_NoChange;
            else
                option.state |= m_bChecked ? QStyle::State_On : QStyle::State_Off;
            if (testAttribute(Qt::WA_Hover) && underMouse()) {
                if (m_bMoving)
                    option.state |= QStyle::State_MouseOver;
                else
                    option.state &= ~QStyle::State_MouseOver;
            }
    
            QCheckBox checkBox;
            option.iconSize = QSize(20, 20);
            option.rect = rect;
            style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, &checkBox);
            //style()->drawItemPixmap(painter, rect, Qt::AlignCenter, QPixmap(":/images/checkBoxChecked"));
            //style()->drawControl(QStyle::CE_CheckBox, &option, painter, this);
        }
    }
    
    // 鼠标按下表头
    void TableHeaderView::mousePressEvent(QMouseEvent *event)
    {
        int nColumn = logicalIndexAt(event->pos());
        if ((event->buttons() & Qt::LeftButton) && (nColumn == CHECK_BOX_COLUMN))
        {
            m_bPressed = true;
        }
        else
        {
            QHeaderView::mousePressEvent(event);
        }
    }
    
    // 鼠标从表头释放,发送信号,更新model数据
    void TableHeaderView::mouseReleaseEvent(QMouseEvent *event)
    {
        if (m_bPressed)
        {
            if (m_bTristate && m_bNoChange)
            {
                m_bChecked = true;
                m_bNoChange = false;
            }
            else
            {
                m_bChecked = !m_bChecked;
            }
    
            update();
    
            Qt::CheckState state = m_bChecked ? Qt::Checked : Qt::Unchecked;
    
            emit stateChanged(state);
        }
        else
        {
            QHeaderView::mouseReleaseEvent(event);
        }
    
        m_bPressed = false;
    }
    
    // 鼠标滑过、离开,更新复选框状态
    bool TableHeaderView::event(QEvent *event)
    {
        if (event->type() == QEvent::Enter || event->type() == QEvent::Leave)
        {
            QMouseEvent *pEvent = static_cast<QMouseEvent *>(event);
            int nColumn = logicalIndexAt(pEvent->x());
            if (nColumn == CHECK_BOX_COLUMN)
            {
                m_bMoving = (event->type() == QEvent::Enter);
    
                update();
                return true;
            }
        }
    
        return QHeaderView::event(event);
    }
    

    接口说明

    • onStateChanged
      槽函数,与model关联,当model的数据发生变化时,表头复选中状态也随之变化。

    • paintSection
      绘制部分,主要用于绘制复选框,主要设置QStyleOptionButton的状态,然后通过QStyle的drawPrimitive绘制样式。

    • mousePressEvent
      鼠标按下表头,设置被按下的标志为true。

    • mouseReleaseEvent
      鼠标从表头释放,发送信号,更新model数据。

    • event
      鼠标滑过、离开,更新复选框状态。

    QAbstractTableModel

    源码

    源码过多,这里只贴更改部分及新增部分,其它部分请参考:Qt之QTableView添加复选框(QAbstractItemDelegate)

    // 设置表格项数据
    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);
    
                if (role == Qt::UserRole)
                    onStateChanged();
                return true;
            }
        }
        default:
            return false;
        }
        return false;
    }
    
    // 复选状态改变,通知表头更新复选状态
    void TableModel::onStateChanged()
    {
        Qt::CheckState state = Qt::Unchecked;
        int nCount = m_recordList.count();
        int nSelectedCount = 0;
        FileRecord record;
        for (int i = 0; i < nCount; ++i)
        {
            record = m_recordList.at(i);
            if (record.bChecked)
                ++nSelectedCount;
        }
    
        if (nSelectedCount >= nCount)
        {
            state = Qt::Checked;
        }
        else if (nSelectedCount > 0)
        {
            state = Qt::PartiallyChecked;
        }
    
        emit stateChanged(state);
    }
    
    // 接收表头复选状态更新变化,修改表格复选状态
    void TableModel::onStateChanged(int state)
    {
        QModelIndex index;
        for (int i = 0; i < rowCount(); ++i)
        {
            index = this->index(i, CHECK_BOX_COLUMN);
            setData(index, state == Qt::Checked, Qt::CheckStateRole);
        }
    }

    接口说明

    • setData
      设置表格项数据,关键代码:当role为Qt::UserRole时候,会调用onStateChanged()函数,来更新表头!

    • onStateChanged
      复选状态改变,通知表头更新复选状态。

    • onStateChanged(int state)
      槽函数,接收表头复选状态更新变化,修改表格复选状态。

    使用

    这时,就需要将header与model的信号与槽关联起来,更新复选框状态了!

    QTableView *pTableView = new QTableView(this);
    TableModel *pModel = new TableModel(this);
    TableHeaderView *pHeader = new TableHeaderView(Qt::Horizontal, this);
    CheckBoxDelegate *pDelegate = new CheckBoxDelegate(this);
    
    pTableView->setHorizontalHeader(pHeader);
    pTableView->setModel(pModel);
    pTableView->setItemDelegate(pDelegate);
    
    connect(pModel, SIGNAL(stateChanged(int)), pHeader, SLOT(onStateChanged(int)));
    connect(pHeader, SIGNAL(stateChanged(int)), pModel, SLOT(onStateChanged(int)));
  • 相关阅读:
    ASP.NET Web开发框架之二 数据输入窗体
    针对HTML5的更新和Unobtrusive Validation
    框架:从MVC到开放API
    使用SSIS创建同步数据库数据任务
    MVC里的Filters
    类型构造器也称为静态构造器,类构造器,或类型初始化器
    铁道部新客票系统设计(二)
    深入浅出SQL Server中的死锁
    你所能用到的数据结构(一)
    python网络编程学习笔记(6):Web客户端访问
  • 原文地址:https://www.cnblogs.com/itrena/p/5938379.html
Copyright © 2020-2023  润新知