QLabel一般用于显示一段文字,这段文字可以被鼠标选中/复制,也可是设置自动换行等,还可以用于显示图片。
但是使用QLabel显示图片时,qss样式设置的圆角radius属性是不生效的。
QLabel显示纯文本时,设置了背景颜色后,border-radius圆角属性是生效的,但是显示QPixmap图片时,圆角属性会失效,另外一个QLabel无法同时显示图片和文本(设置富文本的方式可以但是不灵活图片和文字间距无法调整):
所以我对QLabel需求是:
1.显示图片时,可以给图片设置圆角;
2.图片和文本可以同时显示,且可以设置图片在文字的左边或者右边,间距也可以调整,甚至文本会随尺寸变化,当不能完全显示是变成省略号截断(右边截断,中间截断,左边截断);
以上两点需求都是原生QLbel无法支持的,所以需要继承QLbel重绘。
以下代码是简陋实现的Demo,看懂了你需要自己去完善它,封装成更加通用的控件,例如:提供更多接口去设置上下左右内边距,子控件间距,图片尺寸,图片在文本的上下左右等。。。使劲魔改成适合自己的Label吧
mylabel.h
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QLabel>
class MyLabel : public QLabel
{
public:
MyLabel(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags());
void setPixmap(const QPixmap &pix);
protected:
void paintEvent(QPaintEvent *event) override;
private:
int m_leftPadding;
int m_rightPadding;
int m_topPadding;
int m_bottomPadding;
int m_spacing;
QSize m_iconSize;
QPixmap m_pixmap;
};
#endif // MYLABEL_H
mylabel.cpp
#include "mylabel.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPainterPath>
MyLabel::MyLabel(QWidget *parent, Qt::WindowFlags f) :
QLabel(parent,f)
{
m_leftPadding = 10;
m_rightPadding = 10;
m_topPadding = 10;
m_bottomPadding = 10;
m_spacing = 10;
m_iconSize = QSize(64,64);
// 获取 QLabel 中文本所使用的字体尺寸
QFont labelFont = this->font(); // 获取 QLabel 的字体
QFontMetrics fontMetrics(labelFont); // 使用 QFontMetrics 获取字体尺寸信息
int textHeight = fontMetrics.height(); // 获取文本高度
int h = textHeight + m_topPadding + m_bottomPadding;
this->setMinimumHeight(h);
this->setMinimumWidth(textHeight*2);
}
void MyLabel::setPixmap(const QPixmap &pix)
{
m_pixmap = pix;
}
void MyLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setClipRect(event->rect());
painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing|QPainter::SmoothPixmapTransform,true);
painter.setFont(this->font()); // 设置绘制文本的字体
QPalette palette = this->palette(); // 获取QSS样式中设置的调色板
QColor textColor = palette.color(QPalette::WindowText); // 获取文本颜色
painter.setBrush(Qt::NoBrush);
painter.setPen(textColor);
// 绘制图标/图片
if(!m_pixmap.isNull())
{
int h = m_iconSize.height() + m_topPadding + m_bottomPadding;
this->setMinimumHeight(h);
this->setMinimumWidth(m_iconSize.width() + m_leftPadding + m_rightPadding);
QPixmap pix = m_pixmap.scaled(m_iconSize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
QPainterPath pImgPah;
QRect rImage(m_leftPadding,m_topPadding,m_iconSize.width(),m_iconSize.height());
pImgPah.addRoundedRect(rImage,10,10);// 给路径添加一个圆角矩形区域,rImage就是图像要显示的地方的rect,然后10.0,10.0是指x和y的圆角半径。
painter.setClipPath(pImgPah);// 裁剪路径(把矩形裁剪成圆角矩形)
painter.drawPixmap(rImage,pix);// 把图像画在被裁剪后的目标区域
painter.setClipping(false);// 结束裁剪
// 绘制文本
QRect textRect = event->rect();
textRect = textRect.adjusted(m_leftPadding,m_topPadding,-m_rightPadding,-m_bottomPadding);
textRect = textRect.adjusted(m_iconSize.width()+m_spacing,0,0,0);// 图标与文本的间距
// 判断空间是否足够容纳文本,不够则省略号右截断模式
QFontMetrics fontMetrics(this->font());
QString elidedText = fontMetrics.elidedText(this->text(), Qt::ElideRight, textRect.width());
painter.drawText(textRect,Qt::AlignVCenter|Qt::AlignLeft,elidedText);
}
else
{
// 绘制纯文本
QRect textRect = event->rect();
textRect = textRect.adjusted(m_leftPadding,m_topPadding,-m_rightPadding,-m_bottomPadding);
painter.setBrush(Qt::NoBrush);
// 判断空间是否足够容纳文本,不够则省略号右截断模式
QFontMetrics fontMetrics(this->font());
QString elidedText = fontMetrics.elidedText(this->text(), Qt::ElideRight, textRect.width());
painter.drawText(textRect,Qt::AlignVCenter|Qt::AlignLeft,elidedText);
}
}
注意:重写paintEvent后会导致原生QLabel支持的鼠标选中文本复制的功能异常,所以此种方式重绘不支持文本选中复制,需要自己想办法重写文本选中复制功能。由于文本选中复制功能过于复杂,一般需要文本复制功能的话我就直接使用QLabel了。
使用效果:
先给MyLabel设置QLabel的QSS(由于MyLabel是继承自QLabel所以可以使用它的部分qss属性例如:字体,字体颜色等,但是其他属性(background,border等)是无效的)
QLabel
{
color: rgb(88, 148, 67);
font-size:16px;
}
一个MyLabel同时显示圆角图片和文本,文本支持随尺寸变化而右边省略号截断;
再补充一种非绘制手段将QPixmap的直角图片处理成圆角的QPixmap图片,直接塞给QLabel显示,此种方法不需要继承QLabel重绘,更简单:
QPixmap getRoundedPixmap(const QPixmap &srcPixmap, const int &radius, const int &width, const int &height)
{
// 目标图片尺寸
QSize desSize(width, height);
// 新建一个目标大小的画布Qpixmap
QPixmap desPixMap(desSize);
// 填充透明色作为背景
desPixMap.fill(Qt::transparent);
//以QPixmap 为绘画背景进行画笔绘制
QPainter painter(&desPixMap);
painter.setRenderHints(QPainter::Antialiasing); //抗锯齿
painter.setRenderHints(QPainter::SmoothPixmapTransform); //平滑像素图变换
QPainterPath path;//绘制路径
//绘制圆角矩形,其中最后两个参数值的范围为(0-99),就是圆角的px值
path.addRoundedRect(0, 0, desSize.width(), desSize.height(), radius, radius);
// 将绘制的圆角矩形路径中内容进行裁剪
painter.setClipPath(path);
//将图片绘制到desPixmap中,IgnoreAspectRatio忽视图片比例
painter.drawPixmap(0, 0, desSize.width(), desSize.height(), srcPixmap.scaled(desSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
painter.setClipping(false); // 关闭裁剪
return desPixMap;
}
注意:此种方法不建议用于上面的PaintEvent绘制事件中绘制,因为它比上面的方法多一次拷贝QPixmap图片,我感觉会影响效率。