2

I need to customize the QCheckbox like this: add a square between the checkbox and the text Example:

So to do this, I inherit QCheckBox and override paintEvent(QPaintEvent*):

void customCheckBox::paintEvent(QPaintEvent*){
      QPainter p(this);
      QStyleOptionButton opt;
      initStyleOption(&opt);
      style()->drawControl(QStyle::CE_CheckBox,&opt,&p,this);

      QFontMetrics font= this->fontMetrics();// try to get pos by bounding rect of text, but it ain't work :p
      QRectF rec = font.boundingRect(this->text());
      p.fillRect(rect,QBrush(QColor(125,125,125,128)));
      p.drawRect(rect);

}

I have a problem that I don't know how the position to place the QRectF rec. And I can't set the size too small, eg: it will disappear when size of rec < QSize(10,10).

Any ideas are appreciated.

PS: I use OpenSUSE 13.1 with Qt 4.8.5

Community
  • 1
  • 1
Tiana987642
  • 696
  • 2
  • 10
  • 28

2 Answers2

3

The main idea is to copy default implementation of checkbox drawing and modify it according to your needs. We get label rectangle in default implementation, so we just need to draw new element in this place and shift label to the right. Also we need to adjust size hint so that both new element and default content fit in minimal size.

class CustomCheckBox : public QCheckBox {
  Q_OBJECT
public:
  CustomCheckBox(QWidget* parent = 0) : QCheckBox(parent) {
    m_decoratorSize = QSize(16, 16);
    m_decoratorMargin = 2;
  }

  QSize minimumSizeHint() const {
    QSize result = QCheckBox::minimumSizeHint();
    result.setWidth(result.width() + m_decoratorSize.width() + m_decoratorMargin * 2);
    return result;
  }

protected:
  void paintEvent(QPaintEvent*) {
    QPainter p(this);
    QStyleOptionButton opt;
    initStyleOption(&opt);
    QStyleOptionButton subopt = opt;
    subopt.rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &opt, this);
    style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &subopt, &p, this);
    subopt.rect = style()->subElementRect(QStyle::SE_CheckBoxContents, &opt, this);
    p.fillRect(QRect(subopt.rect.topLeft() + QPoint(m_decoratorMargin, 0),
                     m_decoratorSize), QBrush(Qt::green));
    subopt.rect.translate(m_decoratorSize.width() + m_decoratorMargin * 2, 0);
    style()->drawControl(QStyle::CE_CheckBoxLabel, &subopt, &p, this);
    if (opt.state & QStyle::State_HasFocus) {
      QStyleOptionFocusRect fropt;
      fropt.rect = style()->subElementRect(QStyle::SE_CheckBoxFocusRect, &opt, this);
      fropt.rect.setRight(fropt.rect.right() + 
                          m_decoratorSize.width() + m_decoratorMargin * 2);
      style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, &p, this);
    }
  }

private:
  QSize m_decoratorSize;
  int m_decoratorMargin;
};

Note that this solution may be not portable because checkboxes are drawn with drastic differences on different platforms. I tested it on Windows only. I used default implementation provided by QCommonStyle.

Pavel Strakhov
  • 39,123
  • 5
  • 88
  • 127
  • Hi, your solution is partially worked: It does create the rectangle between the checkbox and the text; but the text is halved. My guess is we need to recalculate the boundingrect of the text? How to? – Tiana987642 May 31 '15 at 06:17
  • Okay , silly me. I just need to resize it on the GUI. – Tiana987642 May 31 '15 at 07:33
1

QAbstractButton has a property called icon, which is drawn differently depending on what subclass is instantiated.

Luckily for you, the position of the icon in a QCheckBox is exactly in the position you illustrated in your picture.

So, all you need to do for your customised QCheckBox is define what the icon should be and the default paintEvent will take care of the rest.

For simplicity's sake, I'm assuming the icon size should be the same size as the check box itself:

class CheckBox : public QCheckBox {
public:
    CheckBox() {
        QStyleOptionButton option;
        initStyleOption(&option);
        QSize indicatorSize = style()->proxy()->subElementRect(QStyle::SE_CheckBoxIndicator, &option, this).size();

        QPixmap pixmap(indicatorSize);
        pixmap.fill(Qt::green);

        QIcon icon;
        icon.addPixmap(pixmap);

        setIcon(icon);

    }
};

I have tested this on a Windows 8.1 machine with Qt 5.2.1 and it works.

RobbieE
  • 4,280
  • 3
  • 22
  • 36
  • Hi, your solution is partially worked: It does create the rectangle between the checkbox and the text; but the text is halved. My guess is we need to recalculate the `boundingrect` of the text? – Tiana987642 May 31 '15 at 05:07