tags:

views:

169

answers:

1

I am creating a custom Qt widget that mimics an A4 printed page and am having problems getting fonts to render at the correct size. My widget uses QPainter::setViewport and QPainter::setWindow to mimic the A4 page, using units of 10ths of a millimetre which enables me to draw easily. However, attempting to create a font at a specific point size doesn't seem to work and using QFont:setPixelSize isn't accurate. Here is some code:

View::View(QWidget *parent) :
    QWidget(parent),
    printer(new QPrinter)
{
    printer->setPaperSize(QPrinter::A4);
    printer->setFullPage(true);
}

void View::paintEvent(QPaintEvent*)
{
    QPainter painter(this);
    painter.setWindow(0, 0, 2100, 2970);
    painter.setViewport(0, 0, printer->width(), printer->height());
    // Draw a rect at x = 1cm, y = 1cm, 6cm wide and 1 inch high
    painter.drawRect(100, 100, 600, 254);

    // Create a 72pt (1 inch) high font
    QFont font("Arial");
    font.setPixelSize(254);
    painter.setFont(font);
    // Draw in the same box
    // The font is too large
    painter.drawText(QRect(100, 100, 600, 254), tr("Wg\u0102"));
    // Ack - the actual font size reported by the metrics is 283 pixels!
    const QFontMetrics fontMetrics = painter.fontMetrics();
    qDebug() << "Font height = " << fontMetrics.height();
}

So I'm asking for a 254 high font (1 inch, 72 pts) and it's too big and sure enough when I query for the font height via QFontMetrics it is 283 high.

Does anyone else know how to use font sizes in points when using custom mapping modes like this? It must be possible. Note that I cannot see how to convert between logical/device points either (i.e. the Win32 DPtoLP/LPtoDP equivalents.)

EDIT: Well, it turns out that my code was working fine after all. I converted it to work with a printer, printed it out and then printed the same text using various word processors and the results are exactly the same. It seems that asking for a font size doesn't take the descent into account and this seems to be the norm.

A: 

QFont may or may not be able to match the exact font that you request. QFontMetrics::height() returns a size of 284 on my system, but QFontInfo::pixelSize() returns a size of 254 which is what was requested. I assume the difference is that height() includes the descent where pixelSize() returns the size in pixels of the matched font, implying that I had a match.

As for drawing, placement, and conversions, you'll need to be careful because the printer device won't be the same as the screen device nor will the resolutions match. To further exacerbate the problem, you can't get the exact printer metrics without calling setup on the print dialog. Device independence gets you close to WYSIWYG, but not always close enough.

In your sample, the paint device is this. Thus, you can get at the logical dpi through the logicalDpiX() and logicalDpiY() functions (as well as their physical equivalents).

Kaleb Pederson
OK, so if I use setPixelSize with the correct ascent then I end up with a font where the height() is correct. The problem is how I find out what the ascent is in advance!
Rob
Typography might limit ascent/descent to being proportional to the font size. If so, you should be to grab the ascent, descent, and pixelSize at two different desired target sizes and then interpolate what size you'll need. I'd expect this to be off by at most two pixels (one each for ascending and descending). It should be easy to test at least.
Kaleb Pederson