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);// 新建一个目标大小的画布QpixmapQPixmap 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图片,我感觉会影响效率。