我正在尝试使用QLabel
作为功能强大的工具,以CSS将某些文本呈现为纹理。获取图像后,在OpenGL中形成纹理,并丢弃原始的Qt对象。之后,我将该纹理与普通OpenGL(无Qt)渲染管道中的任何其他纹理一起使用。
但是,我在处理背景透明性时遇到问题。某些东西-可能是我不知道的某些Qt设置-似乎弄乱了我的设置。
经过一些简化,我的纹理如下所示:
QLabel label;
label.setAttribute(Qt::WA_TranslucentBackground, true);
const QString styleSheet{"color : #00bbbb; background-color : rgba(0,0,0,0);"
"font-family: 'Calibri'; text-decoration: none; margin: 5px;"};
label.setWordWrap(true);
label.setAutoFillBackground(false);
label.setStyleSheet(styleSheet);
QFont font = label.font();
font.setPointSizeF(12.0f);
label.setFont(font);
// set text
label.setText(QString("The quick brown fox jumps over the lazy dog"));
// render
label.adjustSize();
label.updateGeometry();
std::unique_ptr<QImage> imgTexture = std::make_unique<QImage>(label.size(), QImage::Format_RGBA8888);
QPainter painter(imgTexture.get());
label.render(&painter);
uint8_t *bits = imgTexture->bits();
std::cout << int(bits[0]) << " " << int(bits[1]) << " " << int(bits[2]) << " " << int(bits[3]) << std::endl;
输出-产生的图像的左上像素的值-为:
205 205 205 205
而不是我期望的0 0 0 0。因此,问题已经在这一点上出现了,而不是稍后在我的OpenGL处理纹理中出现。最终,我的输出是:
如图所示,背景并非完全透明。
更新资料
根据G.M.的建议,我尝试了
setCompositionMode
(无效果),但也尝试了其他画家设置。显然,将QPainter::setBackgroundMode
设置为Qt::OpaqueMode
会更进一步:Qt手册说:
Qt :: TransparentMode(默认设置)绘制点画的线条和文本,而无需设置背景像素。 Qt :: OpaqueMode用当前背景色填充这些空间。
因此,似乎默认设置是不更改不存在字母的任何地方的输出图像的原始像素。因此,未绘制透明(0,0,0,0),并且先前的颜色(出于某种原因显然是205、205、205、205)保持不变。
强制绘制背景会更新所有像素,但只会更新字母附近的像素。现在,我需要弄清楚如何强制将所有像素清除为CSS中指定的颜色。
更新显然,它并不像看起来那样简单。我尝试了
painter.eraseRect(0, 0, width, height);
,但这将矩形清除为白色,而忽略了CSS设置。 最佳答案
结合实验结果和一些评论。该行为是以下各项的组合:
当QImage
用某个图像区域构造时,该区域未初始化。
QImage::QImage(int width, int height, QImage::Format format)
构造具有给定宽度,高度和格式的图像。
如果无法分配内存,将返回空图像。
警告:这将创建一个带有未初始化数据的QImage。调用fill()用适当的像素值填充图像,然后用QPainter绘制图像。
在Visual Studio的“调试”模式下,未初始化的区域使用0xCD
初始化。在Release中会有些垃圾
默认情况下,使用QPainter绘制文本时,背景保持不变。画家仅将字形添加到目标图像上先前存在的任何内容(在我们的示例中为未初始化的区域)。
void QPainter::setBackgroundMode(Qt::BGMode mode)
将画家的背景模式设置为给定模式
Qt :: TransparentMode(默认设置)绘制点画的线条和文本,而无需设置背景像素。 Qt :: OpaqueMode用当前背景色填充这些空间。
请注意,为了透明地绘制位图或像素图,必须使用QPixmap :: setMask()。
因此,为了绘制QLabel CSS中设置的背景像素,需要将模式更改为Qt::OpaqueMode
。但是,这仅在字形周围绘制,不幸的是没有绘制整个区域。
我们需要先手动清除整个区域。
图像可以通过QPainter::fillRect
清除:
void QPainter::fillRect(int x, int y, int width, int height, const QColor &color)
这是一个过载功能。
使用给定的颜色,以给定的宽度和高度填充从(x,y)开始的矩形。
此功能在Qt 4.5中引入。
但需要注意的是-所有QPainter
操作都与基础图像混合在一起。默认情况下,它考虑绘图颜色的Alpha通道。因此,如果用(0,0,0,0)进行绘制,您将得到...不变。混合操作由以下方式控制:
void QPainter::setCompositionMode(QPainter::CompositionMode mode)
将构图模式设置为给定模式。
警告:只有在QImage上运行的QPainter才能完全支持所有合成模式。 X11支持RasterOp模式,如compositionMode()中所述。
另请参见compositionMode()。
enum QPainter::CompositionMode
定义数字图像合成支持的模式。合成模式用于指定如何将一个图像(源)中的像素与另一图像(目标)中的像素合并。
[...]
设置构图模式后,它将应用于所有绘画操作员,笔,画笔,渐变和像素图/图像绘制。
常数值说明
QPainter :: CompositionMode_SourceOver 0这是默认模式。源的Alpha用于在目标顶部混合像素。
QPainter :: CompositionMode_DestinationOver 1目标的Alpha用于将其混合在源像素的顶部。此模式与CompositionMode_SourceOver相反。
QPainter :: CompositionMode_Clear 2清除目标中的像素(设置为完全透明),而与源无关。
QPainter :: CompositionMode_Source 3输出是源像素。 (这意味着基本的复制操作,并且在源像素不透明时与SourceOver相同)。
QPainter :: CompositionMode_Destination 4输出是目标像素。这意味着混合无效。此模式与CompositionMode_Source相反。
[...](另外30种模式...)
因此,在调用SourceOver
之前,默认的Source
需要替换为fillRect
。
清除也可以通过QImage::fill
完成。更加轻松,并且绘制模式不会混乱!
不幸的是,任何一种解决方案(QImage::fill
或QPainter::fillRect
)都需要明确指定背景色。不能仅从QLable的CSS中读取它。
附言我不知道如何阻塞表:(
关于c++ - 渲染透明的QLabel,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58889139/