PDA

View Full Version : Spinbox sizehint



Alundra
21st February 2014, 16:30
Hi all,
I have a custom spinbox who is a slider spinbox.
I have reimplemented size hint because I don't want the box is large because of decimals/min/max.
but I want it to be enough large to show all the value if added in a layout.
Is it possible to write a sizehint function who do that in Qt ?
Thanks for the help

anda_skoa
21st February 2014, 18:30
Is it possible to write a sizehint function who do that in Qt ?


Yes.

Cheers,
_

P.S.: In case you are asking how to do that: return a QSize object that has a width value large enough for the spinbox to draw its content according to your rules

Alundra
21st February 2014, 19:21
P.S.: In case you are asking how to do that: return a QSize object that has a width value large enough for the spinbox to draw its content according to your rules
Yea it's exactly what I would, just have the size to show the value, not offset about min/max/decimals, so a basic calcule of width.
But since it's based on the font character width, how Qt want it to be written ?
Thanks

anda_skoa
21st February 2014, 20:01
Assuming you have the text that needs to be displayed as a string, see QFontMetrics to calculate the width needed to display it given the widget's current font.

Cheers,
_

Alundra
21st February 2014, 21:21
QSize CDoubleSliderSpinBox::minimumSizeHint() const
{
const QFontMetrics FontMetrics = fontMetrics();
const int Width = FontMetrics.width( "0.00" );
const int Height = FontMetrics.height();
return QSize( Width, Height );
}

QSize CDoubleSliderSpinBox::sizeHint() const
{
const QFontMetrics FontMetrics = fontMetrics();
const int Width = FontMetrics.width( textFromValue( value() ) );
const int Height = FontMetrics.height();
return QSize( Width, Height );
}

Give me bad result, Do you see what's going wrong there ?

anda_skoa
22nd February 2014, 12:41
What do you mean with "bad result"?

Cheers,
_

Alundra
22nd February 2014, 17:42
http://uppix.com/f-BadSizeHint5308d288001585fe.png
Using value returned by minimumSizeHint() I have the result on the left, Using hard coded fixed size I have result on the right.
minimumSizeHint calcules for 0.0, it returns 22 on width and 13 on height, the hard coded value are 50 on width, 18 on height.
Since it calcule to have 0.0 bounded, 30.0 should not be visible but 0.0 should be visible and you can see on the screenshot that it's not.
Absolutly no one value can be read on the size hint returned.

Edit:
Here the code QAbstractSpinBox sizehint from source.
I don't understand all but I see that use min/max, maybe it's just needed to reuse this code and remove the min/max when used.
I wait an answer from you to know the correct way.


QSize QAbstractSpinBox::sizeHint() const
{
Q_D(const QAbstractSpinBox);
if (d->cachedSizeHint.isEmpty()) {
ensurePolished();

const QFontMetrics fm(fontMetrics());
int h = d->edit->sizeHint().height();
int w = 0;
QString s;
s = d->prefix + d->textFromValue(d->minimum) + d->suffix + QLatin1Char(' ');
s.truncate(18);
w = qMax(w, fm.width(s));
s = d->prefix + d->textFromValue(d->maximum) + d->suffix + QLatin1Char(' ');
s.truncate(18);
w = qMax(w, fm.width(s));
if (d->specialValueText.size()) {
s = d->specialValueText;
w = qMax(w, fm.width(s));
}
w += 2; // cursor blinking space

QStyleOptionSpinBox opt;
initStyleOption(&opt);
QSize hint(w, h);
QSize extra(35, 6);
opt.rect.setSize(hint + extra);
extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
QStyle::SC_SpinBoxEditField, this).size();
// get closer to final result by repeating the calculation
opt.rect.setSize(hint + extra);
extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt,
QStyle::SC_SpinBoxEditField, this).size();
hint += extra;

opt.rect = rect();
d->cachedSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this)
.expandedTo(QApplication::globalStrut());
}
return d->cachedSizeHint;
}

anda_skoa
23rd February 2014, 13:57
Your spinbox seems to have sub controls (buttons), but your sizeHint does not include the size needed for them.

Cheers,
_

Alundra
23rd February 2014, 17:01
I tried to add the use of button but that give me big values, here the actual code :


