【问题标题】:Why does QPainter::drawPoint draw a horizontal line segment?QPainter::drawPoint 为什么要画水平线段?
【发布时间】:2018-09-05 22:27:15
【问题描述】:

我正在尝试使用QPainter 绘制一个 3 像素的大点。但下面的代码改为绘制一条宽度为 3 像素的水平线。

#include <QPainter>
#include <QImage>

int main()
{
    const int w=1000, h=1000;
    QImage img(w, h, QImage::Format_RGBX8888);
    {
        QPainter p(&img);
        p.fillRect(0,0,w,h,Qt::black);
        p.scale(w,h);
        p.setPen(QPen(Qt::red, 3./w, Qt::SolidLine, Qt::RoundCap));
        p.drawPoint(QPointF(0.1,0.1));
    }
    img.save("test.png");
}

这是生成图像的左上角:

我希望得到一个红色圆圈或至少一个正方形的点,但我得到的是这条线段。如果我注释掉p.scale(w,h) 并在位置(100,100) 处绘制宽度为3(而不是3./w)的点,那么我会得到一个高度和宽度几乎对称的3 像素点。

发生了什么事?为什么我得到的是线段而不是预期的点?以及如何解决它,而不是求助于绘制椭圆或避免QPainter::scale

我在带有 g++ 5.5.0 的 Linux x86 上使用 Qt 5.10.0。 Qt 5.5.1 也是如此。

【问题讨论】:

  • 你想要一个三像素的大点还是一个破折号?如果你想要破折号,那么你应该使用 Qt::DotLine 而不是 SolidLine。编辑您的问题以明确您的目标
  • @Gurushant 我虽然第一句话已经说过我想要一个观点。 point 不是 dot 的同义词吗?
  • 是的,当然,但后来你说“那我得到正常点,而不是“破折号””。我不明白你在这里的意思。
  • @Gurushant 好的,我已经试着澄清了,请看看是否更好。

标签: c++ qt qpainter


【解决方案1】:

似乎QPaintEngineEx::drawPoints 将点渲染为长度为1/63. 的线段。请参阅 Qt 源代码中 qtbase/src/gui/painting/qpaintengineex.cpp 的以下代码:

void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount)
{
    QPen pen = state()->pen;
    if (pen.capStyle() == Qt::FlatCap)
        pen.setCapStyle(Qt::SquareCap);

    if (pen.brush().isOpaque()) {
        while (pointCount > 0) {
            int count = qMin(pointCount, 16);
            qreal pts[64];
            int oset = -1;
            for (int i=0; i<count; ++i) {
                pts[++oset] = points[i].x();
                pts[++oset] = points[i].y();
                pts[++oset] = points[i].x() + 1/63.;
                pts[++oset] = points[i].y();
            }
            QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
            stroke(path, pen);
            pointCount -= 16;
            points += 16;
        }
    } else {
        for (int i=0; i<pointCount; ++i) {
            qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + qreal(1/63.), points[i].y() };
            QVectorPath path(pts, 2, 0);
            stroke(path, pen);
        }
    }
}

注意不透明画笔分支中的pts[++oset] = points[i].x() + 1/63.; 行。这是路径的第二个顶点——相对于点的所需位置移动。

这解释了为什么线延伸到请求位置的右侧以及为什么它取决于比例。因此,对于理想的QPainter 实现而言,OP 中的代码似乎没有错,但只是遇到了一个 Qt 错误(无论是在方法的实现中还是在其文档中)。

因此结论是:必须通过使用不同的比例,或绘制椭圆,或绘制长度比QPainter::drawPoints 小得多的线段来解决此问题。

我已将此报告为QTBUG-70409

【讨论】:

  • 这解释了原因!谢谢,因此我无法专注于其他工作
【解决方案2】:

虽然我无法确定问题发生的确切原因,但我已经相对接近解决方案了。问题在于缩放。我用下面的代码对不同的缩放比例和点宽度做了很多试验和错误。

const int w=500, h=500;
const int scale = 100;
float xPos = 250;
float yPos = 250;
float widthF = 5;
QImage img(w, h, QImage::Format_RGBX8888);
{
    QPainter p(&img);
    p.setRenderHints(QPainter::Antialiasing);
    p.fillRect(0,0,w,h,Qt::black);
    p.scale(scale, scale);
    p.setPen(QPen(Qt::red, widthF/(scale), Qt::SolidLine, Qt::RoundCap));
    p.drawPoint(QPointF(xPos/scale, yPos/scale));
}
img.save("test.png");

以上代码生成图像

我的观察是
1) 由于高缩放,如果您将宽度设置为 30 之类的东西,圆形可见。
2) 如果要保持点的宽度较低,则必须减小缩放比例。
遗憾的是,我无法解释为什么在高缩放时它没有按比例扩展。

【讨论】:

  • 我找到了罪魁祸首,看我的回答。
猜你喜欢
  • 1970-01-01
  • 2014-08-31
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
  • 2022-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多