我在从QProduitCartoHeaderView继承的类中定义了一个自定义 header QHeaderView
在标题中,我有一个复选框用于选中/取消选中同一列中的所有复选框
用于所有数据行。
c++ - 带有复选框的QHeaderView-如何区分在标题复选框上单击右键与在单元格中的任何位置单击-LMLPHP
当前,当我单击第一列的标题单元格中的任何位置(带有复选框的位置)时,
它检查标题复选框。
我想做的是仅在我单击上恰好在上时单击该复选框,并且如果我单击外部(但仍在单元格内)以对第一列进行排序,则仅选中该复选框。
我尝试过调整复选框矩形的大小(如下面的片段中的QProduitCartoHeaderView::paintSection()所示),但是当我单击单元格中的任意位置(不在复选框上)时,我仍然将其选中。
注意:我已经设法对代码进行排序和检查。我不能做的就是检查
是单击复选框还是在单元格中的复选框之外。
这是我的自定义 header 的代码段:

  • QProduitCartoHeaderView.h

  • #ifndef QPRODUITCARTOHEADERVIEW_H
    #define QPRODUITCARTOHEADERVIEW_H
    
    #include <QWidget>
    #include <QPainter>
    #include <QHeaderView>
    #include <QMessageBox>
    
    class QProduitCartoHeaderView :public QHeaderView
    {
        Q_OBJECT
    public:
        QProduitCartoHeaderView(QWidget * parent = 0);
        ~QProduitCartoHeaderView();
        void on_sectionClicked(int logicalIndex);
        bool all_first_columns_checked(int logicalIndex = 0);
        bool all_first_columns_unchecked(int logicalIndex=0);
        void setIsOn(bool val);
        void setPasTousLesMeme(bool val);
    
    protected:
        virtual void paintSection(QPainter* poPainter, const QRect & oRect, int index) const;
        virtual void mouseReleaseEvent(QMouseEvent *e);
    
    
    private:
        bool isOn = false, pasTousLesMeme = false;
    
    
    signals:
        void dataModifiedSig();
    
    };
    #endif
    
  • QProduitCartoHeaderView.cpp(仅有用的代码,避免冗长的帖子)

  • #ifndef QPRODUITCARTOHEADERVIEW_H
    #include "QProduitCartoHeaderView.h"
    #endif
    #ifndef QPRODUITCARTODATAMODEL_H
    #include "QProduitCartoDataModel.h"
    #endif
    
    QProduitCartoHeaderView::QProduitCartoHeaderView(QWidget* parent) : QHeaderView(Qt::Horizontal, parent)
    {
    }
    
    QProduitCartoHeaderView::~QProduitCartoHeaderView()
    {
    }
    
    void QProduitCartoHeaderView::setIsOn(bool val)
    {
        isOn = val;
    }
    
    void QProduitCartoHeaderView::setPasTousLesMeme(bool val)
    {
        //set if all checkboxes have different value or not
        pasTousLesMeme = val;
    }
    
    void QProduitCartoHeaderView::paintSection(QPainter* poPainter, const QRect & oRect, int index) const
    {
        poPainter->save();
    
        QHeaderView::paintSection(poPainter, oRect, index);
        poPainter->restore();
    
        QStyleOptionButton option;
    
    
        QRect checkbox_rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
        checkbox_rect.moveCenter(oRect.center());
        // pour la colonne 1
        if (index == 0)
        {
            qDebug() << checkbox_rect << " -- " << oRect;
            // position
            option.state = QStyle::State_Enabled | QStyle::State_Active;
            option.rect = checkbox_rect;
            QHeaderView::paintSection(poPainter, checkbox_rect, index);
            if (isOn)
            {
                // on a tout coché
                option.state |= QStyle::State_On;
            }
            else
            { // traite pas tout coché
    
                // on rajoute le troisième état (third state)
                // quand on n'a pas tout coché mais pas tout décoché non plus
                if ( pasTousLesMeme )
                {
                    option.state |= QStyle::State_NoChange;
                }
                else
                {
                    // et si on a tout décoché, on décoche (isOn = false et pasTouslesMemes=false)
                    option.state |= QStyle::State_Off;
                }
    
            }
    
            // on redessine alors la checkbox
            this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, poPainter);
        }
    }
    
    void QProduitCartoHeaderView::mouseReleaseEvent(QMouseEvent *e)
    {
       QHeaderView::mouseReleaseEvent(e);
    }
    
    bool QProduitCartoHeaderView::all_first_columns_checked(int logicalIndex)
    {
    //code to check if all first colum is checked
    
    }
    
    bool QProduitCartoHeaderView::all_first_columns_unchecked(int logicalIndex)
    {
    
    //code to check if all first colum is unchecked
    }
    
    void QProduitCartoHeaderView::on_sectionClicked(int logicalIndex)
    {
        // code pour le click du header contenant les checkboxes
    
        QProduitCartoDataModel* the_Model = (QProduitCartoDataModel*) this->model();
    
        if (logicalIndex == 0)
        {
    
            // on update l'état du checkbox principale (si isOn = true, la checkbox est cochée)
            if (isOn)
            {
                // si elle est cochée, on la met à false (pour flip/flop)
                isOn = false;
                // mais si tout est décoché, alors, on met la checkbox à false
                if (all_first_columns_unchecked(logicalIndex))
                {
                    isOn = true;
                }
    
            }
            else
            {
                isOn = true;
                if (all_first_columns_checked(logicalIndex))
                {
                    isOn = false;
                }
            }
    
            this->update();
            // fin update
    
            int nbRow = this->model()->rowCount();
    
            // on met tout à false si la majorité est à true
            int nbTrue = 0;
    
    
            if (all_first_columns_checked(logicalIndex))
            {
                for (int r = 0; r < nbRow; r++)
                {
                    QModelIndex index = this->model()->index(r, logicalIndex);
    
                    the_Model->setData(index, false, Qt::CheckStateRole);
                }
            }
            else
            {
                // on efface d'abord tout
                for (int r = 0; r < nbRow; r++)
                {
                    QModelIndex index = this->model()->index(r, logicalIndex);
    
                    bool checked = this->model()->data(index, Qt::DisplayRole).toBool();
                    if (checked)
                        the_Model->setData(index, false, Qt::CheckStateRole);
                }
    
    
    
                // Ensuite, on fait le flip/flop
                for (int r = 0; r < nbRow; r++)
                {
                    QModelIndex index = this->model()->index(r, logicalIndex);
                    // update each row of real data
                    the_Model->setData(index, true, Qt::CheckStateRole);
    
                }
            }
        }
    
        emit dataModifiedSig();
    }
    

    最佳答案

    您可以跟踪鼠标并重新实现mousePressEvent(QMouseEvent *event)mouseReleaseEvent(QMouseEvent *event)来确定单击该部分的位置。我在下面创建了一个示例:
    myheaderview.h

    #ifndef MYHEADERVIEW_H
    #define MYHEADERVIEW_H
    
    #include <QHeaderView>
    
    class MyHeaderView : public QHeaderView
    {
    public:
        MyHeaderView(QWidget *parent = nullptr);
    
        QRect visualRectOfColumn(int column) const;
    
    protected:
        virtual void paintSection(QPainter *painter, const QRect &rect, int index) const;
        virtual void mousePressEvent(QMouseEvent *event);
        virtual void mouseReleaseEvent(QMouseEvent *event);
    
    private:
        int press_column_{-1};
        bool checkbox_pressed_{false};
    };
    
    #endif // MYHEADERVIEW_H
    
    myheaderview.cpp
    #include "myheaderview.h"
    
    #include <QPainter>
    #include <QMouseEvent>
    #include <QDebug>
    
    MyHeaderView::MyHeaderView(QWidget *parent) : QHeaderView(Qt::Horizontal, parent)
    {
        this->setMouseTracking(true);
    }
    
    QRect MyHeaderView::visualRectOfColumn(int column) const
    {
        int x = sectionViewportPosition(column);
        int y = 0;
        int h = this->height();
        int w = this->sectionSize(column);
        return QRect(x, y, w, h);
    }
    
    void MyHeaderView::paintSection(QPainter *painter, const QRect &rect, int index) const
    {
        painter->save();
        QHeaderView::paintSection(painter, rect, index);
        painter->restore();
    
        if (index == 0)
        {
            QStyleOptionButton option;
            QRect checkbox_rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
            checkbox_rect.moveCenter(rect.center());
    
            option.state = QStyle::State_Enabled | QStyle::State_Active;
            option.rect = checkbox_rect;
            QHeaderView::paintSection(painter, checkbox_rect, index);
            this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
        }
    }
    
    void MyHeaderView::mousePressEvent(QMouseEvent *event)
    {
        press_column_ = this->visualIndexAt(event->pos().x());
        if (press_column_ == -1)
        {
            checkbox_pressed_= false;
            return QHeaderView::mousePressEvent(event);;
        }
    
        QStyleOptionButton option;
        QRect checkbox_rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
        checkbox_rect.moveCenter(this->visualRectOfColumn(press_column_).center());
        checkbox_pressed_= checkbox_rect.contains(event->pos());
    
        QHeaderView::mousePressEvent(event);
    }
    
    void MyHeaderView::mouseReleaseEvent(QMouseEvent *event)
    {
        int release_column = this->visualIndexAt(event->pos().x());
        if (release_column != -1 && press_column_ == release_column)
        {
            if (release_column != 0)
                qDebug() << "sort";
            else
            {
                QStyleOptionButton option;
                QRect checkbox_rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
                checkbox_rect.moveCenter(this->visualRectOfColumn(release_column).center());
                if (checkbox_pressed_&& checkbox_rect.contains(event->pos()))
                    qDebug() << "checkbox";
                else if (!checkbox_pressed_&& !checkbox_rect.contains(event->pos()))
                    qDebug() << "sort";
            }
        }
    
        press_column_ = -1;
        checkbox_pressed_= false;
        QHeaderView::mouseReleaseEvent(event);
    }
    

    07-28 01:32
    查看更多