【问题标题】:Text from QPainter much nicer than from QPainterPath来自 QPainter 的文本比来自 QPainterPath 的文本好得多
【发布时间】:2013-07-24 11:32:22
【问题描述】:

我想使用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();
}

产生以下结果:

前者显然更干净、更美观,尤其是在较小的字体中。我应该怎么做才能从QPainterPath 获得相同的结果?

我正在使用 Qt 5.0 的 Windows 7 计算机上生成上述结果。

【问题讨论】:

    标签: c++ qt qt5 qpainter


    【解决方案1】:

    根据 Qt 文档向 QPainterPath 添加文本:-

    将给定的文本添加到此路径作为创建的一组封闭子路径 来自提供的字体。

    所以这里发生了转换,这就是它看起来不一样的原因。如果您需要旋转文本,您可以尝试在渲染之前旋转 QPainter,然后再将其恢复。或者,如果您可以使用 QGraphicsView 和 QGraphicsDisplay 而不是仅仅渲染到小部件上,那么 QGraphicsTextItem 类可能会有所帮助。

    但总的来说,导致文本质量不同输出的是向封闭子路径集的转换。

    【讨论】:

    • 对,至少我明白你的意思是转换正在进行,尽管我不明白这在实践中意味着什么(封闭的子路径?)以及是否可以避免。不幸的是,旋转 QPainter 首先会使事情变得更糟,因为旋转文本不支持抗锯齿。
    • 我知道它是 Java,但这个问题的答案简要解释了子路径:stackoverflow.com/questions/4662295/…
    • 至于询问是否可以避免,如果您使用的是QPainterPath,我认为您不会得到完全相同的结果。您也许可以设置一些可以改进它的画家渲染提示,例如 QPainter::TextAntialiasing。请注意,它们是标志,因此可以组合使用。
    • 另一种可能的方法是将具有非常大字体的文本添加到 QPainterPath 中,将其渲染到 QImage 上并在复制到屏幕时缩小图像大小。这可能看起来更好,但您必须尝试一下。
    • 我在QPainter 的别名和旋转文本上搜索了几个论坛主题,似乎没有任何渲染标志有帮助。但是感谢其他关于 hack 的想法,我将尝试一下。
    【解决方案2】:

    这两种字体看起来不一样,因为您正在为 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”好

    【讨论】:

      【解决方案3】:

      我希望与上述答案有所不同,并建议 addText/drawPath 和 drawText 方法做同样的事情,并且可能没有实质性的“转换”。

      正如 Mehdi-Antoine 所指出的 - 使用 drawText 会产生中等大小的文本重量,而使用带有 Pen 和 Brush 的 addText/drawPath 会产生较重的重量,而仅使用带有填充的 addText/drawPath 会产生较轻的重量。

      请注意,QPen 值有一个宽度,默认为 1,如果您使用此笔以宽度为 1 来描边文本的轮廓,则文本会显得非常沉重,如 Medhi-Antoine 的示例所示。

      但是 - 您可以通过使用 addText/drawPath 方法获得与 drawText 有效相同的结果,只需调整所用 Pen 的权重即可。对于 30 磅的字体大小,Arial 将 Pen 宽度设置为 0.2,然后使用 addText/drawPath 方法进行绘画似乎创建了与 drawText 方法相同的东西。

      似乎 drawText 方法获取了 Pen 的颜色,然后使用它进行填充,然后以特定粗细应用笔触。

      如果您要使用 drawPath 方法,您必须为机器人提供 Fill 和 Pen,并且重要的是,适当调整 Pen 的宽度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-11
        相关资源
        最近更新 更多