How can I insert a checkbox into the header of my view?

Currently there is no API to insert widgets in the header, but you can paint the checkbox yourself in order to insert it into the header.

What you could do is to subclass QHeaderView, reimplement paintSection() [doc.qt.nokia.com] and then call drawPrimitive() [doc.qt.nokia.com] PE_IndicatorCheckBox in the section where you want to have this checkbox.

You would also need to reimplement the mousePressEvent() [doc.qt.nokia.com] to detect when the checkbox is clicked, in order to paint the checked and unchecked states.

The example below illustrates how this can be done:

  1. #include <QtGui>
  2.  
  3. class MyHeader : public QHeaderView
  4. {
  5. public:
  6.   MyHeader(Qt::Orientation orientation, QWidget * parent = 0) : QHeaderView(orientation, parent)
  7.   {}
  8.  
  9. protected:
  10.   void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
  11.   {
  12.     painter->save();
  13.     QHeaderView::paintSection(painter, rect, logicalIndex);  
  14.     painter->restore();
  15.     if (logicalIndex == 0)
  16.     {
  17.       QStyleOptionButton option;
  18.       option.rect = QRect(10,10,10,10);
  19.       if (isOn)
  20.         option.state = QStyle::State_On;
  21.       else
  22.         option.state = QStyle::State_Off;
  23.       this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
  24.     }
  25.                
  26.   }
  27.   void mousePressEvent(QMouseEvent *event)
  28.   {
  29.     if (isOn)
  30.       isOn = false;
  31.     else
  32.       isOn = true;
  33.     this->update();
  34.     QHeaderView::mousePressEvent(event);
  35.   }
  36. private:
  37.   bool isOn;
  38. };
  39.  
  40.  
  41. int main(int argc, char **argv)
  42. {
  43.   QApplication app(argc, argv);
  44.   QTableWidget table;
  45.   table.setRowCount(4);
  46.   table.setColumnCount(3);
  47.  
  48.   MyHeader *myHeader = new MyHeader(Qt::Horizontal, &table);
  49.   table.setHorizontalHeader(myHeader);  
  50.   table.show();
  51.   return app.exec();
  52. }

To have all your other checkboxes checked, you could use the pressed() signal which should be fired from the mousePressEvent() [doc.qt.nokia.com] and connect it to a custom slot where you set all your checkboxes checked or unchecked. See:

5 comments

August 8, 2010

Picture of kenji kenji

Lab Rat

The checkbox is partially displayed in Mac OS X. And the position of checkbox is not correct in Windows, Cleanlook, Plastique and so on.

September 30, 2010

Picture of Eduard Huguet Eduard Huguet

Lab Rat

A couple of (possible) improvements:

  • You might use style()->drawControl() instead of style()->drawPrimitive(): this way, it draws a full control, not only the internal tick mark
  • You can also pass the whole section rect to the call, and drawControl() wil draw the widget left-aligned.
  • Use updateSection() instead of update(): for any unknown reason, I wasn’t receiving the painting events until the mouse left the header area. Quite weird…

Anyway, big thanks for the code tip. It’s really working fine for me right now.

April 28, 2012

Picture of Linaro Linaro

Lab Rat

checkedheader.h

  1. #ifndef CHECKEDHEADER_H
  2. #define CHECKEDHEADER_H
  3.  
  4. #include <QHeaderView>
  5. #include <QPainter>
  6. #include <QMouseEvent>
  7.  
  8. class CheckedHeader : public QHeaderView
  9. {
  10.     Q_OBJECT
  11. public:
  12.     explicit CheckedHeader(Qt::Orientation orientation, QWidget *parent = 0);
  13.  
  14.     void setChecked(bool checked);
  15.  
  16. signals:
  17.     void toggled(bool checked);
  18.  
  19. protected:
  20.     void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
  21.     void mousePressEvent(QMouseEvent *event);
  22.  
  23. private:
  24.     QRect checkBoxRect(const QRect &sourceRect) const;
  25.  
  26.     bool m_isOn;
  27. };
  28.  
  29. #endif // CHECKEDHEADER_H

checkedheader.cpp

  1. #include "checkedheader.h"
  2.  
  3. CheckedHeader::CheckedHeader(Qt::Orientation orientation, QWidget *parent)
  4.     : QHeaderView(orientation, parent)
  5.     , m_isOn(false)
  6. {
  7.     // set clickable by default
  8.     setClickable(true);
  9. }
  10.  
  11. void CheckedHeader::setChecked(bool checked)
  12. {
  13.     if (isEnabled() && m_isOn != checked)
  14.     {
  15.         m_isOn = checked;
  16.         updateSection(0);
  17.         emit toggled(m_isOn);
  18.     }
  19. }
  20.  
  21. void CheckedHeader::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
  22. {
  23.     painter->save();
  24.     QHeaderView::paintSection(painter, rect, logicalIndex);
  25.     painter->restore();
  26.     if (logicalIndex == 0)
  27.     {
  28.         QStyleOptionButton option;
  29.         if (isEnabled())
  30.             option.state |= QStyle::State_Enabled;
  31.         option.rect = checkBoxRect(rect);
  32.         if (m_isOn)
  33.             option.state |= QStyle::State_On;
  34.         else
  35.             option.state |= QStyle::State_Off;
  36.         style()->drawControl(QStyle::CE_CheckBox, &option, painter);
  37.     }
  38. }
  39.  
  40. void CheckedHeader::mousePressEvent(QMouseEvent *event)
  41. {
  42.     if (isEnabled() && logicalIndexAt(event->pos()) == 0)
  43.     {
  44.         m_isOn = !m_isOn;
  45.         updateSection(0);
  46.         emit toggled(m_isOn);
  47.     }
  48.     else QHeaderView::mousePressEvent(event);
  49. }
  50.  
  51. QRect CheckedHeader::checkBoxRect(const QRect &sourceRect) const
  52. {
  53.     QStyleOptionButton checkBoxStyleOption;
  54.     QRect checkBoxRect = style()->subElementRect(QStyle::SE_CheckBoxIndicator,
  55.                                                  &checkBoxStyleOption);
  56.     QPoint checkBoxPoint(sourceRect.x() +
  57.                          sourceRect.width() / 2 -
  58.                          checkBoxRect.width() / 2,
  59.                          sourceRect.y() +
  60.                          sourceRect.height() / 2 -
  61.                          checkBoxRect.height() / 2);
  62.     return QRect(checkBoxPoint, checkBoxRect.size());
  63. }

January 15, 2013

Picture of topher topher

Lab Rat

Somehow, I have to call update() on its parent widget to force repaint.

  1. QWidget* view = qobject_cast<QWidget*>(parent());
  2. view->update();
  3. QCoreApplication::processEvents();

June 7, 2013

Picture of The Lion The Lion

Lab Rat

A checkbox only header works fine, but a checkbox with text has some problem.
The checkbox overlays the title text behind.
How can I have it displayed like “[v] Title”, instead of “Tit[v]le”?

Write a comment

Sorry, you must be logged in to post a comment.