How does one make a text box to only take numbers

Hello, I’ m trying to set a text box to only take numbers. This is so I can use the player input to set a int? Does anyone have any clue on how to this, or how to make the spin box round up to the nearest whole number? Thank you for any response on the matter.

You want to perform this operation before any other bindings to OnTextChanged or OnValueChanged because you want to validate that the input is a different, valid integer before other events are called; so you can’t just bind your method to OnTextChanged or OnValueChanged as you would otherwise.

Unfortunately, you can’t directly override the HandleOnTextChanged implementation because it’s protected (unless you want to rewrite engine source), but you can override RebuildWidget. You can create your own method to handle text changes, and then tie that method back into the native HandleOnTextChanged.

//MyIntegerEditableText.h

#include "Runtime/UMG/Public/UMG.h"
#include "Runtime/UMG/Public/Components/EditableText.h"

#include "MyIntegerEditableText.generated.h"
    
UCLASS(Blueprintable, BlueprintType)
class MYGAME_API UMyIntegerEditableText : public UEditableText
{
    GENERATED_BODY()

protected:

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Data")
    int32 IntegerValue;

public:

    UMyIntegerEditableText();

    //~ Begin UWidget Interface
    virtual TSharedRef<SWidget> RebuildWidget() override;
    // End of UWidget

    UFUNCTION(BlueprintCallable, Category = "User Input")
    void MyHandleOnTextChanged(const FText& InText);

    UFUNCTION(BlueprintCallable, Category = "User Input")
    bool ValidateIntegerValue(FText& InText);

    UFUNCTION(BlueprintCallable, Category = "User Input")
    int32 GetIntFromFloat(const float& FloatValue);

};
    
//MyIntegerEditableText.cpp

#include "MyGame.h"

#include "MyIntegerEditableText.h"
    
UMyIntegerEditableText::UMyIntegerEditableText()
    :
    UEditableText(),
    //set your default value to whatever you like
    IntegerValue(0)
{
    //update the default Text value to reflect your integer value
    Text = FText::AsNumber(IntegerValue);

}

TSharedRef<SWidget> UMyIntegerEditableText::RebuildWidget()
{
    //this is a duplication of the UEditableText RebuildWidget method, but
	//with our MyHandleOnTextChanged method bound to OnValueChanged
    MyEditableText = SNew(SEditableText)
        .Style(&WidgetStyle)
        .MinDesiredWidth(MinimumDesiredWidth)
        .IsCaretMovedWhenGainFocus(IsCaretMovedWhenGainFocus)
        .SelectAllTextWhenFocused(SelectAllTextWhenFocused)
        .RevertTextOnEscape(RevertTextOnEscape)
        .ClearKeyboardFocusOnCommit(ClearKeyboardFocusOnCommit)
        .SelectAllTextOnCommit(SelectAllTextOnCommit)
        //here we replace HandleOnValueChanged with our MyHandleOnTextChanged method
        .OnTextChanged(BIND_UOBJECT_DELEGATE(FOnTextChanged, MyHandleOnTextChanged))//<-- 
        .OnTextCommitted(BIND_UOBJECT_DELEGATE(FOnTextCommitted, HandleOnTextCommitted))
        .VirtualKeyboardType(EVirtualKeyboardType::AsKeyboardType(KeyboardType.GetValue()));

    return BuildDesignTimeWidget(MyEditableText.ToSharedRef());

}

void UMyIntegerEditableText::MyHandleOnTextChanged(const FText& InText)
{
	//the native HandleOnTextChanged takes a constant, but we 
	//may be changing this value so we'll convert it to something editable
	FText NewText(InText);
	//We use ValidateIntegerValue to determine if the value has actually changed and is a valid integer
    if (ValidateIntegerValue(NewText)) {
        //important to tie back into the OnTextChanged event with the validated value
        HandleOnTextChanged(NewText);
        //natively HandleOnTextChanged just broadcasts the OnTextChanged event; we could just
		//do that here, but I always prefer to go back to the native method if possible so
		//any future engine updates will seemlessly integrate (hopefully)

    }

}

//this verifies the passed in text can be interpreted as an integer and cleans the value
bool UMyIntegerEditableText::ValidateIntegerValue(FText& InText) {
    //checking to make sure the value is different prevents an infinite loop via SetText
	if (!InText.EqualTo(Text)) {
		if (InText.IsNumeric()) {
			//convert the value to a float so we can round properly if the user entered a decimal
			float FloatValue = FCString::Atof(*InText.ToString());
			//set our integer value
			IntegerValue = GetIntFromFloat(FloatValue);
			//you can use FMath::CeilToInt or FMath::Floor if you prefer
			//IntegerValue = FMath::CeilToInt(FloatValue);
			//IntegerValue = FMath::Floor(FloatValue);

			//then set our new integer back to the text value
			InText = FText::AsNumber(IntegerValue);

			//then we have to set the value back to the SEditableText object
			SetText(InText);
			return true;

		}
	else if (InText.IsEmpty()) {
		//handle the special case of deleting the last digit.
		//here I just set everything to 0; you could set it to a stored default, or whatever
		//I find this to be nicer behavior than refusing to delete the last digit;
		//unfortunately, if the last digit is 0 it still appears to be non-responsive
		IntegerValue = 0;
		SetText(FText::AsNumber(IntegerValue));
		return true;
	}
	else {
			//if we haven't been given a good integer value, set the text value back to our current
			//stored integer value; you can, of course, modify this behavior if you desire
			SetText(FText::AsNumber(IntegerValue));

		}

	}
    return false;

}

