May 17, 2011

dnadave dnadave
Lab Rat
24 posts

Set display precision different from internal precision in QDoubleSpinBox

Page  
1

How can I set the display precision separate from the internal precision of the value in a QDoubleSpinBox? If I use setDecimals, it changes the internal precision such that setDecimals(4) changes value from 1.12345 to 1.1235. This ruins the numerical stability of some code I have.

I also don’t want to have 1.12345 displayed in the spinbox, but rather something like 1.123.

Thanks!!

Dave H

16 replies

May 17, 2011

Franzk Franzk
Lab Rat
830 posts

How would you expect to control the numerical stability if you have two different representations, but the results are always coming from string conversions?

 Signature 

“Horse sense is the thing a horse has which keeps it from betting on people.”—W.C. Fields

http://www.catb.org/~esr/faqs/smart-questions.html

May 17, 2011

dnadave dnadave
Lab Rat
24 posts

Not two different representations, but something like a printf conversion for display only. Is there something like printf for the QDoubleSpinBox display?

May 17, 2011

stuk stuk
Ant Farmer
540 posts

I don’t understand what is the problem from 1.12345 to 1.1235 is round up.
What mean ruins the numerical stability of your code?

May 17, 2011

dnadave dnadave
Lab Rat
24 posts

So, the client for whom I’m doing this work wants the display to real 10 when the value is 10.00001. What happens now is the SpinBox is displaying 10.00001. If I call setDecimals with some value, say 3, then the underlying value is rounded to three significant digits. So, setDecimals changes the precision of the underlying value, ruining the numerical stability of the algorithm, and does not just affect the display precision.

What I need is a way to change only the display precision and keep the underlying value unchanged.

May 17, 2011

stuk stuk
Ant Farmer
540 posts

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…

May 17, 2011

Volker Volker
Robot Herder
5428 posts

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.

May 17, 2011

Andre Andre
Area 51 Engineer
6031 posts

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.

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

May 17, 2011

Bradley Bradley
Lab Rat
314 posts

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.)

  1. class DoubleSpinBox : public QDoubleSpinBox
  2. {
  3. public:
  4.     explicit DoubleSpinBox(QWidget *parent = 0);
  5.     virtual QString textFromValue();
  6.     virtual QSize sizeHint() const;
  7. };

  1. DoubleSpinBox::DoubleSpinBox(QWidget *parent)
  2. {
  3.     // Save default sizeHint before changing decimal property
  4.     cachedSizeHint = QDoubleSpinBox::sizeHint();
  5.  
  6.     // Set decimals to large value since QDoubleSpinBox rounds
  7.     // with QString::number(value, 'f', decimals).toDouble()
  8.     QDoubleSpinBox::setDecimals(std::numeric_limits<double>::max_exponent);
  9. }
  10.  
  11. QString DoubleSpinBox::textFromValue(double value) const
  12. {
  13.     return QString::number(value, 'g', std::numeric_limits<double>::digits10);
  14. }
  15.  
  16. QSize DoubleSpinBox::sizeHint() const
  17. {
  18.     return cachedSizeHint;
  19. }

 Signature 

Nokia Certified Qt Specialist.

May 17, 2011

dnadave dnadave
Lab Rat
24 posts

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?

May 17, 2011

Bradley Bradley
Lab Rat
314 posts

No, there is no member value with an unadulterated double. The value is rounded in setValue() before it is stored.

 Signature 

Nokia Certified Qt Specialist.

May 17, 2011

dnadave dnadave
Lab Rat
24 posts

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?

May 17, 2011

Bradley Bradley
Lab Rat
314 posts

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.

  1. void QDoubleSpinBox::setDecimals(int decimals)
  2. {
  3.     Q_D(QDoubleSpinBox);
  4.     d->decimals = qBound(0, decimals, DBL_MAX_10_EXP + DBL_DIG);
  5.  
  6.     setRange(d->actualMin, d->actualMax); // make sure values are rounded
  7.     setValue(value());
  8. }
  9.  
  10. void QDoubleSpinBox::setValue(double value)
  11. {
  12.     Q_D(QDoubleSpinBox);
  13.     QVariant v(d->round(value));
  14.     d->setValue(v, EmitIfChanged);
  15. }

 Signature 

Nokia Certified Qt Specialist.

May 17, 2011

Peppy Peppy
Hobby Entomologist
389 posts

Some kind of Validator/Placeholder
f.e.: QDoubleValidator [doc.qt.nokia.com]
or QRegExpValidator ??

May 17, 2011

dnadave dnadave
Lab Rat
24 posts

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…

May 17, 2011

Bradley Bradley
Lab Rat
314 posts

From http://doc.qt.nokia.com/4.7/qdoublespinbox.html#details

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.

 Signature 

Nokia Certified Qt Specialist.

Page  
1

  ‹‹ Linking 2 QSpinBoxes      I can’t Insert a new data to SQLITE ››

You must log in to post a reply. Not a member yet? Register here!