我正试图用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)
并在3
位置绘制宽度为3./w
(而不是(100,100)
)的点,那么我在高度和宽度点得到一个小的大多数对称的3像素。
这是怎么回事?为什么我得到一个线段而不是预期的点?以及如何解决它,而不是诉诸绘制椭圆或避免QPainter::scale
?
我在Linux x86上使用Qt 5.10.0和g ++ 5.5.0。 Qt 5.5.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.;
行。这是路径的第二个顶点 - 相对于点的所需位置移位。
这解释了为什么线延伸到所要求位置的右侧以及为什么它取决于比例。因此,似乎OP中的代码对于理想的QPainter
实现并没有错,但只是遇到了Qt错误(无论是在方法的实现中还是在其文档中)。
所以结论是:人们必须通过使用不同的比例,或绘制椭圆,或绘制线段的长度比QPainter::drawPoints
的长度小得多来解决这个问题。
我已将此报告为QTBUG-70409。
虽然我无法确定为什么会出现问题,但我已经相对接近解决方案了。问题在于缩放。我用以下代码做了大量的试验和错误,不同的缩放和点宽度。
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)由于高比例缩放,该点(仅3像素宽)无法在较低宽度(点宽度)上按比例缩放,如果将宽度设置为30,则圆形可见。 2)如果你想保持低点的宽度,你必须减少缩放。 可悲的是,我无法解释为什么在高规模时它不会按比例扩大。