QSize CDoubleSliderSpinBox::sizeHint() const
{
// Be sure for valid calcule.
ensurePolished();

// Compute text size.
const QFontMetrics FontMetrics = fontMetrics();
const int TextWidth = FontMetrics.width( text() );
const int TextHeight = FontMetrics.height();

// Initialize the SpinBox style option.
QStyleOptionSpinBox opt;
initStyleOption( &opt );

// Get size of buttons.
const QSize UpButtonSize = style()->subControlRect( QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxUp ).size();
const QSize DownButtonSize = style()->subControlRect( QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxDown ).size();

// Return the final size.
return QSize( TextWidth, TextHeight ) + UpButtonSize + DownButtonSize;
}

What's going wrong, I use the style()->subControlRect( ... ) function to test intersection and it works, why not here ?
Thanks for the help

anda_skoa
23rd February 2014, 21:59
You are adding the two button sizes.

Just think how that will behave: lets say your text is 50x20 and each button is 25x15.
What you do is (50+25+25, 20+15+15)
What you want is (50+25, 30)

The two buttons are on top of each other, so obviously their contribution to the width is not the sum of their widths, but the maximum of the two values.
Simiar, for the height, the two button heights need to be added up and then the maximum of that value and the text height is the result height.

Cheers,
_

Alundra
23rd February 2014, 22:37
Both give the same height value 239, who is a lot more than it's needed, I let you a screenshot :
http://uppix.com/f-SizeHintProb530a69f900158956.png
Here it's just :

return QSize( TextWidth, TextHeight ) + UpButtonSize;
Since both give the same values I dont do the max( ... ) to test.
TextHeight always has the value of 13.
Hope you know the problem.

EDIT : using hard coded value of size of image Up/Down (.png) :

return QSize( TextWidth, TextHeight ) + QSize( 9, 6 );
I have correct size, both image has same size.
But that must work auto, hard coded is bad.
Hope you know the problem.

anda_skoa
23rd February 2014, 23:49
Both give the same height value 239, who is a lot more than it's needed, I let you a screenshot :
http://uppix.com/f-SizeHintProb530a69f900158956.png
Here it's just :


return QSize( TextWidth, TextHeight ) + UpButtonSize;


I recommend that you read what I wrote before.
I also recommend that you think about that code. I especially recommend to think about the + operator.



Hope you know the problem.

Yes, I do. The problem is that you are trying to find a solution by brute force trial&error instead of stopping for a moment, thinking and then applying the obvious and already suggested solution.

I can highly recommend that "thinking" thing, it tremendously helps to solve problems.

Cheers,
_

Alundra
24th February 2014, 14:54
I have think and searched on the doc of Qt and found some function who could make the code auto.
Here the actual code using these function based on the base QDoubleSpinBox code, so should be correct ?


QSize CDoubleSliderSpinBox::sizeHint() const
{
// Be sure for valid calcule.
ensurePolished();

// Compute text size.
const QFontMetrics FontMetrics = fontMetrics();
const int TextWidth = FontMetrics.width( text() );
const int TextHeight = lineEdit()->sizeHint().height();

// Initialize the SpinBox style option.
QStyleOptionSpinBox opt;
initStyleOption( &opt );

// Set the style option rect.
opt.rect = rect();

// Compute the size from contents.
const QSize ContentSize = QSize( TextWidth, TextHeight );
const QSize SizeFromContents = style()->sizeFromContents( QStyle::CT_SpinBox, &opt, ContentSize, this );

// Return the final size.
return SizeFromContents.expandedTo( QApplication::globalStrut() );
}

It's funky to have size hint working correctly.

anda_skoa
24th February 2014, 15:24
If it works for you then it is correct as far as you are concerned, no? :-)

Cheers,
_

Alundra
24th February 2014, 18:07
If you validate this research so it's ok.
I just saw the mouse wheel problem in Qt, only mouse wheel up works.
EDIT : Apparently using up key and down key the same problem as mouse wheel.
For the mouse wheel problem that demand to rewrite the mouse wheel virtual surely.
One thing I now see is spinBox take a lot of space because of button and surely no way exist other than working without them.
The only solution to that is to have a slider line edit widget surely who act like spinBox but without control.