QSpinBox / QDoubleSpinBox tiene un valor decimal predeterminado. ¿Es posible cambiar de decimal a angular?

ACTUALIZAR> Vea la imagen. Este es el efecto que quiero obtener en QSpinBox / QDoubleSpinBox.

enter image description here

0
Rt Rtt 24 feb. 2018 a las 16:20

2 respuestas

La mejor respuesta

Sí, es posible. Simplemente anule valueFromText, textFromValue y validate (opcionalmente fixup).

  • textFromValue debería ser fácil
  • valueFromText y validate requieren una función de análisis, así que extraiga un método común para ello.
  • fixup utilícelo solo si sabe cómo corregir los errores del usuario y cuando validate devuelve QValidator :: Intermediate en algunos casos.

Consulte la documentación.

Aquí está mi solución 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

Archivo cpp

#include "degreespinbox.h"
#include <QTextStream>
#include <cmath>

QString DegreeSpinBox::textFromValue(double value) const {
    int degrees, minutes;
    double seconds;
    extractDegMinSecFrom(value, &degrees, &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, &degreesDouble) * 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'″');
}
0
Marek R 24 feb. 2018 a las 18:03

Primero, usar un solo cuadro de giro para manipular dicho valor no es aplicable, porque representa un rango significativo. Una caja de giro dedicada para cada componente sería mucho más fácil desde el punto de vista de la experiencia del usuario.

En segundo lugar, si todavía insiste en una sola caja de giro, Qt no tiene un widget que pueda hacer eso de inmediato. Sin embargo, puede extender fácilmente en QDoubleSpinBox y sobrecargar el método textFromValue(), que es el que determina qué texto muestra el cuadro de número, y luego puede componer un valor de cadena a partir de los datos sin procesar que tenga representar la ubicación.

1
dtech 24 feb. 2018 a las 18:50