如何在 QML spinbox 中使用 float
How to use float in a QML spinbox
我使用 QML Spinbox 但我在其中使用浮点数时遇到问题。
如果我写类似 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);
}
}
}
示例:
DoubleSpinBox{
realValue: 5.0
realStepSize: 0.01
}
这是@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");
}
当前的 SpinBox(控件 2.0 - 2.4)存在限制,因为它只接受 +/- 0x7FFF FFFF
的 to
/from
范围(不能'甚至处理一个无符号整数,顺便说一句)。对于 real
s 这具有(可能是严重的)含义,即对于小数点后需要的每个数字,您都会丢失小数点前的数字。例如,如果您需要 6 位小数精度,则最大可能值为 2147.483647
。到目前为止,这会影响此答案中提出的两个解决方案。
如果您尝试将 to
或 from
设置为超出 int
限制(例如,通过乘以此处建议中的系数),您会得到非常“奇怪的”行为,这可能非常令人费解。如果您尝试直接超出这些限制(例如 to: 0xFFFFFFFF
),则会出现错误。
查看(并投票给 :))QTBUG-67349
我知道这不是问题的答案,但希望它可以像我一样为某人节省几个小时的挫败感。
到目前为止,我能想到的唯一解决方法是简单地使用带有 DoubleValidator 的文本编辑字段。我会试着用一个简化的例子回到这里。
编辑:
Here is my version of a DoubleSpinBox (docs)。代码太长,无法粘贴到这里(恕我直言),我不想维护多个版本。
简而言之,这个想法是完全绕过 SpinBox value
,只使用基本的 Controls.2 SpinBox 作为按钮和整体 look/feel。这意味着它不需要根据主题进行定制 (Fusion/Material/etc)。
不幸的是,这涉及重新实现所有事件处理程序(按钮 presses/repeats、滚轮、文本编辑)和一些其他的诡计。但是(到目前为止)我认为这比在尝试匹配所有不同主题时使用自定义 buttons/etc 从头开始重新实现整个事情要好。
它还添加了一些在标准 SpinBox 中不可用的选项...因为,为什么不呢? :)
我发现上面的代码有两个问题。
显示1.299(句点)这样的数字会出错
DoubleSpinBox 将显示 1.2 而不是 1.3
要修复它,你应该写
值 = Math.round(preview.value * 因子)
在 DoubleSpinBox.qml 函数中设置值(预览)
这一行我们覆盖了绑定
doublespinbox.value = Number.fromLocaleString(语言环境,文本)
因为我们有
“属性 别名值:valuePreview.value”
并且可能 'value' 会在代码中绑定一些东西
所以你不能这样做,完全不够写这个:
function(text, locale) {
return Number.fromLocaleString(locale, text) * factor
}
我想我们也可以删除这一行
preview.value = 值/系数
在函数 setValue(预览)中
我使用 QML Spinbox 但我在其中使用浮点数时遇到问题。
如果我写类似 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);
}
}
}
示例:
DoubleSpinBox{
realValue: 5.0
realStepSize: 0.01
}
这是@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");
}
当前的 SpinBox(控件 2.0 - 2.4)存在限制,因为它只接受 +/- 0x7FFF FFFF
的 to
/from
范围(不能'甚至处理一个无符号整数,顺便说一句)。对于 real
s 这具有(可能是严重的)含义,即对于小数点后需要的每个数字,您都会丢失小数点前的数字。例如,如果您需要 6 位小数精度,则最大可能值为 2147.483647
。到目前为止,这会影响此答案中提出的两个解决方案。
如果您尝试将 to
或 from
设置为超出 int
限制(例如,通过乘以此处建议中的系数),您会得到非常“奇怪的”行为,这可能非常令人费解。如果您尝试直接超出这些限制(例如 to: 0xFFFFFFFF
),则会出现错误。
查看(并投票给 :))QTBUG-67349
我知道这不是问题的答案,但希望它可以像我一样为某人节省几个小时的挫败感。
到目前为止,我能想到的唯一解决方法是简单地使用带有 DoubleValidator 的文本编辑字段。我会试着用一个简化的例子回到这里。
编辑:
Here is my version of a DoubleSpinBox (docs)。代码太长,无法粘贴到这里(恕我直言),我不想维护多个版本。
简而言之,这个想法是完全绕过 SpinBox value
,只使用基本的 Controls.2 SpinBox 作为按钮和整体 look/feel。这意味着它不需要根据主题进行定制 (Fusion/Material/etc)。
不幸的是,这涉及重新实现所有事件处理程序(按钮 presses/repeats、滚轮、文本编辑)和一些其他的诡计。但是(到目前为止)我认为这比在尝试匹配所有不同主题时使用自定义 buttons/etc 从头开始重新实现整个事情要好。
它还添加了一些在标准 SpinBox 中不可用的选项...因为,为什么不呢? :)
我发现上面的代码有两个问题。
显示1.299(句点)这样的数字会出错 DoubleSpinBox 将显示 1.2 而不是 1.3 要修复它,你应该写
值 = Math.round(preview.value * 因子)
在 DoubleSpinBox.qml 函数中设置值(预览)
这一行我们覆盖了绑定
doublespinbox.value = Number.fromLocaleString(语言环境,文本)
因为我们有 “属性 别名值:valuePreview.value” 并且可能 'value' 会在代码中绑定一些东西 所以你不能这样做,完全不够写这个:
function(text, locale) {
return Number.fromLocaleString(locale, text) * factor
}
我想我们也可以删除这一行
preview.value = 值/系数
在函数 setValue(预览)中