带有复选框的QHeaderView-如何区分在标题复选框上单击右键与在单元格中的任何位置单击

问题描述

我在从QProduitCartoHeaderView继承的类中定义了自定义标头QHeaderView

标题中有一个复选框,用于选中/取消选中同一列中的所有复选框 用于所有数据行。

enter image description here

当前,当我单击第一列的标题单元格中的任何位置(带有复选框的那个位置)时, 它会检查标题复选框。

我想做的是仅在我完全点击 时,以及在外部(但仍在单元格内)单击以对复选框进行排序时,才选中该复选框。第一列。

我试图调整复选框矩形的大小(如下面的片段中的QProduitCartoHeaderView::paintSection()所示),但是当我单击单元格中的任意位置(不在复选框上)时,我仍然得到它检查了。

注意:我已经设法对代码进行排序和检查。我不能做的就是检查 是单击复选框还是在单元格中的复选框之外。

这是我的自定义标头的摘要

  • 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,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,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,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);
}