6.5 KiB
Raw Blame History

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 发现ClampMinClampMax 会同时限制UI和手动输入的范围。
  • 从MyFloat_HasMinMax_ClampAndUI和MyFloat_HasMinMax_ClampAndUI2发现UI的滚动条会取UI的限制和Clamp限制的更窄范围而实际输入值也是会被限制在更窄的范围内。

MinMax2

原理:

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