QTableView添加选择框

在这里插入图片描述

可单选,水平全选,取消全选,垂直可单选,水平全选,取消全选。主要实现方式是通过继承
class QtCheckHeaderView: public QHeaderView
//下面是QtCheckHeaderView的代码

#ifndef QTCHECKHEADERVIEW_H
#define QTCHECKHEADERVIEW_H

#include <QHeaderView>
#include <QList>
#include <QMap>

class QAbstractItemModel;

class QtCheckHeaderView: public QHeaderView
{
    Q_OBJECT

public:
    explicit QtCheckHeaderView(Qt::Orientation orientation, QWidget *parent = 0);
    virtual ~QtCheckHeaderView();

    QList<int> checkableIndexes() const
    {
        return mCheckableIndexes;
    }

    bool addCheckable(int logicalIndex)
    {
        if (model() && !mCheckableIndexes.contains(logicalIndex))
        {
            mCheckableIndexes.append(logicalIndex);
            mCheckStates.insert(logicalIndex, Qt::Unchecked);
            updateCheckbox(logicalIndex);
            return true;
        }
        return false;
    }

    void removeCheckable(int logicalIndex)
    {
        mCheckableIndexes.removeOne(logicalIndex);
        mCheckStates.remove(logicalIndex);
    }

    void setModel(QAbstractItemModel* model);

protected slots:
    virtual void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight);

protected:
    void mousePressEvent(QMouseEvent* event);
    void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const;

    QList<int> mCheckableIndexes;
    QMap<int, Qt::CheckState> mCheckStates;
    bool blockDataChanged;
    mutable QMap<int, QRect> mSectionRects;

    void updateCheckbox(int logicalIndex);
    void updateModel(int logicalIndex);

    QRect checkRect(const QStyleOptionHeader& option, const QRect& bounding) const;

    inline bool rowIntersectsSelection(int row) const
    {
        return (selectionModel() ? selectionModel()->rowIntersectsSelection(row, rootIndex()) : false);
    }

    inline bool columnIntersectsSelection(int column) const
    {
        return (selectionModel() ? selectionModel()->columnIntersectsSelection(column, rootIndex()) : false);
    }

    inline bool sectionIntersectsSelection(int logical) const
    {
        return (orientation() == Qt::Horizontal ? columnIntersectsSelection(logical) : rowIntersectsSelection(
                                                      logical));
    }

    inline bool isRowSelected(int row) const
    {
        return (selectionModel() ? selectionModel()->isRowSelected(row, rootIndex()) : false);
    }

    inline bool isColumnSelected(int column) const
    {
        return (selectionModel() ? selectionModel()->isColumnSelected(column, rootIndex()) : false);
    }
};

#endif // QTCHECKHEADERVIEW_H

#include "QtCheckHeaderView.h"

#include <QMouseEvent>
#include <QApplication>
#include <QPainter>
#include <QStyleOptionViewItem>

QRect QtCheckHeaderView::checkRect(const QStyleOptionHeader& option, const QRect& bounding) const
{
    QStyleOptionButton opt;
    opt.QStyleOption::operator=(option);
    opt.rect = bounding;
    QRect cr = style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt);

    if (orientation() == Qt::Horizontal)
    {
        int deltaY = (bounding.height() - cr.height()) / 2;
        return QRect(bounding.left() + 2, bounding.top() + deltaY, cr.width(), cr.height());
    }
    else if (orientation() == Qt::Vertical)
    {
        int deltaX = (bounding.width() - cr.width()) / 2;
        return QRect(bounding.left() + deltaX, bounding.top() + 2, cr.width(), cr.height());
    }
    return QRect();
}

QtCheckHeaderView::QtCheckHeaderView(Qt::Orientation orientation, QWidget *parent)
    :QHeaderView(orientation, parent), blockDataChanged(false)
{

}

QtCheckHeaderView::~QtCheckHeaderView()
{

}

void QtCheckHeaderView::setModel(QAbstractItemModel* model)
{
    mSectionRects.clear();
    QHeaderView::setModel(model);

    foreach(int logicalIndex, mCheckableIndexes)
    {
        updateCheckbox(logicalIndex);
    }
}

