Qt QPainter以毫米为单位而非英寸

7
我有一个可以直接打印到物理打印机或PDF的QPrinter。现在我想使用QPainter以毫米为单位进行绘制,但当前坐标系似乎是打印机分辨率下A4纸张宽度和高度的英寸值。

8.26英寸 x 1200分辨率 = 9912
11.69英寸 x 1200分辨率 = 14028

我尝试了以下方法,但文本只变得非常巨大。

auto page = printer.pageRect(QPrinter::Unit::Millimeter);
painter.setWindow(QRect(0, 0, page.width(), page.height()));

我该如何更改这个设置,使我的QPainter可以绘制到210 x 297毫米而不是上面的系统?

这是在Windows 10上使用Qt 5.10。

3个回答

4

我在 X11(Ubuntu Linux)PDF 打印机上测试了这种方法,使用 ScreenResolution 打印机模式:

painter.begin(printer);

int log_w  = 210;
int log_h  = 297;
painter.setWindow(0, 0, log_w, log_h);

int phys_w  = printer->width();
int phys_h = printer->height();
painter.setViewport(0, 0, phys_w, phys_h);

基本上,在Painter窗口中设置您的逻辑大小(以毫米为单位),并将Painter的视口设置为打印机的物理大小。 以下代码可在页面周围打印一个具有10毫米边框的矩形:

painter.drawRect(10, 10, log_w - 20, log_h -20);

文本应相应地工作。此代码应在矩形的左上角打印单词Ok

  QFont font = painter.font();
  font.setPointSize(10); //1 cm height
  painter.setFont(font);
  painter.drawText(10, 20, "Ok");

  painter.end();

使用高分辨率打印模式时,必须使用字体大小进行设置。

font.setPixelSize(10); //1 cm height

而且绘图对象必须设置QPen

QPen pen(Qt::black);
pen.setWidthF(0.2);
painter.setPen(pen);
painter.drawRect(10, 10, log_w - 20, log_h - 20);

关于使用`setPixelSize`导致设备依赖性的问题,我知道文档这里指出: > 通过使用`setPixelSize()`函数,可以将屏幕上显示的字符高度设置为指定数量的像素。但是,使用`setPointSize()`也可以产生类似的效果,并且提供了设备独立性。
但是我认为它仅适用于屏幕,因为文档这里指出: > 当在QPrinter设备上呈现文本时,重要的是要意识到以点为单位指定的文本大小与设备本身指定的分辨率无关。因此,当将文本与图形结合使用时,指定字体大小为像素可能很有用,以确保其相对大小符合您的预期。

嗨,这个方法对矩形部分有效,但对文本完全无效。这是导致问题的最小代码示例:https://pastebin.com/tT0ZLa87。当输出到NativeFormat(Windows 10)时,矩形是正确的,但文本被大幅膨胀。当输出到pdf时,两者都是错误的。PDFFormat输出:http://g2f.nl/0o2if42,NativeFormat输出:http://g2f.nl/0che686。 - Eejin
在高分辨率(本机打印机)打印时,请尝试使用 setPixelSize 设置字体大小。至于 PDF,我真的不知道,我正在使用 ScreenResolution 作为打印机模式。 - p-a-o-l-o
但这将是一种依赖于设备(dpi)的方法。似乎字体没有被正确转换。我觉得这很奇怪,因为这似乎是打印时想要做的基本事情。 - Eejin
我编辑了答案,解决了PDF问题并解决了设备依赖性问题。 - p-a-o-l-o
现在我可以在两个上绘制相同大小的文本,但它现在非常大。我该如何将Adobe Illustrator中设置的点大小转换为在绘图代码中与A4相同大小的点大小?在原始窗口和视口大小下,它是1:1映射。此外,当调用renderer.render()时,我的QSvgRenderer renderer("path");不会显示任何输出。 - Eejin
这些问题基本上都是新的,你觉得呢?我会单独发布它们,并提供相关的代码。 - p-a-o-l-o

2

您的方法是正确的。这里有一个设置打印机/绘图器对的示例。我不会玩弄变换矩阵,因为只需要指定一个窗口/视口对就足够了。我甚至没有明确指定视口,因为它会自动设置为绘画设备的度量(在本例中为QPrinter对象)。

#include <QPrinter>
#include <QPainter>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    QPrinter printer(QPrinter::PrinterResolution);
    printer.setOrientation(QPrinter::Portrait);
    printer.setPageSize(QPageSize(QPageSize::A4));
    printer.setResolution(300 /*dpi*/);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName("ellipse.pdf");

    QPainter painter(&printer);

    auto page = printer.pageRect(QPrinter::Unit::Millimeter);
    painter.setWindow(page.toRect());

    // Draw a 5mm thick ellipse across the whole page.
    painter.setPen(QPen(Qt::black, 5.0));
    painter.drawEllipse(0, 0, 210, 297);

    return 0;
}

生成的PDF截图 没有看到您的其他代码,很难确定问题出在哪里。


你好,使用你发布的示例代码时,椭圆确实被拉伸到整个页面,但是当绘制一些文本时,它会变得过大。这是代码:https://pastebin.com/CFDWghKi 这是输出的PDF文件:http://g2f.nl/0e905rh - Eejin
尝试使用setPixelSize()而不是setPointSize(),你应该没问题了。 - bgp2000
但这将是一种依赖于设备(dpi)的方式来做。字体似乎没有正确转换。我觉得很奇怪,因为这看起来像是打印时你想要做的基本事情。 - Eejin
这是相当令人困惑的东西,因为有许多新的不同实现HiDPI等方式,但setPixelSize对我来说很有效,与文档的DPI无关。点大小始终会非常依赖于平台。 - bgp2000

2
我认为您正在寻找QTransform类,根据官方文档:

QTransform类指定坐标系的2D变换。变换指定如何平移、缩放、倾斜、旋转或投影坐标系,并且通常在渲染图形时使用。

您可以初始化自定义的变换类:
QTransform transform = QTransform::fromScale(painter.device()->physicalDpiX() / scale, painter.device()->physicalDpiY() / scale);

我认为这可能有帮助,每毫米的点数:
const int dot_per_millimeter = qRound(qApp->primaryScreen()->physicalDotsPerInch() / 25.40);

定制您的比例尺,然后使用QPainter应用它:
QPainter painter(parent);
painter.setWorldTransform(transform, false);

使用QTransform :: fromScale(1.f / painter.device() - > physicalDpiX(),1.f / painter.device() - > physicalDpiY()); 只会使一切变得非常小。我以后可以将其缩放回来,但由于以如此低的分辨率绘制,它将变得像素化。 - Eejin

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