PDA

View Full Version : QLabel Autosizing Reduction



Cotlone
22nd December 2011, 07:15
G'Day everyone,

I've made a subclass of the QLabel widget which automatically adjusts it's font size depending on the amount of space in it's frame. It expands quite well, and in a single pass can adjust to the correct size. When quickly minimising (ie using it upper right window buttons) to a smaller size, the widget visibly re-adjusts incrementally. I understand why this is happening based on my code. The widget cannot resize smaller than the contents so it much go as small as it can, then the content adjusts, and so on.

My question, how can I over come this 'slow' adjustment?

I thought of having the content take a small value when the frame is decreased in size, and then in a second pass could grow to the correct size (after the frame has adjusted). This still seems like a poor approach to me though. I am sure some of you guys must know how this should be handled.

Here is the code for my subclassed QLabel:




MyLabel::MyLabel(QWidget *parent):
QLabel(parent)
{
}

void MyLabel::resizeEvent(QResizeEvent *event)
{
// new font size
fontSizeRatio = 0.8;
qreal frameOffset = (1-fontSizeRatio)*0.75;
qreal textHeight = fontMetrics().height();

// (if text height is a bit small for the frame height) or (if text is height is a bit too big for frame height)
if(((1+frameOffset)*textHeight < height()) | (textHeight > (1-frameOffset)*height())){
int newFontSize = -1;

// if the text width ditates a greater height than the label, use that height, otherwise use the label height
if(heightForWidth(fontMetrics().width(text())) > height())
newFontSize = heightForWidth(fontMetrics().width(text()));
else
newFontSize = height();

newFontSize *= fontSizeRatio;

QFont newFont = font();
newFont.setPixelSize(newFontSize);
setFont(newFont);
}
}




Thanks very much for your help, I really appreciate it :)
- Cotlone

Lykurg
22nd December 2011, 09:14
I haven't tested, but I wouldn't call setFont(). I guess you can get rid of your problem if you store the calculated font size in a private member, call update() and then reimp paint event where you use the font size yourself. On setText() you once have to calculate the absolute minimum label size (with the minimum font you like) and set that size.

Cotlone
10th January 2012, 00:36
Thanks for your help Lykurg,

I'll give it a shot and see how it goes :)

-Cotlone

Cotlone
18th January 2012, 02:40
Ok, so is this basically making setFont() and font() unusable?
Would it be best to have an accurate portrayal of the font used in the widget with the font() function? In order to have a more robust solution I mean.

At any rate, I seem to have a functional auto-sizing QLabel subclass now. I am not sure if this is exactly what you mean, but let me know if you think I should change anything about it.




void MyLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);

QFont newFont(font());
newFont.setPixelSize(fontSize);
QFontMetrics fm(newFont);

int fontHeightForWidth = 0;
if (fm.width(text()))
fontHeightForWidth = width()*fm.height()/fm.width(text());

if(fontHeightForWidth < height())
fontSize = fontHeightForWidth;
else
fontSize = height();

fontSize *= fontSizeRatio;
newFont.setPixelSize(fontSize);

painter.setFont(newFont);
painter.drawText(event->rect(), Qt::AlignCenter, text());
}



Thanks for your help,
Cotlone

Lykurg
18th January 2012, 07:55
that is what I had in mind. Only fontSizeRatio is puzzling me.

Cotlone
19th January 2012, 02:29
The fontSizeRatio was a decimal fraction (eg 0.8) used to reduce the size of the text from the edge of its frame by some amount.

It seems there is a problem in my code now that you point this out. When I set the fontSizeRatio to 1, I would expect the text to meet the width of the frame. It appears too large though. I am not sure why this is the case. I am using width() to find the widget's width.

I doubt it, but is it something to do with the layouts it is in?

Cheers,
Cotlone


Edit: Actually, I measured the pixel height of the drawn text on the screen to be around 100pixels whilst the setPixelSize(fontSize) function was receiving a value of 64 pixels. In this condition, the text is surpassing the boundary of the widget. What could cause the drawn pixel size to differ from what is specified?

Lykurg
19th January 2012, 07:46
The pixel size of the font is not the absolute height! See
QFont f("Linux Libertine O");
f.setPixelSize(100);
QFontMetrics fm(f);
qWarning() << fm.height() << f.pixelSize();Take your calculation as a starting point for a loop where you adjust the size ala
QFont f = font();
realfontSize = fontSize;
while(QFontMetrics(f).height() > height())
{f.setPixelSize(realfontSize--);}
But you should do some optimizations... Or simply scale QPainter to the needed size!

Cotlone
20th January 2012, 01:36
Ah, right. I didn't realise that. Thanks Lykurg!

Here is my new code for those who may need it.




void MyLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);

QFont f(font());
f.setPixelSize(fontSize);
QFontMetrics fm(f);

int fontHeightForWidth = 0;
if (fm.width(text()))
fontHeightForWidth = width()*fm.height()/fm.width(text());

if(fontHeightForWidth < height())
fontSize = fontHeightForWidth;
else
fontSize = height();

f.setPixelSize(fontSize);
fontSize = fontSize*f.pixelSize()/QFontMetrics(f).height();
f.setPixelSize(fontSize);

painter.setFont(f);
painter.drawText(event->rect(), Qt::AlignCenter, text());
}



Thanks again mate!

- Cotlone