Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QPlainTextEdit with equal line heights



  • I need to get equal line-heights in a editor class. It contains only the visible part of very huge files. I use QPlainTextEdit as base because I only need some syntax highlighting. The project must work on windows, linux, and macOS.

    I need to estimate how many lines will fit into the editors visible part before painting to avoid flickering. Therefore it should not depend on dynamic line heights.

    Several problems occurred:

    • For some fonts QFontMetrics::lineSpacing() may result in different heights depending on some attributes (e.g. italic for Courier New is 17 - regular is 16).
    • Sometimes QFontMetrics::lineSpacing() returns a way lower value (-4) than the resulting QTextLayout::boundingRect() uses in the end (especially on mac).
    • trying to force a fixed line height based on the current font using QTextBlockFormat::setLineHeight(30, QTextBlockFormat::FixedHeight) was ignored by QPlainTextEdit.
    • Modifying QTextLayout::position() in each QTextBlock has a visual effect but produces graphical errors on interacting with the text (e.g. mouse drag).

    Any ideas how to force all lines into a given height?

    Regards,
    Jazzco



  • I'm getting closer to a solution. One way to get the same height for all lines is to use

    QFont::setHintingPreference(QFont::PreferNoHinting);
    

    What I have not yet solved satisfactorily is the determination of the height. In most cases it is possible to get the correct height with

    qtextline.height() + (qtextline.leading() < 0 ? qCeil(qtextline.leading()) : 0);
    

    Unfortunately the QTextLine represents the current old representation - not the upcoming new one, for which this calculation is the requirement. The central problem is that I did not manage to find this value in any of the members of the font or its metrics. I digged inside the Qt sources to understand how the height of the QTextLine is calculated but ended up in several internal undocumented engines.

    An example:
    The QFontMetrics on Windows 10 for Courier New in point size 8 has a height and a lineSpacing of 12. For whatever reasons the QTextLine created with this font in QPlainTextEdit returns a height of 13. Where does this extra pixel come from?

    Regards
    Jazzco



  • Ok, I finally found the solution. The issue was the use of QPlaintTextEdit::fontMetrics() method. It provides only the integer data QFontMetrics of the font and rounds values below .5 to the floor. To solve this an instance of QFontMetricsF is needed. Additionally for some fonts the lineSpacing is smaller than calculating the bounding QRectF of the string "Äg". So my solution is:

    int TextViewEdit::lineCount()    
    {
        QFontMetricsF metric(font());
        qreal lineHeight = qCeil(qMax(metric.lineSpacing(), metric.boundingRect("Äg").height()));
        return qFloor(qreal(viewport()->height()) / lineHeight);
    }
    

Log in to reply