Qt 如何在QML spinbox中使用浮点

Qt 如何在QML spinbox中使用浮点,qt,qml,qtquick2,qspinbox,Qt,Qml,Qtquick2,Qspinbox,我使用QML,但在其中使用浮点数时遇到问题。 如果我编写类似于value:5.0的内容,它将显示为5,因此将显示为int而不是float 你知道怎么做吗 非常感谢,祝你度过愉快的一天 您可以使用自定义文本创建一个Spinbox DoubleSpinBox.qml import QtQuick 2.0 import QtQuick.Controls 2.1 Item { property int decimals: 2 property real realValue: 0.0

我使用QML,但在其中使用浮点数时遇到问题。 如果我编写类似于
value:5.0
的内容,它将显示为
5
,因此将显示为int而不是float

你知道怎么做吗


非常感谢,祝你度过愉快的一天

您可以使用自定义文本创建一个Spinbox

DoubleSpinBox.qml

import QtQuick 2.0

import QtQuick.Controls 2.1

Item {
    property int decimals: 2
    property real realValue: 0.0
    property real realFrom: 0.0
    property real realTo: 100.0
    property real realStepSize: 1.0

    SpinBox{
        property real factor: Math.pow(10, decimals)
        id: spinbox
        stepSize: realStepSize*factor
        value: realValue*factor
        to : realTo*factor
        from : realFrom*factor
        validator: DoubleValidator {
            bottom: Math.min(spinbox.from, spinbox.to)*spinbox.factor
            top:  Math.max(spinbox.from, spinbox.to)*spinbox.factor
        }

        textFromValue: function(value, locale) {
            return parseFloat(value*1.0/factor).toFixed(decimals);
        }

    }
}
import QtQuick 2.0
import QtQuick.Controls 2.2
import QmlUtils 1.0

Item
{
    id: doublespinbox
    width: 140
    height: 40
    property int decimals: 1
    property alias value: valuePreview.value
    property real from: 0
    property real to: 99
    property real stepSize: 1
    property alias editable: spinbox.editable
    property alias font: spinbox.font

    SpinBox
    {
        id: spinbox
        property bool init: false
        property real factor: Math.pow(10, decimals)

        function setValue(preview)
        {
            init = true
            value = preview.value * factor
            init = false
            preview.value = value / factor
        }

        DoubleValuePreview
        {
            id: valuePreview
            onValuePreview: spinbox.setValue(preview)
        }

        anchors.fill: parent
        editable: true
        stepSize: doublespinbox.stepSize * factor
        to : doublespinbox.to * factor
        from : doublespinbox.from * factor

        onValueChanged:
        {
            if (init)
                return

            valuePreview.setValueDirect(value / factor)
        }

        validator: DoubleValidator
        {
            bottom: Math.min(spinbox.from, spinbox.to)
            top: Math.max(spinbox.from, spinbox.to)
        }

        textFromValue: function(value, locale)
        {
            return Number(value / factor).toLocaleString(locale, 'f', doublespinbox.decimals)
        }

        valueFromText: function(text, locale)
        {
            doublespinbox.value = Number.fromLocaleString(locale, text)
            return doublespinbox.value * factor
        }
    }
}
例如:

DoubleSpinBox{
    realValue: 5.0
    realStepSize: 0.01
}

这是@eyllanesc的固定版本。所有其他缺少的属性必须具有别名。如果你发现错误,请报告我

DoubleSpinBox.qml

import QtQuick 2.0

import QtQuick.Controls 2.1

Item {
    property int decimals: 2
    property real realValue: 0.0
    property real realFrom: 0.0
    property real realTo: 100.0
    property real realStepSize: 1.0

    SpinBox{
        property real factor: Math.pow(10, decimals)
        id: spinbox
        stepSize: realStepSize*factor
        value: realValue*factor
        to : realTo*factor
        from : realFrom*factor
        validator: DoubleValidator {
            bottom: Math.min(spinbox.from, spinbox.to)*spinbox.factor
            top:  Math.max(spinbox.from, spinbox.to)*spinbox.factor
        }

        textFromValue: function(value, locale) {
            return parseFloat(value*1.0/factor).toFixed(decimals);
        }

    }
}
import QtQuick 2.0
import QtQuick.Controls 2.2
import QmlUtils 1.0

Item
{
    id: doublespinbox
    width: 140
    height: 40
    property int decimals: 1
    property alias value: valuePreview.value
    property real from: 0
    property real to: 99
    property real stepSize: 1
    property alias editable: spinbox.editable
    property alias font: spinbox.font

    SpinBox
    {
        id: spinbox
        property bool init: false
        property real factor: Math.pow(10, decimals)

        function setValue(preview)
        {
            init = true
            value = preview.value * factor
            init = false
            preview.value = value / factor
        }

        DoubleValuePreview
        {
            id: valuePreview
            onValuePreview: spinbox.setValue(preview)
        }

        anchors.fill: parent
        editable: true
        stepSize: doublespinbox.stepSize * factor
        to : doublespinbox.to * factor
        from : doublespinbox.from * factor

        onValueChanged:
        {
            if (init)
                return

            valuePreview.setValueDirect(value / factor)
        }

        validator: DoubleValidator
        {
            bottom: Math.min(spinbox.from, spinbox.to)
            top: Math.max(spinbox.from, spinbox.to)
        }

        textFromValue: function(value, locale)
        {
            return Number(value / factor).toLocaleString(locale, 'f', doublespinbox.decimals)
        }

        valueFromText: function(text, locale)
        {
            doublespinbox.value = Number.fromLocaleString(locale, text)
            return doublespinbox.value * factor
        }
    }
}
QmlValuePreview.h

#pragma once

#include <qobject.h>
#include <qqmlengine.h>

class QDoubleValueArg : public QObject
{
    Q_OBJECT
public:
    QDoubleValueArg(double value) : Value(value)
    {
        QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
    }
public:
    Q_PROPERTY(double value MEMBER Value)
public:
    double Value;
};

class QmlDoubleValuePreview : public QObject
{
    Q_OBJECT
public:
    using QObject::QObject;
public:
    Q_PROPERTY(double value READ getValue WRITE setValue NOTIFY valueChanged)
public:
    Q_INVOKABLE void setValueDirect(double value)
    {
        if (m_value == value)
            return;

        m_value = value;
        emit valueChanged();
    }
public:
    inline double getValue() const { return m_value; }
    inline void setValue(double value)
    {
        if (m_value == value)
            return;

        QDoubleValueArg arg(value);
        emit valuePreview(&arg);
        if (m_value == arg.Value)
            return;

        m_value = arg.Value;
        emit valueChanged();
    }
signals:
    void valueChanged();
    void valuePreview(QDoubleValueArg *preview);
private:
    double m_value = 0;
};
#pragma一次
#包括
#包括
QDoubleValueArg类:公共QObject
{
Q_对象
公众:
QDoubleValueArg(双值):值(值)
{
QQmlEngine::setObjectOwnership(这是QQmlEngine::CppOwnership);
}
公众:
Q_属性(双值成员值)
公众:
双重价值;
};
类QmlDoubleValuePreview:公共QObject
{
Q_对象
公众:
使用QObject::QObject;
公众:
Q_属性(双值读取getValue写入setValue NOTIFY valueChanged)
公众:
Q_可调用的void setValueDirect(双值)
{
如果(m_值==值)
返回;
m_值=值;
emit valueChanged();
}
公众:
内联双getValue()常量{返回m_值;}
内联无效设置值(双值)
{
如果(m_值==值)
返回;
QDoubleValueArg(值);
发出值预览(&arg);
如果(m_值==参数值)
返回;
m_值=参数值;
emit valueChanged();
}
信号:
void valueChanged();
作废值预览(QDoubleValueArg*预览);
私人:
双m_值=0;
};
注册地址:

#define URI "QmlUtils"
#define VERSION_MAJOR 1
#define VERSION_MINOR 0

void registerTypes()
{
    qRegisterMetaType<QDoubleValueArg *>("QDoubleValueArg *");
    qmlRegisterType<QmlDoubleValuePreview>(URI, VERSION_MAJOR, VERSION_MINOR, "DoubleValuePreview");
}
#定义URI“qmultils”
#定义主要版本1
#定义版本0
无效注册表类型()
{
qRegisterMetaType(“QDoubleValueArg*”);
qmlRegisterType(URI,主要版本,次要版本,“DoubleValuePreview”);
}

当前SpinBox(控件2.0-2.4)有一个限制,它只接受+/-
0x7FFF FFFF
范围内的
/
(顺便说一句,它甚至不能处理无符号整数)。对于
real
s,这意味着(可能是严重的)小数点后所需的每一位数字,都会丢失小数点前的一位数字。例如,如果需要6位十进制精度,则最大可能值为
2147.483647
。到目前为止,这影响了本答案中提出的两种解决方案

如果您试图将
设置为
设置为超出这些
int
限制(例如,通过乘以此处建议中的系数),您将得到非常“奇怪”的行为,这可能会非常令人困惑。如果您试图直接超出这些限制(例如,
到:0xFFFFFFFF
),则会出现错误

见(并投票支持:)

我意识到这并不是问题的答案,但希望它能像我一样让人少受几个小时的挫折

到目前为止,我能想到的唯一解决办法是简单地使用文本编辑字段和双重验证程序。我将尝试在这里返回一个简化的示例

编辑:

()。代码太长,无法粘贴到这里(IMHO),我不想维护多个版本

简单地说,我们的想法是完全绕过SpinBox
,只使用基本控件。2 SpinBox用于按钮和整体外观。这意味着它不需要根据主题(融合/材质等)进行定制

不幸的是,这涉及到重新实现所有事件处理程序(按钮按下/重复、滚轮滚动、文本编辑)和一些其他诡计。但是(到目前为止),我认为这比用自定义按钮等从头开始重新实现整个过程要好得多,同时尝试匹配所有不同的主题

它还添加了一些在标准SpinBox中不可用的选项。。。因为,为什么不呢?:)


