How to use float in a QML spinbox

旧城冷巷雨未停 提交于 2019-12-11 02:03:06

问题


I use a QML Spinbox but I have trouble to use floats in it. If I write something like value: 5.0 , it will be displayed as 5 , so as an int instead of a float.

Do you have any idea of how to proceed ?

Thanks a lot and have a good day !


回答1:


You can create a Spinbox with custom texts

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);
        }

    }
}

Example:

DoubleSpinBox{
    realValue: 5.0
    realStepSize: 0.01
}




回答2:


There is a limit in the current SpinBox (Controls 2.0 - 2.4) in that it only accepts a to/from range of +/- 0x7FFF FFFF (which can't even handle an unsigned int, BTW). For reals this has the (possibly serious) implication that for every digit you need after the decimal point, you lose a digit before the decimal. For example if you need 6 digit decimal precision, your maximum possible value is 2147.483647. This affects both the proposed solutions in this answer so far.

If you try to set the to or from beyond those int limits (eg. by multiplying by the factor like in the suggestions here), you will get very "strange" behavior which can be quite baffling. If you try to exceed those limits directly (eg. to: 0xFFFFFFFF) you get an error.

See (and vote for :) ) QTBUG-67349

I realize this is not an answer to the question, but hopefully it can save someone some hours of frustration like I had.

The only workaround I can come up with so far is to simply use a text edit field with a DoubleValidator. I will try to come back here with a simplified example.

EDIT:

Here is my version of a DoubleSpinBox. The code is too long to paste here (IMHO) and I'd rather not maintain multiple versions.

Briefly, the idea is to bypass the SpinBox value entirely and just use the base Controls.2 SpinBox for the buttons and overall look/feel. This means it doesn't need to be customized per theme (Fusion/Material/etc).

Unfortunately this involves re-implementing all the event handlers (button presses/repeats, wheel scroll, text edit), and a bit of other chicanery. But (so far) I think it beats re-implementing the whole thing from scratch with custom buttons/etc while trying to match all the different themes.

It also adds a few options not available in the standard SpinBox... because, why not? :)




回答3:


This is a @eyllanesc fixed version. All other missing properties must be aliased. Please report me bugs, if you find.

DoubleSpinBox.qml

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;
};

Registered with:

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

void registerTypes()
{
    qRegisterMetaType<QDoubleValueArg *>("QDoubleValueArg *");
    qmlRegisterType<QmlDoubleValuePreview>(URI, VERSION_MAJOR, VERSION_MINOR, "DoubleValuePreview");
}


来源:https://stackoverflow.com/questions/43406830/how-to-use-float-in-a-qml-spinbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!