//converts referenced float to integer value with proper rounding rules
int32 UMyIntegerEditableText::GetIntFromFloat(const float& FloatValue) {
    if (FloatValue >= 0.0f) {
        return (int)(FloatValue + 0.5f);

    }
    return (int)(FloatValue - 0.5f);

}

A spinbox is very similar, but involves OnValueChanged instead of OnTextChanged.

//MyIntegerSpinBox.h
    
#include "Runtime/UMG/Public/UMG.h"
#include "Runtime/UMG/Public/Components/SpinBox.h"
    
#include "MyIntegerSpinBox.generated.h"
    
UCLASS(Blueprintable, BlueprintType)
class MYGAME_API UMyIntegerSpinBox : public USpinBox
{
	GENERATED_BODY()

protected:

	//within the spin box this is an optional value since we don't need it to restore
	//non-numeric input; if you choose you can just use the native float Value
	//and convert it to int when required
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Data")
	int32 IntegerValue;

	//this is an entirely optional value that your designers can use to
	//create alternative displays of the current, validated IntegerValue
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Data")
	FText DisplayValue;

public:

	UMyIntegerSpinBox();

	//~ Begin UWidget Interface
	virtual TSharedRef<SWidget> RebuildWidget() override;
	// End of UWidget

	UFUNCTION(BlueprintCallable, Category = "User Input")
	void MyHandleOnValueChanged(float InValue);

	UFUNCTION(BlueprintCallable, Category = "User Input")
	bool ValidateIntegerValue(float& InValue);

	UFUNCTION(BlueprintCallable, Category = "User Input")
	int32 GetIntFromFloat(const float& FloatValue);

	UFUNCTION(BlueprintCallable, Category = "User Input")
	void UpdateDisplayValue();

};
    
//MyIntegerSpinBox.cpp

#include "MyGame.h"

#include "MyIntegerSpinBox.h"
    
UMyIntegerSpinBox::UMyIntegerSpinBox()
	:
	USpinBox(),
	IntegerValue(GetIntFromFloat(Value)),
	DisplayValue(FText::AsNumber(IntegerValue))
{}

TSharedRef<SWidget> UMyIntegerSpinBox::RebuildWidget()
{
	MySpinBox = SNew(SSpinBox<float>)
		.Style(&WidgetStyle)
		.Font(Font)
		.ClearKeyboardFocusOnCommit(ClearKeyboardFocusOnCommit)
		.SelectAllTextOnCommit(SelectAllTextOnCommit)
		.OnValueChanged(BIND_UOBJECT_DELEGATE(FOnFloatValueChanged, MyHandleOnValueChanged))
		.OnValueCommitted(BIND_UOBJECT_DELEGATE(FOnFloatValueCommitted, HandleOnValueCommitted))
		.OnBeginSliderMovement(BIND_UOBJECT_DELEGATE(FSimpleDelegate, HandleOnBeginSliderMovement))
		.OnEndSliderMovement(BIND_UOBJECT_DELEGATE(FOnFloatValueChanged, HandleOnEndSliderMovement))
		;
	return BuildDesignTimeWidget(MySpinBox.ToSharedRef());

}

void UMyIntegerSpinBox::MyHandleOnValueChanged(float InValue) {
	if (ValidateIntegerValue(InValue)) {
		HandleOnValueChanged(InValue);

	}

}

bool UMyIntegerSpinBox::ValidateIntegerValue(float& InValue) {
	//checking to make sure the value is different prevents an infinite loop via SetValue
	if (Value != InValue) {
		//round up or down, depending on where we're going
		InValue = Value < InValue ? FMath::CeilToFloat(InValue) : FMath::FloorToFloat(InValue);

		//then we have to set the value back to the spinner
		SetValue(InValue);

		//we can store the integer value if desired
		IntegerValue = GetIntFromFloat(InValue);
		//you can use CeilToFlot or Floor if you prefer
		//IntegerValue = FMath::CeilToFloat(InValue);
		//IntegerValue = FMath::Floor(InValue);

		//finally, update the optional FText display value
		UpdateDisplayValue();
		return true;

	}
	return false;

}

int32 UMyIntegerSpinBox::GetIntFromFloat(const float& FloatValue) {
	if (FloatValue >= 0.0f) {
		return (int)(FloatValue + 0.5f);

	}
	return (int)(FloatValue - 0.5f);

}

void UMyIntegerSpinBox::UpdateDisplayValue() {
	DisplayValue = FText::AsNumber(IntegerValue);

}

If you are not set on an editable text box, you can look into SNumericEntryBox https://api.unrealengine.com/INT/API/Runtime/Slate/SNumericEntryBox/index.html