我在上面的代码中看到两个问题

  • 如果显示像1.299(句点)这样的数字,则会出现错误 DoubleSpinBox将显示1.2而不是1.3 为了解决这个问题,你应该写

    value=数学圆(preview.value*因子)

  • 在DoubleSpinBox.qml函数中设置值(预览)

  • 在这一行中,我们有覆盖绑定

    doublespinbox.value=Number.fromLocaleString(区域设置,文本)

  • 因为我们有 “属性别名值:valuePreview.value” “value”可能会绑定代码中的某些对象 因此,你不能这样做,也不能完全写下:

    function(text, locale) {
            return Number.fromLocaleString(locale, text) * factor
    }
    
  • 我想我们也可以去掉这条线

    preview.value=值/系数


  • 在函数setValue(预览)

    中,它就在您链接的文档中:谢谢!但是我想知道是否没有简单的方法可以做到这一点,因为我找不到doublespinbox或类似的东西。doublespinbox的建议:非常感谢,这很简单也很好!)基本上与GrecKo链接的第二个示例相同,只是不太好,因为您忘记了许多部分:
    valueFromText
    ,因此有人可以输入文本,并对其进行验证。你没有办法在隐藏值的同时读出它(我无法找到任何理由)将
    SpinBox
    封装在
    项中。我看不出你如何将当前值写回你的
    项目
    。我建议使用@GrecKo已经发布的链接的第二个示例。再一次:@derM这不是同一个例子,如果你测试代码,你会发现你得到的不是5.0,而是5,把它放在一个项目中以隐藏属性因子。我测试了代码,它工作得很好。实际上,它不是真正的浮点Spinbox,而是一个固定点,通过将其内部存储为
    int
    可以适当地处理固定点。唯一可以改进的是一种方法,最初设置一个
    realValue
    ——但这需要一个更复杂的双绑定机制,这将打破examp的范围