01 Qt自定义风格控件的基本原则-CSDN博客
02 从QLabel聊起:自定义控件扩展-图片控件-CSDN博客
03 从QLabel聊起:自定义控件扩展-文本控件-CSDN博客
目录
系列文章目录
前言
一、从QToolButton的渲染源码讲起
1. QToolButton渲染源码
2. 文本+图标居中显示繁琐的原因
二、自定义Button控件的使用场景
1.单一文本按钮风格:
2.单一图标风格:
3.图标+文本风格:
三、实现思路
1.概述
2.功能接口举例
3.按钮渲染部分代码示例
总结
相信按钮控件对于任何一个QtUI开发者都不陌生,真的是极其普遍与通用的一个基础控件!而且,在Qt-Widget框架中, QToolButton类不仅具备基本的按钮点击功能, 而且还预置了几种风格:
乍一看,似乎已经满足开发者的各种业务需要。
然而,有一天我突然发现,当我想实现居中显示文本+图标这一极其简单的业务场景(ToolButtonTextBesideIcon )时,竟然复杂的让人恼火!
这也是我决定封装一个自定义的按钮组件功能类的一个起因!
至于为什么实现文本+图标居中显示效果极其繁琐,下面的篇幅我会简单陈述!
既聊思路,也说代码!我们开始今天的Button扩展控件类的分享!
以下为Qt源码中关于QToolButton按钮渲染的部分代码:
//Qt::ToolButtonTextBesideIcon
pr.setWidth(pmSize.width() + 4);
tr.adjust(pr.width(), 0, 0, 0);
pr.translate(shiftX, shiftY);
if (!hasArrow)
{
proxy()->drawItemPixmap(p, QStyle::visualRect(opt->direction, rect, pr),Qt::AlignCenter, pm);
} else {
drawArrow(proxy(), toolbutton, pr, p, widget);
}
alignment |= Qt::AlignLeft | Qt::AlignVCenter;
tr.translate(shiftX, shiftY);
const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
proxy()->drawItemText(p, QStyle::visualRect(opt->direction, rect, tr), alignment, toolbutton->palette,toolbutton->state & State_Enabled, text,QPalette::ButtonText);
详情见qcommonstyle.cpp中函数:QCommonStyle::drawControl
在以上源码中, pr为pixmap的绘制Rect, tr为text的绘制Rect。drawItemPixmap为绘制按钮图标,drawItemText为绘制按钮文本。
从第1、2行就可以知道,Qt源码中图标显示区域与文本显示区域的间隙是固定的4像素,
所以,如果想图标、文本居中显示,需要在qss样式表中, 结合按钮宽高值,图标的宽高值、各种设置margin、padding参数,才能达到居中效果!
着实让我有些头痛!
为了沿用按钮的基本功能接口, 我们需要继承QAbstractButton类, 然后在paintEvent中实时绘制图标与文本内容, 必要的话还要区分三态效果(包括:默认态、Hover态、Press态)
public:
//按钮风格
enum ButtonStyle
{
IconOnly = 0,
TextOnly,
TextBesideIcon,
TextUnderIcon
};
explicit QUiButton(QWidget *parent = nullptr);
//设置按钮风格
void setButtonStyle(ButtonStyle style);
//设置按钮图标
void setIcons(const QString& normal);
//设置文本颜色
void setTextColor(const QColor& clr);
//图标、文本间距
void setSpacing(int spacing);
//设置按钮圆角
void setBorderRadius(int radius);
//设置按钮背景色
void setBackground(const QColor& clr);
void QUiButton::paintEvent(QPaintEvent *pEvt)
{
QStylePainter paint(this);
paint.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
drawBackground(&paint);
if(m_eButtonStyle == IconOnly)
{
drawIconOnly(&paint);
}
else if(m_eButtonStyle == TextOnly)
{
drawTextOnly(&paint);
}
else if(m_eButtonStyle == TextBesideIcon)
{
drawTextBesideIcon(&paint);
}
else if(m_eButtonStyle == TextUnderIcon)
{
drawTextUnderIcon(&paint);
}
}
绘制图标+文本居中效果部分参考代码:
void QUiButton::drawTextBesideIcon(QStylePainter *paint)
{
QRect rcContents = contentsRect();
QFontMetrics metric(font());
int iTextW = metric.horizontalAdvance(text());
int iTextH = metric.leading() + metric.ascent() + metric.descent();
int iTotalWidth = iconSize().width() + m_iSpacing + iTextW;
int iTotalHeight = qMax(iconSize().height(), iTextH);
QRect rcDisplay( (rcContents.width() - iTotalWidth)/2
, (rcContents.height() - iTotalHeight)/2
, iTotalWidth, iTotalHeight);
QRect rcPix = rcDisplay;
QRect rcText = rcDisplay;
rcPix.setWidth(iconSize().width());//左上角不变,缩小宽度
rcText.adjust(rcPix.width() + m_iSpacing, 0, 0, 0);//
//绘制图标
QPixmap pix = m_iconNormal.pixmap(qt_getWindow(this), rcDisplay.size().boundedTo(iconSize()));
paint->drawItemPixmap(rcPix, Qt::AlignCenter, pix);
//绘制文本
paint->setFont(font());
paint->setPen(m_textClrNormal);
paint->drawText(rcText, Qt::AlignCenter, text());
}
以上就是今天要分享的内容,本篇主要针对QToolButton功能接口进行功能仿写与扩展,然后独立出一个自定义的组件功能类Button。
既聊思路,也说代码!我们下次继续分享自定义风格扩展组件!
PS:本专栏所有篇幅涉及的UI扩展组件类,后面会封装成插件动态库,感兴趣的同学可以留言哦!