Search code examples
qtqpainterqfontmetrics

Center text vertically when drawing with QPainter's drawText()


My strategy when centering text on images is to get bounding rectangle for that text and divide width or height by two. I did the same in this case. This is example I have created:

void CanvasWidget::paintEvent(QPaintEvent*)
{
    //Create image:
    QImage image(rect().width(), rect().height(), QImage::Format_RGB32);
    QPainter paint(&image);
    // White background
    image.fill(QColor("#FFF"));
    // set some metrics, position and the text to draw
    QFontMetrics metrics = paint.fontMetrics();
    int yposition = 100;
    QString text = "Hello world.";
    // Draw gray line to easily see if centering worked
    paint.setPen(QPen(QColor("#666"), 1, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin));
    paint.drawLine(0, yposition, image.width(), yposition);
    // Get rectangle
    QRect fontRect = metrics.boundingRect(text);
    // Black text
    paint.setPen(QPen(QColor("#000"), 1, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin));
    // Add half the height to position (note that Qt has [0,0] coordinates at the bottom of the image
    paint.drawText(4, yposition+round(((double)fontRect.height())/2.0), text);


    QPainter p(this);
    p.drawImage(rect(), image, image.rect());
    p.end();
}

This is the result - the text is under line instead centered on the line:

Android:
image description
Windows:
image description

I used lines to draw frame around the text based on metrics rectangle:

image description

Intended result was to center visible text exactly around the given point/line:

image description

To put you in perspective, this is the actual problem I am having:
image description
The numbers should be in the middle of the lines, not so much below.

The function I am using returns size including accents and other big characters that aren't there. How do I get the rectangle in pixels only for characters that are there?


Solution

  • Not quite sure what you're asking, but if it's why does the bounding rect appear wrong, it's because you're not taking into account characters that have accents in the font such as é, å etc. The bounding rect returned from font metrics includes these.

    As it states in the boundingRect documentation

    The height of the bounding rectangle is at least as large as the value returned by height().

    This is not the case for tightBoundingRect that will, I expect, provide the right result.