QtQuick中弧度与角度切换管理

在QtQuick中实现角度与弧度的自动切换:

1. 创建角度/弧度管理类 (AngleRadiansManager)

// anglemanager.h
#include <QObject>
#include <cmath>

class AngleManager : public QObject {
    Q_OBJECT
    Q_PROPERTY(bool useDegrees READ useDegrees WRITE setUseDegrees NOTIFY useDegreesChanged)

public:
    explicit AngleManager(QObject *parent = nullptr);

    bool useDegrees() const;
    void setUseDegrees(bool useDegrees);

    // 核心转换函数
    Q_INVOKABLE double toDisplayUnit(double value, bool isStoredInRadians) const;
    Q_INVOKABLE double fromDisplayUnit(double displayValue, bool storeAsRadians) const;

signals:
    void useDegreesChanged();

private:
    bool m_useDegrees = true; // 默认显示角度
};

// anglemanager.cpp
#include "anglemanager.h"

AngleManager::AngleManager(QObject *parent) : QObject(parent) {}

bool AngleManager::useDegrees() const { return m_useDegrees; }

void AngleManager::setUseDegrees(bool useDegrees) {
    if (m_useDegrees != useDegrees) {
        m_useDegrees = useDegrees;
        emit useDegreesChanged();
    }
}

double AngleManager::toDisplayUnit(double value, bool isStoredInRadians) const {
    if (m_useDegrees && isStoredInRadians) {
        return qRadiansToDegrees(value); // 弧度 -> 角度
    } else if (!m_useDegrees && !isStoredInRadians) {
        return qDegreesToRadians(value); // 角度 -> 弧度
    }
    return value; // 不需要转换
}

double AngleManager::fromDisplayUnit(double displayValue, bool storeAsRadians) const {
    if (m_useDegrees && storeAsRadians) {
        return qDegreesToRadians(displayValue); // 显示角度 → 存储弧度
    } else if (!m_useDegrees && !storeAsRadians) {
        return qRadiansToDegrees(displayValue); // 显示弧度 → 存储角度
    }
    return displayValue; // 不需要转换
}

2. 注册到QML上下文

// main.cpp
#include "anglemanager.h"

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);
    
    AngleManager angleManager;
    QQmlApplicationEngine engine;
    
    // 注册单例管理类
    engine.rootContext()->setContextProperty("angleManager", &angleManager);
    
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

3. QML控件实现

// 切换按钮
Switch {
    text: qsTr("角度模式")
    checked: angleManager.useDegrees
    onToggled: angleManager.setUseDegrees(checked)
}

// 使用示例1: 显示角度值(内部存储为弧度)
TextInput {
    property double angleRadians: Math.PI / 4  // 内部始终以弧度存储
    
    text: angleManager.toDisplayUnit(angleRadians, true).toFixed(2)
    validator: DoubleValidator {}
    
    onTextEdited: {
        var val = parseFloat(text);
        if (!isNaN(val)) {
            angleRadians = angleManager.fromDisplayUnit(val, true);
        }
    }
}

// 使用示例2: 显示角度值(内部存储为角度)
TextInput {
    property double angleDegrees: 45  // 内部始终以角度存储
    
    text: angleManager.toDisplayUnit(angleDegrees, false).toFixed(2)
    validator: DoubleValidator {}
    
    onTextEdited: {
        var val = parseFloat(text);
        if (!isNaN(val)) {
            angleDegrees = angleManager.fromDisplayUnit(val, false);
        }
    }
}

// 单位标签
Text {
    text: angleManager.useDegrees ? "°" : "rad"
}

4. 高级用法 - 创建可重用组件

// SmartAngleInput.qml
Item {
    property double value: 0
    property bool storeAsRadians: true  // 声明内部存储格式
    
    TextInput {
        id: inputField
        text: angleManager.toDisplayUnit(parent.value, parent.storeAsRadians).toFixed(2)
        validator: DoubleValidator {}
        
        onTextEdited: {
            var val = parseFloat(text);
            if (!isNaN(val)) {
                parent.value = angleManager.fromDisplayUnit(val, parent.storeAsRadians);
            }
        }
    }
    
    Text {
        anchors.left: inputField.right
        anchors.verticalCenter: inputField.verticalCenter
        text: angleManager.useDegrees ? "°" : "rad"
    }
}

实现说明:

  1. 统一管理中心:通过AngleManager单例管理全局显示状态
  2. 双向转换
    • toDisplayUnit(): 将存储值转换为当前显示单位
    • fromDisplayUnit(): 将显示值转换回存储单位
  3. 数据存储分离
    • 通过bool参数isStoredInRadians声明数据存储格式
    • 控件不需要关心当前显示模式
  4. 自动响应
    • 当angleManager.useDegrees改变时,所有绑定toDisplayUnit的控件自动更新
  5. 支持双向绑定
    • 编辑时自动转换回原始存储格式
  6. 组件化
    • 通过SmartAngleInput封装可重用组件

此方案特点:

  • 核心逻辑集中在C++中,性能更优
  • QML层保持简洁
  • 支持任意类型控件(Slider、Text、Dial等)
  • 自动响应单位切换
  • 支持不同的数据存储需求(有些数据存弧度,有些存角度)

当用户切换显示模式时,所有控件会自动根据预设的存储格式进行正确转换,并在界面上更新显示值和单位符号。

posted @ 2025-06-17 15:50  今天昔水  阅读(44)  评论(0)    收藏  举报