void QtCheckHeaderView::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight)
{
    if (blockDataChanged)
        return;

    if (orientation() == Qt::Horizontal)
    {
        for (int i = topLeft.column(); i <= bottomRight.column(); ++i)
        {
            if (mCheckableIndexes.contains(i))
            {
                updateCheckbox(i);
                updateSection(i);
            }
        }
    }
    else if (orientation() == Qt::Vertical)
    {
        for (int i = topLeft.row(); i <= bottomRight.row(); ++i)
        {
            if (mCheckableIndexes.contains(i))
            {
                updateCheckbox(i);
                updateSection(i);
            }
        }
    }
}

void QtCheckHeaderView::mousePressEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton)
    {
        int logicalIndex = logicalIndexAt(event->pos());
        QStyleOptionHeader opt;
        initStyleOption(&opt);
        QRect rect = checkRect(opt, mSectionRects.value(logicalIndex));
        if (rect.contains(event->pos()))
        {
            if (mCheckableIndexes.contains(logicalIndex))
            {
                blockDataChanged = true;
                if (mCheckStates.value(logicalIndex) == Qt::Checked)
                {
                    mCheckStates.insert(logicalIndex, Qt::Unchecked);
                }
                else if (mCheckStates.value(logicalIndex) == Qt::Unchecked)
                {
                    mCheckStates.insert(logicalIndex, Qt::Checked);
                }
                else if (mCheckStates.value(logicalIndex) == Qt::PartiallyChecked)
                {
                    mCheckStates.insert(logicalIndex, Qt::Checked);
                }
                updateModel(logicalIndex);
                blockDataChanged = false;
                updateCheckbox(logicalIndex);
                updateSection(logicalIndex);
                return;
            }
        }
    }

    QHeaderView::mousePressEvent(event);
}

void QtCheckHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const
{
    mSectionRects.insert(logicalIndex, rect);
    if (mCheckableIndexes.contains(logicalIndex))
    {
        painter->save();

        QStyleOptionHeader opt;
        initStyleOption(&opt);
        QStyle::State state = QStyle::State_None;
        if (isEnabled())
            state |= QStyle::State_Enabled;
        if (window()->isActiveWindow())
            state |= QStyle::State_Active;

        QPoint cursorPos = mapFromGlobal(cursor().pos());
        bool containMouse = rect.contains(cursorPos);
        if (this->sectionsClickable())
        {
            if (containMouse)
                state |= QStyle::State_MouseOver;
            if (containMouse && (QApplication::mouseButtons() && (Qt::LeftButton || Qt::RightButton)))
                state |= QStyle::State_Sunken;
            else if (highlightSections())
            {
                if (sectionIntersectsSelection(logicalIndex))
                    state |= QStyle::State_On;
            }
        }

        // setup the style options structure
        QVariant textAlignment = model()->headerData(logicalIndex, orientation(), Qt::TextAlignmentRole);
        opt.rect = rect;
        opt.section = logicalIndex;
        opt.state |= state;
        opt.textAlignment = Qt::Alignment(textAlignment.isValid() ? Qt::Alignment(textAlignment.toInt())
                                                                  : defaultAlignment());

        if (isSortIndicatorShown())
        {
            if (sortIndicatorSection() == logicalIndex)
            {
                if (sortIndicatorOrder() == Qt::AscendingOrder)
                {
                    opt.sortIndicator = QStyleOptionHeader::SortDown;
                }
                else
                {
                    opt.sortIndicator = QStyleOptionHeader::SortUp;
                }
            }
        }
        else
        {
            opt.sortIndicator = QStyleOptionHeader::None;
        }

        opt.iconAlignment = Qt::AlignVCenter;

        QVariant variant = model()->headerData(logicalIndex, orientation(), Qt::DecorationRole);
        opt.icon = qvariant_cast<QIcon> (variant);
        if (opt.icon.isNull())
            opt.icon = qvariant_cast<QPixmap> (variant);
        QVariant foregroundBrush = model()->headerData(logicalIndex, orientation(), Qt::ForegroundRole);
        if (foregroundBrush.canConvert<QBrush>())
            opt.palette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush> (foregroundBrush));

        QVariant backgroundBrush = model()->headerData(logicalIndex, orientation(), Qt::BackgroundRole);
        if (backgroundBrush.canConvert<QBrush>())
        {
            opt.palette.setBrush(QPalette::Button, qvariant_cast<QBrush> (backgroundBrush));
            opt.palette.setBrush(QPalette::Window, qvariant_cast<QBrush> (backgroundBrush));
            painter->setBrushOrigin(opt.rect.topLeft());
        }

        // the section position
        int visual = visualIndex(logicalIndex);
        Q_ASSERT(visual != -1);
        if (count() == 1)
            opt.position = QStyleOptionHeader::OnlyOneSection;
        else if (visual == 0)
            opt.position = QStyleOptionHeader::Beginning;
        else if (visual == count() - 1)
            opt.position = QStyleOptionHeader::End;
        else
            opt.position = QStyleOptionHeader::Middle;
        opt.orientation = orientation();
        // the selected position
        bool previousSelected = sectionIntersectsSelection(this->logicalIndex(visual - 1));
        bool nextSelected = sectionIntersectsSelection(this->logicalIndex(visual + 1));
        if (previousSelected && nextSelected)
            opt.selectedPosition = QStyleOptionHeader::NextAndPreviousAreSelected;
        else if (previousSelected)
            opt.selectedPosition = QStyleOptionHeader::PreviousIsSelected;
        else if (nextSelected)
            opt.selectedPosition = QStyleOptionHeader::NextIsSelected;
        else
            opt.selectedPosition = QStyleOptionHeader::NotAdjacent;
        // draw the section
        style()->drawControl(QStyle::CE_Header, &opt, painter, this);
        painter->restore();

        opt.text = model()->headerData(logicalIndex, orientation(), Qt::DisplayRole).toString();
        if (textElideMode() != Qt::ElideNone)
            opt.text = opt.fontMetrics.elidedText(opt.text, textElideMode(), rect.width() - 4);

        QRect check = checkRect(opt, opt.rect);

        if (orientation() == Qt::Horizontal)
        {
            opt.rect.setLeft(check.right());
        } else if (orientation() == Qt::Vertical)
        {
            opt.rect.setTop(check.bottom());
        }

        style()->drawControl(QStyle::CE_HeaderLabel, &opt, painter, this);


        // ===============================================================
        // Draw checkbox
        QStyleOptionButton option;
        option.QStyleOption::operator =(opt);
        option.rect = checkRect(opt, rect);
        //option.rect = QRect(10, 10, 10, 10);

        switch (mCheckStates.value(logicalIndex))
        {
        case Qt::Checked:
            option.state |= QStyle::State_On;
            break;
        case Qt::Unchecked:
            option.state |= QStyle::State_Off;
            break;
        case Qt::PartiallyChecked:
            option.state |= QStyle::State_NoChange;
            break;
        }
        style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);

        // ===============================================================
    }
    else
    {
        QHeaderView::paintSection(painter, rect, logicalIndex);
    }
}

