是的,这是可能的。只需覆盖valueFromText、textFromValue 和validate(可选fixup)。
-
textFromValue 应该很简单
-
valueFromText 和validate 需要解析功能,所以提取常用方法。
-
fixup 仅在您知道如何纠正用户错误以及在某些情况下当validate 返回QValidator::Intermediate 时使用。
见documentation。
这是我的 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 文件
#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'″');
}