【问题标题】:Qt: How to set QSpinBox/QDoubleSpinBox to angular values?Qt:如何将 QSpinBox/QDoubleSpinBox 设置为角度值?
【发布时间】:2018-02-24 13:20:25
【问题描述】:

QSpinBox/QDoubleSpinBox 默认为十进制值。是否可以将十进制更改为角度?

更新>请看图片。这是我想在QSpinBox/QDoubleSpinBox中得到的效果。

【问题讨论】:

  • 弧度还是度数?
  • @p-a-o-l-o 是的。如何将 QSpinBox 从十进制设置为弧度/度值,这是我的问题。
  • 我不得不承认我从来没有听说过角数系统,我用过二进制、八进制、十进制和十六进制,我听说过十二进制和六十进制的文化,但是我没有听说过 Angular,我在互联网上也找不到任何关于它的信息。
  • 撇开讽刺不谈,这是一个很好的例子,说明了为什么科学命名法在具体科学中很重要,因为没有适当的一个事情就没有意义,这个问题就是一个很好的例子。
  • @dtech 在 Excel 中输入角度值并不难。因此,我问如何在 Qt 中做。

标签: qt pyqt


【解决方案1】:

首先 - 使用单个旋转框来操作这样的值是不适用的,因为它代表了一个重要的范围。从用户体验的角度来看,每个组件的专用旋转框会更容易。

第二 - 如果您仍然坚持使用单个 spinbox,Qt 没有可以开箱即用的小部件。但是,您可以轻松地扩展 QDoubleSpinBox 并重载 textFromValue() 方法,该方法确定旋转框显示的文本,然后您可以从您必须代表该位置的任何原始数据组成一个字符串值。

【讨论】:

  • 我认为没有必要拥有 3 个 QSpinBox,一个就足够了,因为如果分针增加,度数的旋转框必须受到影响,彼此也是如此。它应该类似于 QDateTimeEdit。
  • @eyllanesc 你的意思是达到 1 度用户必须旋转 60 次?
  • @eyllanesc 对我来说 QDateTimeEdit 不是一个“旋转框”——它是一个下拉日历的行编辑。 “现代”多组件控制对每个组件都有专用控制。这很有意义。有很多方法可以做到这一点,但看起来它们都超出了 OP 的范围。 3 个 spinboxes 是他最好的机会,虽然不是“很好”,但从用户体验的角度来看它是完全足够的。
  • @dtech QDateTimeEdit 继承自 QAbstractSpinBox,所以它是一种 SpinBox,目前就是这样。显然有几种方法可以创建您想要的内容,您可以使用 3 个旋转框创建,或者使用新控件创建自定义小部件等。
  • @p-a-o-l-o QSpinBox 是可编辑的,类似于 QLineEdit,因此不需要旋转 60 次。
【解决方案2】:

是的,这是可能的。只需覆盖valueFromTexttextFromValuevalidate(可选fixup)。

  • textFromValue 应该很简单
  • valueFromTextvalidate 需要解析功能,所以提取常用方法。
  • 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, &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'″');
}

【讨论】:

  • 那么,valueFromText 覆盖应该为以下文本返回什么 intdouble 值:180° 45' 20''
  • @p-a-o-l-o well 64 位实数具有足够的分辨率。钳制的 0 到 1 值可以表示整个范围,因此坐标系中心的坐标将为 0.5x0.5,从那时起,您可以通过计算商和提示将其转换为所需的任何单位组合。 180° 45' 20'' 将是 0.502098765。
  • 此外,具有 53 位精度的 64 位实数将比使用整数的° ' '' 格式提供大约 70 亿倍 的分辨率。
  • "nice" 我已经提供了完整的工作代码(我已经测试过了)并且有人在没有解释的情况下投票否决了我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 2019-06-04
相关资源
最近更新 更多