void QtCheckHeaderView::updateCheckbox(int logicalIndex)
{
    bool allchecked = true;
    bool allunchecked = true;

    if (orientation() == Qt::Horizontal)
    {
        for (int i = 0; i < model()->rowCount(rootIndex()); ++i)
        {
            if (model()->index(i, logicalIndex, rootIndex()).data(Qt::CheckStateRole).toInt())
            {
                allunchecked = false;
            }
            else
            {
                allchecked = false;
            }
        }
    }
    else if (orientation() == Qt::Vertical)
    {
        for (int i = 0; i < model()->columnCount(rootIndex()); ++i)
        {
            if (model()->index(logicalIndex, i, rootIndex()).data(Qt::CheckStateRole).toInt())
            {
                allunchecked = false;
            }
            else
            {
                allchecked = false;
            }
        }
    }
    if (allunchecked)
    {
        mCheckStates.insert(logicalIndex, Qt::Unchecked);
    }
    else if (allchecked)
    {
        mCheckStates.insert(logicalIndex, Qt::Checked);
    }
    else
    {
        mCheckStates.insert(logicalIndex, Qt::PartiallyChecked);
    }
}

void QtCheckHeaderView::updateModel(int logicalIndex)
{
    Qt::CheckState checked = mCheckStates.value(logicalIndex);

    if (orientation() == Qt::Horizontal)
    {
        for (int i = 0; i < model()->rowCount(rootIndex()); ++i)
        {
            model()->setData(model()->index(i, logicalIndex, rootIndex()), checked, Qt::CheckStateRole);
        }
    }
    else if (orientation() == Qt::Vertical)
    {
        for (int i = 0; i < model()->columnCount(rootIndex()); ++i)
        {
            model()->setData(model()->index(logicalIndex, i, rootIndex()), checked, Qt::CheckStateRole);
        }
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vqt5_qt6

你的鼓励是我们创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值