6.5 KiB
6.5 KiB
UIMin
- 功能描述: 指定数字输入框上滚动条拖动的最小范围值
- 使用位置: UPROPERTY
- 引擎模块: Numeric Property
- 元数据类型: float/int
- 限制类型: float,int32
- 关联项: UIMax, ClampMin, ClampMax
- 常用程度: ★★★★★
UIMin-UIMax和ClampMin-ClampMax的区别是,UI系列阻止用户在拖动鼠标的时候把值超过某个范围,但是用户依然可以手动输入超过这个范围的值。而Clamp系列是实际的值的范围限制,用户拖动或者手动输入值都不允许超过这个范围。
这两个限制都无法限制蓝图下直接修改值。
测试代码:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest)
float MyFloat_NoMinMax = 100;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (UIMin = "0", UIMax = "100"))
float MyFloat_HasMinMax_UI = 100;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (ClampMin = "0", ClampMax = "100"))
float MyFloat_HasMinMax_Clamp = 100;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (ClampMin = "0", ClampMax = "100",UIMin = "20", UIMax = "50"))
float MyFloat_HasMinMax_ClampAndUI = 100;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (ClampMin = "20", ClampMax = "50",UIMin = "0", UIMax = "100"))
float MyFloat_HasMinMax_ClampAndUI2= 100;
测试效果:
- 从MyFloat_HasMinMax_UI发现,UIMin, UIMax限制数字输入框滚动条的范围,但依然可以手动输入超过的值999
- 从MyFloat_HasMinMax_Clamp 发现,ClampMin,ClampMax 会同时限制UI和手动输入的范围。
- 从MyFloat_HasMinMax_ClampAndUI和MyFloat_HasMinMax_ClampAndUI2发现,UI的滚动条会取UI的限制和Clamp限制的更窄范围,而实际输入值也是会被限制在更窄的范围内。
原理:
TNumericPropertyParams在构造的时候就会取得一些meta来初始化这些变量。否则就会成为默认值。
数值类型有实际的最小最大值(MinValue-MaxValue),是由ClampMin和ClampMax提供的。也有UI上的最小最大值(MinSliderValue-MaxSliderValue),是由Max(UImin,ClampMin)和Min(UIMax,ClampMax)提供的,即取最小的范围来保障合法输入。
template<typename NumericType>
struct TNumericPropertyParams
{
if (MetaDataGetter.IsBound())
{
UIMinString = MetaDataGetter.Execute("UIMin");
UIMaxString = MetaDataGetter.Execute("UIMax");
SliderExponentString = MetaDataGetter.Execute("SliderExponent");
LinearDeltaSensitivityString = MetaDataGetter.Execute("LinearDeltaSensitivity");
DeltaString = MetaDataGetter.Execute("Delta");
ClampMinString = MetaDataGetter.Execute("ClampMin");
ClampMaxString = MetaDataGetter.Execute("ClampMax");
ForcedUnits = MetaDataGetter.Execute("ForceUnits");
WheelStepString = MetaDataGetter.Execute("WheelStep");
}
TOptional<NumericType> MinValue;
TOptional<NumericType> MaxValue;
TOptional<NumericType> MinSliderValue;
TOptional<NumericType> MaxSliderValue;
NumericType SliderExponent;
NumericType Delta;
int32 LinearDeltaSensitivity;
TOptional<NumericType> WheelStep;
}
//最终这些值会传输给
SAssignNew(SpinBox, SSpinBox<NumericType>)
.Style(InArgs._SpinBoxStyle)
.Font(InArgs._Font.IsSet() ? InArgs._Font : InArgs._EditableTextBoxStyle->TextStyle.Font)
.Value(this, &SNumericEntryBox<NumericType>::OnGetValueForSpinBox)
.Delta(InArgs._Delta)
.ShiftMultiplier(InArgs._ShiftMultiplier)
.CtrlMultiplier(InArgs._CtrlMultiplier)
.LinearDeltaSensitivity(InArgs._LinearDeltaSensitivity)
.SupportDynamicSliderMaxValue(InArgs._SupportDynamicSliderMaxValue)
.SupportDynamicSliderMinValue(InArgs._SupportDynamicSliderMinValue)
.OnDynamicSliderMaxValueChanged(InArgs._OnDynamicSliderMaxValueChanged)
.OnDynamicSliderMinValueChanged(InArgs._OnDynamicSliderMinValueChanged)
.OnValueChanged(OnValueChanged)
.OnValueCommitted(OnValueCommitted)
.MinFractionalDigits(MinFractionalDigits)
.MaxFractionalDigits(MaxFractionalDigits)
.MinSliderValue(InArgs._MinSliderValue)
.MaxSliderValue(InArgs._MaxSliderValue)
.MaxValue(InArgs._MaxValue)
.MinValue(InArgs._MinValue)
.SliderExponent(InArgs._SliderExponent)
.SliderExponentNeutralValue(InArgs._SliderExponentNeutralValue)
.EnableWheel(InArgs._AllowWheel)
.BroadcastValueChangesPerKey(InArgs._BroadcastValueChangesPerKey)
.WheelStep(InArgs._WheelStep)
.OnBeginSliderMovement(InArgs._OnBeginSliderMovement)
.OnEndSliderMovement(InArgs._OnEndSliderMovement)
.MinDesiredWidth(InArgs._MinDesiredValueWidth)
.TypeInterface(Interface)
.ToolTipText(this, &SNumericEntryBox<NumericType>::GetValueAsText);
//最后
void SSpinBox<NumericType>::CommitValue(NumericType NewValue, double NewSpinValue, ECommitMethod CommitMethod, ETextCommit::Type OriginalCommitInfo)
{
if (CommitMethod == CommittedViaSpin || CommitMethod == CommittedViaArrowKey)
{
const NumericType LocalMinSliderValue = GetMinSliderValue();
const NumericType LocalMaxSliderValue = GetMaxSliderValue();
NewValue = FMath::Clamp<NumericType>(NewValue, LocalMinSliderValue, LocalMaxSliderValue);
NewSpinValue = FMath::Clamp<double>(NewSpinValue, (double)LocalMinSliderValue, (double)LocalMaxSliderValue);
}
{
const NumericType LocalMinValue = GetMinValue();
const NumericType LocalMaxValue = GetMaxValue();
NewValue = FMath::Clamp<NumericType>(NewValue, LocalMinValue, LocalMaxValue);
NewSpinValue = FMath::Clamp<double>(NewSpinValue, (double)LocalMinValue, (double)LocalMaxValue);
}
// Update the internal value, this needs to be done before rounding.
InternalValue = NewSpinValue;
const bool bAlwaysUsesDeltaSnap = GetAlwaysUsesDeltaSnap();
// If needed, round this value to the delta. Internally the value is not held to the Delta but externally it appears to be.
if (CommitMethod == CommittedViaSpin || CommitMethod == CommittedViaArrowKey || bAlwaysUsesDeltaSnap)
{
NumericType CurrentDelta = Delta.Get();
if (CurrentDelta != NumericType())
{
NewValue = FMath::GridSnap<NumericType>(NewValue, CurrentDelta); // snap numeric point value to nearest Delta
}
}
// Update the max slider value based on the current value if we're in dynamic mode
if (SupportDynamicSliderMaxValue.Get() && ValueAttribute.Get() > GetMaxSliderValue())
{
ApplySliderMaxValueChanged(float(ValueAttribute.Get() - GetMaxSliderValue()), true);
}
else if (SupportDynamicSliderMinValue.Get() && ValueAttribute.Get() < GetMinSliderValue())
{
ApplySliderMinValueChanged(float(ValueAttribute.Get() - GetMinSliderValue()), true);
}
}