Issue with Text Rendering Length Differences Using QPainter
-
wrote on 24 Feb 2024, 15:58 last edited by
Hello,
I'm encountering a problem when rendering text with QPainter in two different methods within a Qt-based project. Here's what I'm doing:
-
Drawing a sentence ("the quick brown fox jumps over the lazy dog") all at once using QPainter.drawText().
-
Drawing the same sentence character by character, moving the position for each drawText() call by the character's width as determined by QPainter.fontMetrics().horizontalAdvance().
QPainter painter(this); QString sentence = "the quick brown fox jumps over the lazy dog"; // Method 1 QPoint position = QPoint(25, 25); painter.drawText(position.x(), position.y(), sentence); // Method 2 position = QPoint(25, 50); for (QChar character : sentence) { painter.drawText(position, character); position.setX(position.x() + painter.fontMetrics().horizontalAdvance(character)); }
The issue is that the text rendered character by character becomes slightly longer than when rendered all at once, as illustrated here: https://postimg.cc/8jX0Wv6R.
It might seem subtle and insignificant, but it's causing significant issues in my project. I'm trying to make a Qt-based frontend for the terminal-based text editor Kakoune. In the editor, a line of text often contains parts of different text colors. Therefore, to render a line, I have to break the line into multiple parts and then render them after each other (similar to Method 2, but applied to chunks of text rather than individual characters). Since Method 2 makes the chunks of text slightly longer, the size differences become very noticable and distracting.
The problem within my project can be seen here: https://www.youtube.com/watch?v=dTejP0D4Dzw
(The blue rectangle is the cursor that moves around. Since the text chunks change when moving the cursor around, the text slightly juggles)Do you guys have any idea on how to fix this issue? If anything was unclear, please let me know!
Thanks!
-
-
Hello,
I'm encountering a problem when rendering text with QPainter in two different methods within a Qt-based project. Here's what I'm doing:
-
Drawing a sentence ("the quick brown fox jumps over the lazy dog") all at once using QPainter.drawText().
-
Drawing the same sentence character by character, moving the position for each drawText() call by the character's width as determined by QPainter.fontMetrics().horizontalAdvance().
QPainter painter(this); QString sentence = "the quick brown fox jumps over the lazy dog"; // Method 1 QPoint position = QPoint(25, 25); painter.drawText(position.x(), position.y(), sentence); // Method 2 position = QPoint(25, 50); for (QChar character : sentence) { painter.drawText(position, character); position.setX(position.x() + painter.fontMetrics().horizontalAdvance(character)); }
The issue is that the text rendered character by character becomes slightly longer than when rendered all at once, as illustrated here: https://postimg.cc/8jX0Wv6R.
It might seem subtle and insignificant, but it's causing significant issues in my project. I'm trying to make a Qt-based frontend for the terminal-based text editor Kakoune. In the editor, a line of text often contains parts of different text colors. Therefore, to render a line, I have to break the line into multiple parts and then render them after each other (similar to Method 2, but applied to chunks of text rather than individual characters). Since Method 2 makes the chunks of text slightly longer, the size differences become very noticable and distracting.
The problem within my project can be seen here: https://www.youtube.com/watch?v=dTejP0D4Dzw
(The blue rectangle is the cursor that moves around. Since the text chunks change when moving the cursor around, the text slightly juggles)Do you guys have any idea on how to fix this issue? If anything was unclear, please let me know!
Thanks!
wrote on 24 Feb 2024, 16:06 last edited by@haukkagu
int QFontMetrics::horizontalAdvance(QChar ch) constWarning: This function will produce incorrect results for Arabic characters or non-spacing marks in the middle of a string, as the glyph shaping and positioning of marks that happens when processing strings cannot be taken into account. When implementing an interactive text control, use QTextLayout instead.
Isn't this exactly your case?
-
-
Hello,
I'm encountering a problem when rendering text with QPainter in two different methods within a Qt-based project. Here's what I'm doing:
-
Drawing a sentence ("the quick brown fox jumps over the lazy dog") all at once using QPainter.drawText().
-
Drawing the same sentence character by character, moving the position for each drawText() call by the character's width as determined by QPainter.fontMetrics().horizontalAdvance().
QPainter painter(this); QString sentence = "the quick brown fox jumps over the lazy dog"; // Method 1 QPoint position = QPoint(25, 25); painter.drawText(position.x(), position.y(), sentence); // Method 2 position = QPoint(25, 50); for (QChar character : sentence) { painter.drawText(position, character); position.setX(position.x() + painter.fontMetrics().horizontalAdvance(character)); }
The issue is that the text rendered character by character becomes slightly longer than when rendered all at once, as illustrated here: https://postimg.cc/8jX0Wv6R.
It might seem subtle and insignificant, but it's causing significant issues in my project. I'm trying to make a Qt-based frontend for the terminal-based text editor Kakoune. In the editor, a line of text often contains parts of different text colors. Therefore, to render a line, I have to break the line into multiple parts and then render them after each other (similar to Method 2, but applied to chunks of text rather than individual characters). Since Method 2 makes the chunks of text slightly longer, the size differences become very noticable and distracting.
The problem within my project can be seen here: https://www.youtube.com/watch?v=dTejP0D4Dzw
(The blue rectangle is the cursor that moves around. Since the text chunks change when moving the cursor around, the text slightly juggles)Do you guys have any idea on how to fix this issue? If anything was unclear, please let me know!
Thanks!
wrote on 24 Feb 2024, 16:19 last edited by@haukkagu Yes, it looks like it. However, I've tried many other methods to calculate the width of the text: QFontMetrics::horizontalAdvance, QFontMetrics::size, QFontMetrics::averageCharWidth etc. Every method gives the wrong result.
But perhaps QTextLayout is better suited for what I'm trying to accomplish, so I'll have a look at that. Thank you!
-
-
wrote on 24 Feb 2024, 16:22 last edited by
Indeed - to render a string of text, it has to go though a process called "shaping", in which for each distinct user-visible character the proper glyph needs to be selected from the font, and those glyphs arranged horizontally and vertically. These process simply can't be done for each
QChar
separately, since context is essential.There are languages (like Arabic, mentioned by @JonB) where the same character can have different shapes depending on where it is located in the word. There are many languages where multiple Unicode code points combine to from a single visual character. But even sticking to just English, there is the matter of kerning - and it not being applied when working character by character seems to be what you are showing in the screenshot.
The easiest way forward is to use
QTextLayout
to handle those things for you. Use one for each paragraph. Rather than breaking the text itself, give it ranges of character formats that specify the different colors, fonts, weights, etc. -
@haukkagu Yes, it looks like it. However, I've tried many other methods to calculate the width of the text: QFontMetrics::horizontalAdvance, QFontMetrics::size, QFontMetrics::averageCharWidth etc. Every method gives the wrong result.
But perhaps QTextLayout is better suited for what I'm trying to accomplish, so I'll have a look at that. Thank you!
-
wrote on 25 Feb 2024, 10:00 last edited by
Your issue is because font metrics are just font metrics but kerning is more complicated than just font metrics.
In other words in kerning the vertical and horizontal advances and offsets depend on kerning pairs etc, i.e. the adjacent glyphs and the result is not necessarily the same as the simple font metrics for font glyphs.
-
wrote on 27 Feb 2024, 08:55 last edited by
Thanks for all the input!
-
1/7