为什么QPainter :: drawPoint绘制水平线段?

时间:2018-09-05 22:27:15

标签: c++ qt qpainter

我正在尝试使用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");
}

这是结果图像的左上角:

line instead of a point

我希望得到一个红色圆圈或至少一个正方形的点,但是我得到了该线段。如果我注释掉p.scale(w,h)并在位置3上画一个宽度为3./w(而不是(100,100)的点),那么我得到的是高度对称且很小的3像素小像素,宽度点。

这是怎么回事?为什么我得到线段而不是预期的点?以及如何解决此问题而不求助于绘制椭圆或避免使用QPainter::scale

我正在Linux x86和g ++ 5.5.0上使用Qt 5.10.0。 Qt 5.5.1也会发生同样的情况。

2 个答案:

答案 0 :(得分:2)

看来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

答案 1 :(得分:0)

尽管我无法确切指出问题出在何处,但我已经接近解决方案了。问题在于缩放。我使用下面的代码对不同的缩放比例和宽度进行了大量的试验和错误。

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");

上面的代码产生图像
enter image description here

我的观察结果是
1)由于缩放比例高,如果将宽度设置为30左右,则可以看到圆形(仅3像素宽)在较低的宽度(点的宽度)上按比例缩放。
2)如果要保持点的宽度较小,则必须减小缩放比例。
 可悲的是,我无法解释为什么在高比例缩放时它没有按比例扩展。