从QPainter绘制的文本比从QPainterPath绘制的文本更美观。

7
我想使用QPainter来绘制文本,并且我想先使用QPainterPath(因为最终我想以各种方式旋转文本)。但是,我发现QPainterPath生成的文本比QPainter生成的文本要难看得多。
以下是代码:
void MyWidget::paintEvent(QPaintEvent* /*event*/) {

     QFont font;
     font.setStyleHint(QFont::Times, QFont::PreferAntialias);
     font.setPointSize(30);

     QPainter painter;
     painter.begin(this);
     painter.setRenderHint(QPainter::Antialiasing);
     painter.setBrush(Qt::black);
     painter.setFont(font);
     painter.drawText(10, 40, "Hello World");

     QPainterPath textPath;
     textPath.addText(10, 100, font, "Hello world");
     painter.drawPath(textPath);

     painter.end();
}

生成以下结果:

enter image description here

前者显然更干净、更美观,尤其是在小字体中。我应该如何使用QPainterPath来获得相同的结果?

我在Windows 7电脑上使用Qt 5.0生成以上结果。

3个回答

5
根据Qt关于向QPainterPath添加文本的文档:-

使用提供的字体,将给定的文本作为一组闭合子路径添加到此路径中。

因此,这里发生了转换,这就是为什么它看起来不同。如果需要旋转文本,可以在渲染前旋转QPainter,然后在渲染后恢复它。或者,如果可以使用QGraphicsView和QGraphicsTextItem而不仅仅是渲染到小部件上,则有可能使用类QGraphicsTextItem。

但总的来说,将文本转换为闭合子路径集合是导致文本质量不同的原因。


好的,至少我明白你的意思了,即存在一种转换(closed subpaths?),尽管我不理解这在实践中意味着什么,以及是否可以避免。不幸的是,首先旋转QPainter会使情况变得更糟,因为旋转文本不支持抗锯齿。 - Yellow
我知道这是Java,但是这个问题的答案简要地解释了子路径:http://stackoverflow.com/questions/4662295/what-is-path-subpath-in-java2d - TheDarkKnight
关于是否可以避免这个问题,如果您正在使用QPainterPath,我认为您不会得到完全相同的结果。您可以设置一些绘图器渲染提示来改善它,例如QPainter :: TextAntialiasing。请注意,它们是标志,因此可以组合使用。 - TheDarkKnight
1
另一种可能的方法是使用非常大的字体将文本添加到QPainterPath中,将其渲染到QImage上,并在复制到屏幕时缩小图像大小。这可能会看起来更好,但您需要尝试一下。 - TheDarkKnight
没问题。祝你好运,让我们知道你的进展情况。 - TheDarkKnight
显示剩余3条评论

5

两种字体看起来不同,是因为你在QPainterPath文本中添加了额外的轮廓。

以下代码片段应该能够获得良好的结果:

QFont font;
font.setStyleHint(QFont::Times, QFont::PreferAntialias);
font.setPointSize(30);

QPainter painter;
painter.begin(this);
painter.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
painter.setFont(font);

// painter text color is modified by setPen()
painter.setPen(Qt::white);
painter.drawText(10, 40, "Hello World 1");

QPainterPath textPath;
textPath.addText(10, 100, font, "Hello World 2");

// painter path text color is modified by setBrush()
painter.setBrush(Qt::white);
// setPen(Qt::white) add extra white contour on text path (what you did)
painter.setPen(Qt::white);
painter.drawPath(textPath);

QPainterPath textPath2;
textPath2.addText(10, 160, font, "Hello World 3");

// painter path text color is modified by setBrush
painter.setBrush(Qt::white);
// setPen(Qt::NoPen) avoid extra contours for QPainter Path
painter.setPen(Qt::NoPen);
painter.drawPath(textPath2);

painter.end();

我承认QPainterPath文本“Hello World 3”比QPainterText文本“Hello World 1”丑了一点,但结果仍然比“Hello World 2”好。

enter image description here


0

我不太同意以上的答案,建议使用addText/drawPath和drawText方法可以实现相同的效果,并且可能没有实质性的“转换”。

正如Mehdi-Antoine所指出的那样,使用drawText方法会得到中等大小的文本权重,而使用带有Pen和Brush的addText/drawPath方法会得到较重的权重,而仅使用填充的addText/drawPath方法则会得到较轻的权重。

请注意,QPen值具有宽度,默认为1,如果您将此笔应用于描绘宽度为1的文本轮廓,则文本将显示非常重,就像Medhi-Antoine的示例一样。

然而,您可以通过调整所使用的Pen的权重,仅使用addText/drawPath方法即可实现与drawText方法完全相同的结果。对于30点Arial字体大小,设置0.2的Pen宽度,然后使用addText/drawPath方法进行绘制似乎可以创建与drawText方法完全相同的内容。

似乎drawText方法获取Pen的颜色,然后使用该颜色进行填充,然后以特定厚度应用描边。

如果您要使用drawPath方法,您必须同时提供填充和笔,并且重要的是适当调整笔的宽度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接