Question

Is there a way to draw text with fractional point sizes in Qt 5. I'm trying to use QFont::setPointSizeF() but it doesn't seem to work on any platform I tried on (mac/linux/windows) and point size is always rounded.

QFontDatabase::isScalable and QFontDatabase::isSmoothlyScalable returns true for the font in all cases.

I tried setting various QFont::fontHintingPreference and QPainter::RenderHint.

I might be able to work around this using QFont::setPixelSize and QPainter::scale, but seem odd that QFont::setPointSizeF is broken?!

Am I missing something or doing something wrong?

Simple program that shows the problem:

#include <QtWidgets>

class MyWidget : public QWidget
{
public:
    MyWidget() : QWidget(0)
    {
    }

protected:
    void paintEvent(QPaintEvent */*e*/)
    {
        QPainter p(this);
        int y=10;

        for (qreal i = 10; i < 20; i += 0.2) {
            QFont font("Times"); // or any font font in the system
            font.setPointSizeF(i);
            p.setFont(font);
            p.drawText(1, y, QString("This should be point size %1 but is %2!").arg(font.pointSizeF()).arg(QFontInfo(font).pointSizeF()));
            y += i;
        }
    }
};

int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    MyWidget widget;
    widget.resize(400, 740);
    widget.show();
    return app.exec();
}
Was it helpful?

Solution 2

It seems that Qt calculates pixel size based on point size and that ends up at QFont::setPixelSize which takes int as parameter so it gets rounded (or something like that).

So to get better precision I can do something like:

void paintEvent(QPaintEvent * /*e*/)
{
    QPainter p(this);
    int y=10;

    for (qreal i = 10; i < 20; i += 0.2) {
        QFont font("Times"); // or any font
        font.setPointSizeF(i); // this has round to int error (on 72 dpi screen 10.2 would be rounded to 10 and 10.6 to 11.0 etc)
        p.setFont(font);

        qreal piX = i * p.device()->logicalDpiX() / 72.0;
        qreal piY = i * p.device()->logicalDpiY() / 72.0;
        qreal xscale = piX / qRound(piX);
        qreal yscale = piY / qRound(piY);

        //p.save();
        p.translate(1, y);
        p.scale(xscale, yscale);
        p.drawText(0, 0, QString("This should be point size %1 but is %2!").arg(font.pointSizeF()).arg(QFontInfo(font).pointSizeF() * xscale));
        p.resetTransform();
        //p.restore();
        y += i;
    }
}

I can get desired result this way.

OTHER TIPS

This is not an unexpected behavior. See the lines below:

"This should be point size 10 but is 9.75!"
"This should be point size 10.2 but is 10.5!"
"This should be point size 10.4 but is 10.5!"
"This should be point size 10.6 but is 10.5!"
"This should be point size 10.8 but is 10.5!"
"This should be point size 11 but is 11.25!"
"This should be point size 11.2 but is 11.25!"
"This should be point size 11.4 but is 11.25!"
"This should be point size 11.6 but is 11.25!"
"This should be point size 11.8 but is 12!"
"This should be point size 12 but is 12!"
"This should be point size 12.2 but is 12!"
...

Then, check also the documentation:

Sets the point size to pointSize. The point size must be greater than zero. The requested precision may not be achieved on all platforms.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top