For Qt 4.6.x, how to auto-size text to fit in a specified width?
Inside of my QGraphicsRectItem::paint(), I am trying to draw the name of the item within its rect(). However, for each of the different items, they can be of variable width and similarly names can be of variable length.
Currently I am starting with a maximum font size, checking if it fits and decrementing it until I find a font size that fits. So far, I haven't been able to find a quick and easy way to do this. Is there a better, or more efficient way to do this?
Thanks!
Code:
void checkFontSize
(QPainter *painter,
const QString
& name
) { // check the font size - need a better algorithm... this could take awhile
while (painter->fontMetrics().width(name) > rect().width()) {
int newsize = painter->font().pointSize() - 1;
painter
->setFont
(QFont(painter
->font
().
family(), newsize
));
}
}
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
Hi there!
Two days ago I solved it with QFont::setPointSizeF like this:
Code:
float factor = rect().width() / painter->fontMetrics().width(name);
if ((factor < 1) || (factor > 1.25))
{
QFont f
= painter
->font
();
f.setPointSizeF(f.pointSizeF()*factor);
painter->setFont(f);
}
This assumes, that your fonts width scales like its height. Works fine for me.
HIH
Johannes
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
This, or something along the same lines seem like the only way to me. Be careful that you don't get a runaway loop with zero or negative font size (width == 0?); not sure what QFontMetrics will make of that.
An approximation could go like: Pre-calculating the width of an "M" at each point size (Substitute the character set's widest glyph if you are using non-Latin characters). When you get your string, take its length and select the font size that gets length() Ms into the available width. Might be a bit quicker if you call this a lot.
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
Johannes - I just tried out the code snippet you supplied and so far so good! I like how your solution comes up with a good approximation in one pass. Thanks!
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
I have got the same problem, so I post here since this thread is in good place in Google :)
The solution provided by JohannesMunk works well for 1 line of text.
But what about auto-size text in a specified rectangle, possibly (but not necessary) wraping on multiple lines.
Do you have a solution for that ?
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
Hi!
How about using QFontMetrics::boundingRect with the Qt::TextWordWrap flag set?
The problem will be that word wrapping will usually only occur, after the scaling has been applied.
So the text will not be wrapped when called the first time.
Mmh..
Johannes
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
I needed this functionality myself - here is what I came up with:
Code:
qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());
QFont f
= painter
->font
();
qreal aspectRatio = painter->fontMetrics().lineSpacing() / painter->fontMetrics().averageCharWidth();
int pixelsize = sqrt(r.width()*r.height()/aspectRatio/(stitle.length()*3))*aspectRatio;
f.setPixelSize(pixelsize);
int flags = Qt::AlignCenter|Qt::TextDontClip|Qt::TextWordWrap;
if ((pixelsize * lod) < 13)
flags |= Qt::TextWrapAnywhere;
QRectF tbr
= fm.
boundingRect(r,flags,stitle
);
pixelsize = f.pixelSize()*qMin(r.width()*0.95/tbr.width(),r.height()*0.95/tbr.height());
f.setPixelSize(pixelsize);
painter->setFont(f);
painter->drawText(r,flags,stitle);
The idea of the first attempt to calculate a pixelsize is to calculate how big a letter can be if you want to distribute a certain amount of letters on the available space.
numberOfLetters = width / charWidth * height / (charWidth*aspectRatio)
=> pixelSize = charWidth * aspectRatio = sqrt ( width * height / numberOfLetters / aspectRatio) * aspectRatio;
For my scenario numberOfLetters is 3 times the amount of text I want to display, because I don't want to cover the whole item with text.
With this guess I call QFontMetricF::boundingRect and fine tune the result accordingly.
This works fine for my purpose.
HIH
Johannes
1 Attachment(s)
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
Quote:
Originally Posted by
JohannesMunk
This works fine for my purpose.
I'm confirming you that this solution (i named it the 2nd) fit at the best my requirements too.
Here is my two solutions comparison:
Attachment 7232
My scene doesn't has too much items, so the drawing performances are acceptable.
Thank you guys for shared your work.
Re: For Qt 4.6.x, how to auto-size text to fit in a specified width?
Hi Johannes / All
Could you please explain the math behind this?
"numberOfLetters = width / charWidth * height / (charWidth*aspectRatio)
=> pixelSize = charWidth * aspectRatio = sqrt ( width * height / numberOfLetters / aspectRatio) * aspectRatio;
"
I don't follow it.
Thank you
Tim