3

我使用 QML Spinbox,但我无法在其中使用浮点数。如果我写类似value: 5.0的内容,它将显示为5,因此显示为 int 而不是 float。

你知道如何进行吗?

非常感谢,祝您有美好的一天!

4

4 回答 4

8

您可以使用自定义文本创建 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);
        }

    }
}

例子:

DoubleSpinBox{
    realValue: 5.0
    realStepSize: 0.01
}

在此处输入图像描述

于 2017-04-14T08:08:19.517 回答
7

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

如果您尝试设置tofrom超出这些int限制(例如,通过乘以此处建议中的因子),您将获得非常“奇怪”的行为,这可能会非常令人费解。如果您尝试直接超过这些限制(例如to: 0xFFFFFFFF),则会出现错误。

请参阅(并投票给:))QTBUG-67349

我意识到这不是问题的答案,但希望它可以像我一样为某人节省几个小时的挫败感。

到目前为止,我能想到的唯一解决方法是简单地使用带有 DoubleValidator 的文本编辑字段。我将尝试用一个简化的例子回到这里。

编辑:

这是我的 DoubleSpinBox 版本文档)。代码太长,无法在此处粘贴(恕我直言),我宁愿不维护多个版本。

简而言之,这个想法是完全绕过 SpinBox value,只使用基本的 Controls.2 SpinBox 作为按钮和整体外观/感觉。这意味着它不需要为每个主题(Fusion/Material/etc)进行定制。

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

它还添加了一些标准 SpinBox 中没有的选项......因为,为什么不呢?:)

默认主题 融合主题 材质主题

于 2018-07-22T20:07:38.097 回答
2

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

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

注册:

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

void registerTypes()
{
    qRegisterMetaType<QDoubleValueArg *>("QDoubleValueArg *");
    qmlRegisterType<QmlDoubleValuePreview>(URI, VERSION_MAJOR, VERSION_MINOR, "DoubleValuePreview");
}
于 2017-12-06T00:35:50.260 回答
0

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

  1. 如果显示像 1.299(句点)这样的数字,您将有错误 DoubleSpinBox 将显示 1.2 而不是 1.3 要修复它,您应该编写

    value = Math.round(preview.value * 因子)

在 DoubleSpinBox.qml 函数 setValue(preview)

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

    doublespinbox.value = Number.fromLocaleString(locale, text)

因为我们有“属性别名值:valuePreview.value”并且可能“值”会在代码中绑定一些所以你不能这样做,完全可以写这个:

function(text, locale) {
        return Number.fromLocaleString(locale, text) * factor
}
  1. 我想我们也可以删除这条线

    preview.value = 值/因子

在函数 setValue(preview)

于 2021-01-12T11:44:52.710 回答