Reputation: 617
QSpinBox/QDoubleSpinBox has default of decimal value. Is it possible to change decimal to angular?
UPDATE> Please see the picture. This is the effect i want to get in QSpinBox/QDoubleSpinBox.
Upvotes: 0
Views: 1828
Reputation: 49279
First - using a single spin box to manipulate such a value is not applicable, because it represents a significant range. A dedicated spin box for every component would be much easier from a user experience standpoint.
Second - if you still insist on a single spinbox, Qt doesn't have a widget that can do that out of the box. You can however easily extend on QDoubleSpinBox
and overload the textFromValue()
method, which is the one that determines what text the spin box is showing, and then you can compose a string value from whatever raw data you have to represent the location.
Upvotes: 1
Reputation: 37512
Yes it is possible. Just override valueFromText
, textFromValue
and validate
(optionally fixup
).
textFromValue
should be easyvalueFromText
and validate
requires a parsing functionality, so extract common method for it.fixup
use only if you know how to correct user mistakes and when validate
returns QValidator::Intermediate in some cases.See documentation.
Here is my solution C++11:
#ifndef DEGREESPINBOX_H
#define DEGREESPINBOX_H
#include <QDoubleSpinBox>
class DegreeSpinBox : public QDoubleSpinBox
{
Q_OBJECT
public:
using QDoubleSpinBox::QDoubleSpinBox;
QString textFromValue(double value) const override;
double valueFromText(const QString &text) const override;
QValidator::State validate(QString &text, int &pos) const override;
private:
static void extractDegMinSecFrom(double value,
int *degrees,
int *minutes,
double *seconds);
static bool parse(QString str, double *result);
static bool areSeparatorsValid(QChar deg, QChar min, QChar sec);
};
#endif // DEGREESPINBOX_H
cpp file
#include "degreespinbox.h"
#include <QTextStream>
#include <cmath>
QString DegreeSpinBox::textFromValue(double value) const {
int degrees, minutes;
double seconds;
extractDegMinSecFrom(value, °rees, &minutes, &seconds);
return QString(tr("%1° %2′ %3″"))
.arg(degrees).arg(minutes).arg(seconds);
}
double DegreeSpinBox::valueFromText(const QString &text) const {
double result = 0;
auto ok = parse(text, &result);
Q_ASSERT(ok);
return result;
}
QValidator::State DegreeSpinBox::validate(QString &text, int &pos) const {
Q_UNUSED(pos)
return parse(text, nullptr) ? QValidator::Acceptable : QValidator::Invalid;
}
void DegreeSpinBox::extractDegMinSecFrom(double value,
int *degrees,
int *minutes,
double *seconds) {
Q_ASSERT(degrees);
Q_ASSERT(minutes);
Q_ASSERT(seconds);
double degreesDouble;
double minutesDouble = std::modf(value, °reesDouble) * 60;
*degrees = static_cast<int>(degreesDouble);
*seconds = std::modf(minutesDouble, &minutesDouble) * 60;
*minutes = static_cast<int>(minutesDouble);
}
bool DegreeSpinBox::parse(QString str, double *result) {
QTextStream stream(&str);
int degrees(0), minutes(0);
double seconds(0);
// %1° %2′ %3″"
QChar symbolDegree(0), symbolMinutes(0), symbolSeconds(0);
stream >> degrees >> symbolDegree
>> ws >> minutes >> symbolMinutes
>> ws >> seconds >> symbolSeconds;
bool success = stream.status() == QTextStream::Ok
&& areSeparatorsValid(symbolDegree, symbolMinutes, symbolSeconds)
&& minutes >=0 && minutes < 60
&& seconds >=0 && seconds < 60;
if (success && result) {
*result = (seconds / 60.0 + minutes) / 60.0 + degrees;
}
return success;
}
bool DegreeSpinBox::areSeparatorsValid(QChar deg, QChar min, QChar sec) {
return deg == QChar(L'°')
&& min == QChar(L'′')
&& sec == QChar(L'″');
}
Upvotes: 0