效果示例:
MRadioButton.h
//********************************************************
/// @brief 自定义单选按钮
/// @author y974183789@gmail.com
/// @date 2021/9/18
/// @note 支持自定义设置单选指示器位置
/// @version 1.0.0
//********************************************************
#pragma once
#include <QtWidgets/QRadioButton>
class MRadioButton : public QRadioButton {
Q_OBJECT
public:
//指示器位置,默认为左
enum IndicatorPosition{
kIndicatorLeft = 0,
kIndicatorTop,
kIndicatorRight,
kIndicatorBottom,
};
public:
explicit MRadioButton(QWidget *parent = nullptr);
~MRadioButton() override;
//设置指示器位置
void setIndicatorPosition( IndicatorPosition pos);
protected:
void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
bool hitButton(const QPoint &pos) const Q_DECL_OVERRIDE;
private:
IndicatorPosition m_IndicatorPosition;
};
MRadioButton.cpp
//********************************************************
/// @brief 自定义单选按钮
/// @author y974183789@gmail.com
/// @date 2021/9/18
/// @note 支持自定义设置单选指示器位置
/// @version 1.0.0
//********************************************************
#include "MRadioButton.h"
#include <QtWidgets/QStyleOptionButton>
#include <QtCore/qglobal.h>
#include <QtGui/QPainter>
#include <QtWidgets/QApplication>
#include <QtCore/QDebug>
#define INDICATOR_SPACING 4
MRadioButton::MRadioButton(QWidget *parent)
: QRadioButton(parent)
, m_IndicatorPosition(kIndicatorLeft)
{
}
MRadioButton::~MRadioButton()
{
}
void MRadioButton::setIndicatorPosition(IndicatorPosition pos)
{
m_IndicatorPosition = pos;
}
void MRadioButton::paintEvent(QPaintEvent *e)
{
if (kIndicatorLeft == m_IndicatorPosition)
{
return QRadioButton::paintEvent(e);
}
QWidget::paintEvent(e);
QPainter p(this);
QStyleOptionButton opt;
initStyleOption(&opt);
QRect rectIndicator;
QRect rectLabel;
auto alignment = Qt::AlignHCenter | Qt::AlignVCenter;
auto pStyle = this->style();
QRect indicator = opt.rect;
indicator.setWidth(opt.iconSize.width());
indicator.setHeight(opt.iconSize.height());
int spacing = INDICATOR_SPACING;
if(Q_NULLPTR != pStyle)
{
int h = pStyle->pixelMetric(QStyle::PM_IndicatorHeight, &opt, this);
indicator.setRect(opt.rect.x(), opt.rect.y() + ((opt.rect.height() - h) / 2),
pStyle->pixelMetric(QStyle::PM_IndicatorWidth, &opt, this), h);
indicator = pStyle->visualRect(opt.direction, opt.rect, indicator);
spacing = pStyle->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &opt, this);
}
switch (m_IndicatorPosition)
{
case kIndicatorTop:
{
rectIndicator = QRect(QPoint(rect().center().x() - indicator.width() / 2,
2), indicator.size());
rectLabel = QRect(QPoint(rect().left(), rectIndicator.bottom() + INDICATOR_SPACING),
rect().bottomRight());
break;
}
case kIndicatorRight:
{
alignment = Qt::AlignRight | Qt::AlignVCenter;
rectIndicator = QRect(QPoint(rect().right() - indicator.width(), (rect().height() - indicator.height()) / 2), indicator.size());
rectLabel = QRect(rect().topLeft(), QPoint(rectIndicator.left() - spacing,
rect().bottom()));
break;
}
case kIndicatorBottom:
{
rectIndicator = QRect(QPoint(rect().center().x() - indicator.width() / 2, rect().bottom() - indicator.height() - INDICATOR_SPACING), indicator.size());
rectLabel = QRect(rect().topLeft(), QPoint(rect().right(), rectIndicator.top() - INDICATOR_SPACING));
break;
}
default:
break;
}
//绘制指示器
opt.rect = rectIndicator;
style()->drawPrimitive(QStyle::PE_IndicatorRadioButton, &opt, &p, this);
//绘制文本
opt.rect = rectLabel;
style()->drawItemText(&p, opt.rect, alignment | Qt::TextShowMnemonic,
opt.palette, opt.state & QStyle::State_Enabled, opt.text, QPalette::WindowText);
}
QSize MRadioButton::sizeHint() const
{
if (kIndicatorLeft == m_IndicatorPosition
|| kIndicatorRight == m_IndicatorPosition)
{
return QRadioButton::sizeHint();
}
ensurePolished();
QFontMetrics fm = fontMetrics();
QStyleOptionButton opt;
initStyleOption(&opt);
QSize sz = style()->itemTextRect(fm, QRect(), Qt::TextShowMnemonic, false,text()).size();
sz = QSize(qMax(sz.width(), opt.iconSize.width()), sz.height() + opt.iconSize.height() + INDICATOR_SPACING * 2);
return style()->sizeFromContents(QStyle::CT_RadioButton, &opt, sz, this);
}
bool MRadioButton::hitButton(const QPoint &pos) const
{
if (kIndicatorLeft == m_IndicatorPosition){
return QRadioButton::hitButton(pos);
}
return rect().contains(pos);
}