title: QHeaderView with checkbox - how to differentiate clicking right on the header checkbox from clicking anywhere in the cell
body: <p>I have a custom header <code>QProduitCartoHeaderView</code> defined in a class inheriting from <code>QHeaderView</code>.</p>
  <p>In my header I have a checkbox used to check/uncheck all the checkboxes in the same column
  for all rows of data.</p>
  <p><a href="https://i.stack.imgur.com/Nx3Jx.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Nx3Jx.png" alt="enter image description here" /></a></p>
  <p>Currently when I click anywhere in the header cell of the first column (the one with checkbox),
  It checks the header checkbox.</p>
  <p>What I would like to do is to only check the checkbox when I click <strong>exactly</strong> on it and if I click outside (<strong>but still within the cell</strong>) to sort the first column.</p>
  <p>I have tried to resize the checkbox rectangle (as seen in <code>QProduitCartoHeaderView::paintSection()</code> in the snippet below) but when I click anywhere in the cell (<strong>not on the checkbox</strong>), I still get it checked.</p>
  <p>Note: I already managed to make the code to sort and to check. What I cannot do is to check
  whether I click on the checkbox or outside the checkbox within the cell.</p>
  <p>Here is a snippet of my custom header:</p>
  <ul>
  <li>QProduitCartoHeaderView.h</li>
  </ul>
  <pre class="lang-cpp prettyprint-override"><code>#ifndef QPRODUITCARTOHEADERVIEW_H
  #define QPRODUITCARTOHEADERVIEW_H
  
  #include &lt;QWidget&gt;
  #include &lt;QPainter&gt;
  #include &lt;QHeaderView&gt;
  #include &lt;QMessageBox&gt;
  
  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 &amp; oRect, int index) const;
      virtual void mouseReleaseEvent(QMouseEvent *e);
  
  
  private:
      bool isOn = false, pasTousLesMeme = false;
  
  
  signals:
      void dataModifiedSig();
  
  };
  #endif
  </code></pre>
  <ul>
  <li>QProduitCartoHeaderView.cpp (only useful code to avoid long post)</li>
  </ul>
  <pre class="lang-cpp prettyprint-override"><code>#ifndef QPRODUITCARTOHEADERVIEW_H
  #include &quot;QProduitCartoHeaderView.h&quot;
  #endif
  #ifndef QPRODUITCARTODATAMODEL_H
  #include &quot;QProduitCartoDataModel.h&quot;
  #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 &amp; oRect, int index) const
  {
      poPainter-&gt;save();
  
      QHeaderView::paintSection(poPainter, oRect, index);
      poPainter-&gt;restore();
  
      QStyleOptionButton option;
  
  
      QRect checkbox_rect = style()-&gt;subElementRect(QStyle::SE_CheckBoxIndicator, &amp;option);
      checkbox_rect.moveCenter(oRect.center());
      // pour la colonne 1
      if (index == 0)
      {
          qDebug() &lt;&lt; checkbox_rect &lt;&lt; &quot; -- &quot; &lt;&lt; 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-&gt;style()-&gt;drawPrimitive(QStyle::PE_IndicatorCheckBox, &amp;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-&gt;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-&gt;update();
          // fin update
  
          int nbRow = this-&gt;model()-&gt;rowCount();
  
          // on met tout à false si la majorité est à true
          int nbTrue = 0;
  
  
          if (all_first_columns_checked(logicalIndex))
          {
              for (int r = 0; r &lt; nbRow; r++)
              {
                  QModelIndex index = this-&gt;model()-&gt;index(r, logicalIndex);
  
                  the_Model-&gt;setData(index, false, Qt::CheckStateRole);
              }
          }
          else
          {
              // on efface d'abord tout
              for (int r = 0; r &lt; nbRow; r++)
              {
                  QModelIndex index = this-&gt;model()-&gt;index(r, logicalIndex);
  
                  bool checked = this-&gt;model()-&gt;data(index, Qt::DisplayRole).toBool();
                  if (checked)
                      the_Model-&gt;setData(index, false, Qt::CheckStateRole);
              }
  
  
  
              // Ensuite, on fait le flip/flop
              for (int r = 0; r &lt; nbRow; r++)
              {
                  QModelIndex index = this-&gt;model()-&gt;index(r, logicalIndex);
                  // update each row of real data
                  the_Model-&gt;setData(index, true, Qt::CheckStateRole);
                  
              }
          }
      }
  
      emit dataModifiedSig();
  }
  </code></pre>