Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Issue with Text Rendering Length Differences Using QPainter
Forum Updated to NodeBB v4.3 + New Features

Issue with Text Rendering Length Differences Using QPainter

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 4 Posters 793 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    haukkagu
    wrote on 24 Feb 2024, 15:58 last edited by
    #1

    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:

    1. Drawing a sentence ("the quick brown fox jumps over the lazy dog") all at once using QPainter.drawText().

    2. 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!

    J H 2 Replies Last reply 24 Feb 2024, 16:06
    2
    • H haukkagu
      24 Feb 2024, 15:58

      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:

      1. Drawing a sentence ("the quick brown fox jumps over the lazy dog") all at once using QPainter.drawText().

      2. 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!

      J Online
      J Online
      JonB
      wrote on 24 Feb 2024, 16:06 last edited by
      #2

      @haukkagu
      int QFontMetrics::horizontalAdvance(QChar ch) const

      Warning: 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?

      1 Reply Last reply
      0
      • H haukkagu
        24 Feb 2024, 15:58

        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:

        1. Drawing a sentence ("the quick brown fox jumps over the lazy dog") all at once using QPainter.drawText().

        2. 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!

        H Offline
        H Offline
        haukkagu
        wrote on 24 Feb 2024, 16:19 last edited by
        #3

        @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!

        J 1 Reply Last reply 24 Feb 2024, 16:25
        0
        • I Offline
          I Offline
          IgKh
          wrote on 24 Feb 2024, 16:22 last edited by
          #4

          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.

          1 Reply Last reply
          2
          • H haukkagu
            24 Feb 2024, 16:19

            @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!

            J Online
            J Online
            JonB
            wrote on 24 Feb 2024, 16:25 last edited by JonB
            #5

            @haukkagu
            As @IgKh is saying and the docs, outputting characters in a string (adjacent to others) is not just "move by horizontal advance", it's context-dependent. And the code is more complex.

            1 Reply Last reply
            0
            • S Offline
              S Offline
              SamiV123
              wrote on 25 Feb 2024, 10:00 last edited by
              #6

              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.

              1 Reply Last reply
              0
              • H Offline
                H Offline
                haukkagu
                wrote on 27 Feb 2024, 08:55 last edited by
                #7

                Thanks for all the input!

                1 Reply Last reply
                0
                • H haukkagu has marked this topic as solved on 27 Feb 2024, 08:55

                1/7

                24 Feb 2024, 15:58

                • Login

                • Login or register to search.
                1 out of 7
                • First post
                  1/7
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved