Set display precision different from internal precision in QDoubleSpinBox
-
So you want use two different representations, one your value 10.000000000001 and one the display 10
So create a function convert/deconvert to display your personal value and pass to SpinBox... -
I as a user would drive nuts, if the displayed value of "10" is actually "translated" to a value of "10.0000001" or "10" for the application, depending on the source of the "10" (rounded set-value in the first case, user typed-in in the latter).
I consider this bad user experience and programming style...
An no, it is not just a case of printf. The spinbox is an input element, not just a fancy display. Naturally, the entered value is exactly represented internally.
-
Actually, I would not be too sure that when using a Double, 10 isn't just 10.000000001 anyway. I would display the precision you are going to use the number with. That is, if the 10th decimal is relevant for your algorithm, make sure you display it.
What I would do (and should do for my own purposes as well, thanks for reminding me), is make a QDoubleSpinbox that has an extra button or dropdown or something that you use to control the precision. That makes it easy to use the spinbox with the set precision, but also possible to change to a higher precision if needed.
-
You can set the decimals property to a large value to prevent it from rounding and then use textFromValue(double) to display the number in your own way. I use it to create a spin box which displays using the 'g' format. Since the sizeHint is based upon the decimals property, it must also be adjusted.
Here is the idea. (The code below is incomplete.)
@
class DoubleSpinBox : public QDoubleSpinBox
{
public:
explicit DoubleSpinBox(QWidget *parent = 0);
virtual QString textFromValue();
virtual QSize sizeHint() const;
};
@@
DoubleSpinBox::DoubleSpinBox(QWidget *parent)
{
// Save default sizeHint before changing decimal property
cachedSizeHint = QDoubleSpinBox::sizeHint();// Set decimals to large value since QDoubleSpinBox rounds // with QString::number(value, 'f', decimals).toDouble() QDoubleSpinBox::setDecimals(std::numeric_limits<double>::max_exponent);
}
QString DoubleSpinBox::textFromValue(double value) const
{
return QString::number(value, 'g', std::numeric_limits<double>::digits10);
}QSize DoubleSpinBox::sizeHint() const
{
return cachedSizeHint;
}@
-
Volker, I understand where you are coming from. The application has three spinboxes, say a, b , and c. The user can input parameters into any one of the three. If the user inputs a parameter into spinbox a, some calculations are done and the values in spinboxes b and c are are updated. What is happening is that the calculations are off if I use setDecimal and set its integer value to something reasonable for display. This is why I'm asking if there is something like printf.
From what I think I understand is going on, it sounds like the private member value is an unadulturated double. The member function value() returns value rounded to the precision set with setDecimal. This may be where the problem is. If this is the case, without subclassing QDoubleSpinBox, is there a way to access value in its unadulturated form?
-
No, there is no member value with an unadulterated double. The value is rounded in setValue() before it is stored.
-
Bradley, I saw your reply just after I sent mine in. Thanks for the code. I'm thinking that subclassing might be the only way to go.
So, just to be sure, setValue() is called when setDecimals() has been called and value() is called to display the value in the SpinBox? I.e. setDecimal(4) leads to something like setValue( round( value() , 4 ) ) in order to display the value in the spinbox?
-
Below is the source for setDecimals() and setValue(). Yes, calling setDecimals() calls setValue(value()) and in setValue(), round(value) is called which uses the decimals property to round the number.
@
void QDoubleSpinBox::setDecimals(int decimals)
{
Q_D(QDoubleSpinBox);
d->decimals = qBound(0, decimals, DBL_MAX_10_EXP + DBL_DIG);setRange(d->actualMin, d->actualMax); // make sure values are rounded setValue(value());
}
void QDoubleSpinBox::setValue(double value)
{
Q_D(QDoubleSpinBox);
QVariant v(d->round(value));
d->setValue(v, EmitIfChanged);
}
@ -
Some kind of Validator/Placeholder
f.e.: "QDoubleValidator":http://doc.qt.nokia.com/latest/qdoublevalidator.html
or QRegExpValidator ?? -
Wow! That's crazy! Why would you do that?
To me, I was expecting setDecimals() to behave much like the iostream modifiers, and not to change the underlying value. This should be documented somewhere as I doubt it is the expected behavior from reading the documentation.
Looks like I'll have to subclass QDoubleSpinBox...
-
From http://doc.qt.nokia.com/4.7/qdoublespinbox.html#details
bq. Note: QDoubleSpinBox will round numbers so they can be displayed with the current precision. In a QDoubleSpinBox with decimals set to 2, calling setValue(2.555) will cause value() to return 2.56.
-
You can hack it!
Set up decimals to 4, but allows placing just 3, so it shouldn't round value...I think :)