Qt World Summit: Submit your Presentation

Trying to collapse per-character QPainter::drawText() Qt commands into a single string drawText(). Monospacing format is not being preserved...

  • Hello everyone,

    I have poked around for quite some time on the net trying to find insight into this problem, but I've had no luck so far.
    Below is an example of what draws correctly:
    for (int i = 0; i < string.size(); ++i)
    QString char_string(string.at(i));
    QRect box(current_pos, char_size);
    m_painter->drawText(box, Qt::AlignCenter, char_string);
    current_pos.setX(current_pos.x() + char_size.width());

    So here I am calling drawText() on each character of the string in order to print it in a monospaced format. Each character is printed neatly in the center of its own box, and the spacing between characters remains constant. char_size is a QSize obj which is a rect in which i print each character.

    I need to modify this and just pass 'string' into drawText(), making only one function call per string. The problem is that no matter how I configure my font, it will not actually print each character aligned how I need them the way that the above snippet does.

    Here is my current approximation of what I need to do:

    QRect box(pos, char_size);
    box.setWidth(char_size.width() * string.size());
    m_painter->drawText(box, Qt::AlignVCenter /| Qt::AlignHCenter/ | Qt::AlignJustify, string);

    Here is a snapshot of roughly how I'm trying to set up the font. You can see I'm trying commenting and uncommenting certain lines together to try to replicate the spacing configuration I need:

    @QFont QtCanvas::GetFont(const FontData &font_data)
    QFont font;

        font.setFamily("Droid Sans Mono");
        QFontMetrics font_metrics(font);
        //font.setLetterSpacing(QFont::AbsoluteSpacing, font_data.m_size.width - font_metrics.boundingRect(QChar('H')).width());
        //font.setLetterSpacing(QFont::AbsoluteSpacing, font_data.m_size.width - font_metrics.boundingRect(QChar('0')).width());
        //font.setLetterSpacing( QFont::AbsoluteSpacing, ( font_data.m_size.width );
        //font.setWordSpacing( -font_data.m_size.width + (font_metrics.boundingRect(QChar('H')).width()) );
        //font.setWordSpacing(font_data.m_size.width  - font_metrics.boundingRect(QChar('H')).width() * -1);
        return font;

    The font I'm using is a monospaced font loaded from the resource file, though for some silly reason when I delve into the QFontMetrics and print out each character's bounding rect, each character has a varied width (no longer monospaced, fixed-width). So, when I tell it to draw, it's drawing the characters in sequence using their truncated widths and destroys the monospacing. This is bad... I need each character to line up and take up the same width of every other character. Spacing and character width should be uniform.

    Does anyone have any useful insight? All help is appreciated, I can provide more information if things aren't clear!

  • Lifetime Qt Champion


    Might be a stupid question but: are you sure you are getting the font you want to have ?

  • Hey,

    Thank you for taking an interest in my post. Not a stupid question at all, but I can confirm that my text is being drawn with the "Droid Sans Mono" font. It's included in the Qt project resource file, and does draw the font with the correct shapes. I can open the font file in a font viewer and it seems fine as well.

    I think either there are some parts of the API I don't understand, or there is some limitation to the API and I won't be able to make only one draw call with this configuration. To better shed light on my confusion for instance - some of the flags you can pass with setStyleHint seem to indicate the properties I want, but I don't know how to apply them directly (monospaced typesetting, as a typewriter would output). The API hints at a font selection algorithm, but I already know what font I want to use and I'm supplying it myself... I figured the spacing would be fine by default with this font, but I am having difficulties. If there is a great deal of confusion about this problem, I can perhaps show some screenshots of output tomorrow.

  • Alright its been a while and I'd rather this thread not get buried -

    I've been looking at my problem, and I am able to replicate the spacing I want if I use QFont::setStretch(),but I have to use a different stretch value for different font sizes, and although I can stretch the spacing out to how I need it, it also stretches the letters of the font itself which I'd rather avoid.

    Whenever I try to use QFont::setLetterSpacing(), I can modify the letter spacing but the character widths are already all different per-character (I need to have the same character width, but chars such as '-' and 'i' for instance are noticeably thinner than other characters... which causes my spacing issues). This is how Qt is interpreting the font, but I need it to be monospaced, and if I decide to change the spacing it needs to modify the spacing for every character the same way.

    I thought maybe setting flags with setKerning(false); and setFixedPitch(true) might force characters to be monospaced, but it's still not correct...

    Is there something I can change about the way the font gets loaded by Qt? As of now, we're just adding it to the resource file, then just saying font.setFamily("Droid Sans Mono"); along with the aformetioned flags, but it's not working quite as expected... I need to be able to force the characters to retain equal widths.

  • Lifetime Qt Champion

    Did you also add your font to the "QFontDatabase":http://qt-project.org/doc/qt-4.8/qfontdatabase.html ?

  • Yeah dude, I called addApplicationFont() in an initialization function.

    The fonts I add to the database are registering correctly ( I've verified with console printfs using QFontDatabase::families(). Also, the stuff is just drawing in the font straight up, so I know it sees it.

    The problem seems to just boil down to character spacing - I can scale the string horizontally via the stretch function and get the right spacing, but that also stretches the characters so they look fatter. I want to scale the spacing the same way. I have had less success trying to directly change the font spacing with setLetterSpacing(); when I modify the spacing, it seems to act on the bounding boxes of the font as seen using the QFontMetrics stuct generated by the font, which shrink to the physical size of each character and don't keep the fixed width. My string's spacing is then goofed up.

    Side note - is there a way to actually see the result of the 'font selection algorithm' after it's selected the font it's gonna use? All I can see is being able to print out the DB that it can select from. It took me a while to figure out what font it actually selects for instance when I specify font family 'Monospace' because Monospace isnt a font (as near as I can tell, Monospace is a group of different fonts).

    Edit - also, forgot to mention I've been experimenting with other fonts. Switched to DejaVu Sans Mono which seems to work the same way... though I probably need to regress with the other font a bit and try what I've tried already again on the seperate font.

  • Hi.

    About a year later, I am facing a similar problem. I've found out the problem might be that the font doesn't provide all the necessary characters, in which case Qt tries to find and use characters from another similar font.

    To see if that's the case, use this setting:

    @font.setStyleStrategy(QFont::StyleStrategy(font.styleStrategy() | QFont::NoFontMerging));@

    I'm still trying to figure out how to solve the problem.

  • Hi,

    this challenges also me. Essentially a QPainter method that lets me pass an array with the character widths would be sufficient. PostScript, Windows or OS X have such functions - xshow, ExtTextOut(), CGContextShowGlyphsWithAdvances()

    Does anybody know a Qt method that allows to control the character advances? This would provide the means to draw monospaced text even with proportional fonts.

Log in to reply