问题
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 real
s 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