i am still new to c# i am trying to write a code that would check my if condition if 4 conditions are met then something happens.
Here is my codes:enter code here
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NameTrans : MonoBehaviour {
public string thename;
public GameObject inputField;
public GameObject textDisplay;
public GameObject textDisplay2;
// Use this for initialization
public void Showname () {
thename = inputField.GetComponent<Text>().text;
if (thename.ToUpper().Contains("Man".ToUpper()) || thename.ToUpper().Contains("Dog".ToUpper()))
{
textDisplay2.SetActive(false);
textDisplay.SetActive(true);
textDisplay.GetComponent<Text>().text = "WOrks" ;
}
else
{
textDisplay.SetActive(false);
textDisplay2.SetActive(true);
textDisplay2.GetComponent<Text>().text = "Not WORK" ;
}
}
}
In case only one of 4 conditions needs to be met, you are already doing the right thing. You just need to add the missing two condidions.
if((thename.ToUpper().Contains("Man".ToUpper())) ||
(thename.ToUpper().Contains("Dog".ToUpper())) ||
(thename.ToUpper().Contains("Cat".ToUpper())) ||
(thename.ToUpper().Contains("Fish".ToUpper())))
{
//do something
}
else
{
//do something else
}
If all 4 conditions need to be met, you need to connect the conditions with "&&" instead of "||".
if((thename.ToUpper().Contains("Man".ToUpper())) &&
(thename.ToUpper().Contains("Dog".ToUpper())) &&
(thename.ToUpper().Contains("Cat".ToUpper())) &&
(thename.ToUpper().Contains("Fish".ToUpper())))
{
//do something
}
else
{
//do something else
}
UPDATE with new info
If you want to check if any 4 of x conditions are true, I would probably do something like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NameTrans : MonoBehaviour {
public string thename;
public GameObject inputField;
public GameObject textDisplay;
public GameObject textDisplay2;
private string[] conditions;
private int counter;
// Use this for initialization
public void Showname () {
thename = inputField.GetComponent<Text>().text;
conditions = {"Man", "Dog", "Cat", "Fish", "Goat",
"Frog", "Bird", "Alligator"};
counter = 0;
foreach(string cond in conditions)
{
if (thename.ToUpper().Contains(cond.ToUpper())
{
counter += 1;
if (counter >= 4)
{
break;
}
}
}
if (counter >= 4)
{
textDisplay2.SetActive(false);
textDisplay.SetActive(true);
textDisplay.GetComponent<Text>().text = "WOrks" ;
}
else
{
textDisplay.SetActive(false);
textDisplay2.SetActive(true);
textDisplay2.GetComponent<Text>().text = "Not WORK" ;
}
}
}
Thanks alot `enter code here Paddex for the answer.
For those using unity Add New string[]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NewBehaviourScript : MonoBehaviour {
public string thename;
public GameObject inputField;
public GameObject textDisplay;
public GameObject textDisplay2;
private string[] conditions;
private int counter;
// Use this for initialization
public void Showname()
{
thename = inputField.GetComponent<Text>().text;
conditions = new string[] {
"Man", "Dog", "Cat", "Fish", "Goat",
"Frog", "Bird", "Alligator"};
counter = 0;
foreach (string cond in conditions)
{
if (thename.ToUpper().Contains(cond.ToUpper()))
{
counter += 1;
if (counter >= 4)
{
break;
}
}
}
if (counter >= 4)
{
textDisplay2.SetActive(false);
textDisplay.SetActive(true);
textDisplay.GetComponent<Text>().text = "WOrks";
}
else
{
textDisplay.SetActive(false);
textDisplay2.SetActive(true);
textDisplay2.GetComponent<Text>().text = "Not WORK";
}
}
}
Related
this is my first post here. I'm doing pong game in Unity, and i have problem finding instantinated gameobject ball, which i want to gets it's position to program AI controlling second Paddle. Here how it looks like:
GameController.cs:
public class GameController : MonoBehaviour
{
public GameObject ballPrefab;
public Text score1Text;
public Text score2Text;
public float scoreCoordinates = 3.4f;
private Ball2 currentBall;
private int score1 = 0;
private int score2 = 0;
// Start is called before the first frame update
void Start()
{
SpawnBall();
}
void SpawnBall()
{
GameObject ballInstance = Instantiate(ballPrefab, transform);
currentBall = ballInstance.GetComponent<Ball2>();
currentBall.transform.position = Vector3.zero;
score1Text.text = score1.ToString();
score2Text.text = score2.ToString();
}
// Update is called once per frame
void Update()
{
if (currentBall != null)
{
if (currentBall.transform.position.x > scoreCoordinates)
{
score1++;
Destroy(currentBall.gameObject);
SpawnBall();
}
if (currentBall.transform.position.x < -scoreCoordinates)
{
score2++;
Destroy(currentBall.gameObject);
SpawnBall();
}
}
}
}
AI.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AI : MonoBehaviour
{
private Rigidbody2D AIrig;
private Ball2 ball;
public float speed = 1f;
// Start is called before the first frame update
void Start()
{
ball = GetComponent<Ball2>();
AIrig = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
ball.transform.position = Vector3.zero;
if (ball.transform.position.y > AIrig.transform.position.y)
{
AIrig.velocity = new Vector2(0, speed);
}
else if (ball.transform.position.y > AIrig.transform.position.y)
{
AIrig.velocity = new Vector2(0, -speed);
}
}
}
Ball2.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball2 : MonoBehaviour
{
public float minXspeed = 0.8f;
public float maxXspeed = 1.2f;
public float minYspeed = 0.8f;
public float maxYspeed = 1.2f;
private Rigidbody2D ballRigidbody;
// Start is called before the first frame update
void Start()
{
ballRigidbody = GetComponent<Rigidbody2D>();
ballRigidbody.velocity = new Vector2(Random.Range(minXspeed, maxXspeed) * (Random.value > 0.5f ? -1 : 1), Random.Range(minYspeed, maxYspeed) * (Random.value > 0.5f ? -1 : 1));
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter2D(Collider2D otherCollider)
{
if (otherCollider.tag == "Limit")
{
if (otherCollider.transform.position.y > transform.position.y && ballRigidbody.velocity.y > 0)
{
ballRigidbody.velocity = new Vector2(ballRigidbody.velocity.x, -ballRigidbody.velocity.y);
}
if (otherCollider.transform.position.y < transform.position.y && ballRigidbody.velocity.y < 0)
{
ballRigidbody.velocity = new Vector2(ballRigidbody.velocity.x, -ballRigidbody.velocity.y);
}
}
else if (otherCollider.tag == "Paddle")
{
if (otherCollider.transform.position.x < transform.position.x && ballRigidbody.velocity.x < 0)
{
ballRigidbody.velocity = new Vector2(-ballRigidbody.velocity.x, ballRigidbody.velocity.y);
}
if (otherCollider.transform.position.x > transform.position.x && ballRigidbody.velocity.x > 0)
{
ballRigidbody.velocity = new Vector2(-ballRigidbody.velocity.x, ballRigidbody.velocity.y);
}
}
}
}
I can't get refference to instantinated object (ball). If anyone could help me i will be grateful.
All right, i get it, here is the solution:
I've modified AI.cs, now it looks like:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AI : MonoBehaviour
{
private Rigidbody2D AIrig;
public GameObject ball;
public float speed = 1f;
// Start is called before the first frame update
void Start()
{
AIrig = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
ball = GameObject.Find("Ball(Clone)");
if (ball.transform.position.y > AIrig.transform.position.y)
{
AIrig.velocity = new Vector2(0, speed);
}
else if (ball.transform.position.y < AIrig.transform.position.y)
{
AIrig.velocity = new Vector2(0, -speed);
}
}
}
I am not exactly clear where are those scripts attached.
So, I don't know if your getComponent will work.
GetComponent will work if you have scripts attached to the same object
Otherwise, you have can consider options like FindObjectOfType(), FindGameObjectsWithTag(string tag), GameObject.Find("object name") and more...
But I think the best way to do it, is if you want one object reference then store the instantiated ball to a public variable, and access it through it.
And if you are instantiating multiple objects, then store them in the public list in GameController. Then in the start function take the reference of the game controller and you will have access to those public variables.
This blog describes how to perform shake to undo, however I'd like to create some kind of base class (in Xamarin forms) that I can reuse this code:
#region respond to shaking (OS3+)
public override bool CanBecomeFirstResponder {
get {
return true;
}
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
this.BecomeFirstResponder();
}
public override void ViewWillDisappear (bool animated)
{
this.ResignFirstResponder();
base.ViewWillDisappear (animated);
}
public override void MotionEnded (UIEventSubtype motion, UIEvent evt)
{
Console.WriteLine("Motion detected");
if (motion == UIEventSubtype.MotionShake)
{
Console.WriteLine("and was a shake");
// Do your application-specific shake response here...
Update();
}
}
#endregion
I'm not sure where to begin... to create a base class that only applies to iOS.
Is there any kind of Dependency injection I can use with XamarinForms for this runtime implementation of a base class for all views?
Explaination
The good news is we can take advantage of the Device Motion NuGet Package in lieu of Custom Renderers!
We can implement the shake functionality in a base NavgiationPage class and use this as our MainPage.
I've also included logic in the App constructor that only implements the ShakeListenerNavigationPage for iOS.
Code
using System;
using System.Diagnostics;
using Xamarin.Forms;
using DeviceMotion.Plugin;
using DeviceMotion.Plugin.Abstractions;
namespace YourNamespace
{
public class App : Application
{
public App()
{
NavigationPage navigationPage;
switch(Device.RuntimePlatform)
{
case Device.iOS:
navigationPage = new ShakeListenerNavigationPage(new MyPage());
break;
default:
navigationPage = new NavigationPage(new MyPage());
break;
}
MainPage = navigationPage;
}
}
public class ShakeListenerNavigationPage : NavigationPage
{
#region Constant Fields
const int _shakeDetectionTimeLapse = 250;
readonly double _shakeThreshold;
#endregion
#region Fields
bool _hasUpdated;
DateTime _lastUpdate;
double _lastX, _lastY, _lastZ;
#endregion
#region Constructors
public ShakeListenerNavigationPage(Page root) : base(root)
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
_shakeThreshold = 20;
break;
default:
_shakeThreshold = 800;
break;
}
CrossDeviceMotion.Current.Start(MotionSensorType.Accelerometer, MotionSensorDelay.Default);
CrossDeviceMotion.Current.SensorValueChanged += HandleSensorValueChanged;
}
#endregion
#region Methods
void HandleSensorValueChanged(object sender, SensorValueChangedEventArgs e)
{
if (e.SensorType == MotionSensorType.Accelerometer)
{
double x = ((MotionVector)e.Value).X;
double y = ((MotionVector)e.Value).Y;
double z = ((MotionVector)e.Value).Z;
var currentTime = DateTime.Now;
if (_hasUpdated == false)
{
_hasUpdated = true;
_lastUpdate = currentTime;
}
else
{
var hasMinimumTimeElapsed = (currentTime - _lastUpdate).TotalMilliseconds > _shakeDetectionTimeLapse;
if (!hasMinimumTimeElapsed)
return;
_lastUpdate = currentTime;
var timeSinceLastShakeInMilliseconds = (currentTime - _lastUpdate).TotalMilliseconds;
var totalMovementDistance = x + y + z - _lastX - _lastY - _lastZ;
var shakeSpeed = Math.Abs(totalMovementDistance) / timeSinceLastShakeInMilliseconds * 10000;
Debug.WriteLine($"Shake Speed: {shakeSpeed}");
if (shakeSpeed > _shakeThreshold)
HandleShake();
}
_lastX = x;
_lastY = y;
_lastZ = z;
}
}
void HandleShake()
{
Device.BeginInvokeOnMainThread(async () => await DisplayAlert("Shake Detected", "You shook your device!", "Ok"));
}
#endregion
}
}
Sample App
Here's a sample Xamarin.Forms app where I implemented this feature!
https://github.com/brminnick/InvestmentDataSampleApp
How would you add a placeholder to an Editor in Xamarin Forms for iOS?
I tried adding through custom renderer as Control.Layer but could not find a property related to it.
Please help.
Try following code:
PCL:
using System;
using Xamarin.Forms;
namespace ABC.CustomViews
{
public class PlaceholderEditor : Editor
{
public static readonly BindableProperty PlaceholderProperty =
BindableProperty.Create<PlaceholderEditor, string>(view => view.Placeholder, String.Empty);
public PlaceholderEditor()
{
}
public string Placeholder
{
get
{
return (string)GetValue(PlaceholderProperty);
}
set
{
SetValue(PlaceholderProperty, value);
}
}
}
}
iOS (CustomeRenderer) :
using UIKit;
using ABC.CustomViews;
using ABC.iOS.CustomRenderer;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace ABC.iOS.CustomRenderer
{
public class PlaceholderEditorRenderer : EditorRenderer
{
private string Placeholder { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
var element = this.Element as PlaceholderEditor;
if (Control != null && element != null)
{
Placeholder = element.Placeholder;
Control.TextColor = UIColor.LightGray;
Control.Text = Placeholder;
Control.ShouldBeginEditing += (UITextView textView) =>
{
if (textView.Text == Placeholder)
{
textView.Text = "";
textView.TextColor = UIColor.Black; // Text Color
}
return true;
};
Control.ShouldEndEditing += (UITextView textView) =>
{
if (textView.Text == "")
{
textView.Text = Placeholder;
textView.TextColor = UIColor.LightGray; // Placeholder Color
}
return true;
};
}
}
}
}
Usage :
_replyEditor = new PlaceholderEditor
{
Placeholder = "Placeholder Text"
};
below is the code for android
using System;
using MyApp;
using MyApp.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CustomEditor), typeof(CustomEditorRenderer))]
namespace MyApp.Droid
{
public class CustomEditorRenderer : EditorRenderer
{
public CustomEditorRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var element = e.NewElement as CustomEditor;
this.Control.Hint = element.Placeholder;
Control.Gravity = Android.Views.GravityFlags.Start;
Control.SetBackgroundColor(global::Android.Graphics.Color.White);
Control.SetPadding(15,15,15,15);
}
}
}
Here is a Xamarin forms version that allows a placehodler to be included in the initializer of the Editor, and also handles consistent behavior if the Text property is set in code (i.e. if Editor.Text="" it will show the placeholder in light gray.
using System;
using Xamarin.Forms;
namespace CrowdWisdom.Controls
{
public class EditorPlaceHolder : Editor
{
String placeHolderText = "";
public EditorPlaceHolder(String placeholder)
{
Text = placeholder;
TextColor = Color.LightGray;
this.Focused += EditorPlaceHolder_Focused;
this.Unfocused += EditorPlaceHolder_Unfocused;
this.placeHolderText = placeholder;
}
private void EditorPlaceHolder_Focused(object sender, FocusEventArgs e) //triggered when the user taps on the Editor to interact with it
{
if (Empty())
{
base.Text = "";
this.TextColor = Color.Black;
}
}
private void EditorPlaceHolder_Unfocused(object sender, FocusEventArgs e) //triggered when the user taps "Done" or outside of the Editor to finish the editing
{
if (Empty()) //if there is text there, leave it, if the user erased everything, put the placeholder Text back and set the TextColor to gray
{
this.Text = placeHolderText;
this.TextColor = Color.LightGray;
}
}
public String PlaceHolderText
{
get
{
return this.placeHolderText;
}
set
{
if (this.Empty())
{
this.Text = value;
this.TextColor = Color.LightGray;
}
this.placeHolderText = value;
}
}
public bool Empty()
{
return (this.Text.Equals("") || this.Text.Equals(this.placeHolderText));
}
public virtual new string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
if (Empty())
{
this.TextColor = Color.LightGray;
base.Text = this.placeHolderText;
}
else
{
this.TextColor = Color.Black;
}
}
}
}
}
Xamarin Forms adding a placeholder to an Editor for Android
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace MyCare.Renderers
{
class PlaceholderEditor : Editor
{
public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create<PlaceholderEditor, string>(view => view.Placeholder, String.Empty);
public PlaceholderEditor()
{
}
public string Placeholder
{
get
{
return (string)GetValue(PlaceholderProperty);
}
set
{
SetValue(PlaceholderProperty, value);
}
}
}
}
//Renderer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using MyCare.Renderers;
using MyCare.Droid.Renderers;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace MyCare.Droid.Renderers
{
class PlaceholderEditorRenderer : EditorRenderer
{
private string Placeholder { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
var element = this.Element as PlaceholderEditor;
if (Control != null && element != null)
{
Placeholder = element.Placeholder;
Control.SetTextColor(Android.Graphics.Color.Black);
Control.SetHintTextColor(Android.Graphics.Color.LightGray);
Control.Hint = element.Placeholder;
Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
}
}
}
}
Inherit from Jay's solution. Here is a usage in XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cstCtrl="clr-namespace:TeamCollaXform.Views"
x:Class="TeamCollaXform.Views.MailComposePage">
...
<cstCtrl:PlaceholderEditor Grid.Row="2" x:Name="txtContent" Text="" HeightRequest="750" Placeholder="Compose..."/>
I have implemented a helper script using a youtube example. But when I use the Resource method in my other scripts the compiler gives an null Reference error. What am I doing wrong.
this is my helper script and how the resources are called.
using UnityEngine;
using System.Collections;
namespace Helper
{
public class Resource
{
public static string AnimatorController = "System/PlayerAnimator";
}
}
The path according to my scene is
Assets/Resources/System/PlayerAnimator.controller
This is how I used in my other scripts to load the resources
private Animator _animator;
private RuntimeAnimatorController _animatorController;
_animatorController = Resources.Load(Resource.AnimatorController) as RuntimeAnimatorController;
_animator.runtimeAnimatorController = _animatorController;
What is the fix for this?
I added both of the scripts. Non didn't work
PlayerCharctor.cs
using UnityEngine; using System.Collections; using Helper;
[RequireComponent(typeof(NetworkView))] [RequireComponent(typeof(CharacterController))] [RequireComponent(typeof(Animator))]
[RequireComponent(typeof(PlayerMotor))] [RequireComponent(typeof(PlayerCamera))]
[AddComponentMenu("Scripts/Player/PlayerCharacter")] public class PlayerCharacter : MonoBehaviour {
#region Variables & Properties (Private)
private CharacterController _controller;
private Animator _animator;
private RuntimeAnimatorController _animatorController;
#endregion
#region Variables & Properties (Public)
public CharacterController Controller
{
get
{
return _controller;
}
}
public Animator Animator
{
get
{
return _animator;
}
}
#endregion
#region Unity Event Funtions
void awake()
{
_animator = GetComponent<Animator>();
_controller = GetComponent<CharacterController>();
}
// Use this for initialization
void Start ()
{
//Ensure networkview Component exists
if (GetComponent<NetworkView>() != null)
{
//Ensure that initialization only executes if this is a valid instance
if (GetComponent<NetworkView>().isMine || Network.peerType == NetworkPeerType.Disconnected)
{
//Load in the AnimatorController at runtime
_animatorController = Resources.Load(Resource.AnimatorController) as RuntimeAnimatorController;
_animator.runtimeAnimatorController = _animatorController;
_controller.center = new Vector3(0f, 1f, 0f);
_controller.height = 1.8f;
}
else
{
enabled = false;
}
}
else
{
Debug.Log("Attach a NetWorkViewComponent!!");
}
}
// Update is called once per frame
void Update ()
{
}
#endregion
#region Methods
#endregion Methods }
AND the Helper script
using UnityEngine;
using System.Collections;
namespace Helper
{
#region Referance Cache
public class PlayerInput
{
public static string Horizontal = "Horizontal";
public static string Vertical = "vertical";
public static string Jump = "Jump";
public static string RightX = "Mouse X";
public static string RightY = "Mouse Y";
}
public class GameTag
{
//System tags
public static string Untagged = "Untagged";
public static string Respawn = "Respawn";
public static string Finish = "Finish";
public static string EditorOnly = "EditorOnly";
public static string MainCamera = "MainCamera";
public static string Player = "Player";
public static string GameController = "GameController";
public static string PlayerCamera = "PlayerCamera";
}
public class Resource
{
public static string AnimatorController= "System/PLController"; //Changed the name of the controller (new one)
}
public static class AnimatorConditions
{
public static string Speed = "Speed";
public static string Direction = "Direction";
public static string Grounded = "Grounded";
public static string AirVelocity = "AirVelocity";
}
#endregion
#region FSM Enumerations (Finite State Machine)
public enum CameraState
{
Normal,
Target
}
public enum SpeedState
{
Walk,
Run,
Sprint
}
#endregion
#region Object Structures
public struct CameraTargetObject
{
private Vector3 position;
private Transform xForm;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
}
}
public Transform XForm
{
get
{
return xForm;
}
set
{
xForm = value;
}
}
public void Init(string camName, Vector3 pos, Transform transform, Transform parent)
{
position = pos;
xForm = transform;
xForm.name = camName;
xForm.parent = parent;
xForm.localPosition = Vector3.zero;
xForm.localPosition = position;
}
}
public struct CameraMountPoint
{
private Vector3 position;
private Transform xForm;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
}
}
public Transform XForm
{
get
{
return xForm;
}
set
{
xForm = value;
}
}
public void Init(string camName, Vector3 pos, Transform transform, Transform parent)
{
position = pos;
xForm = transform;
xForm.name = camName;
xForm.parent = parent;
xForm.localPosition = Vector3.zero;
xForm.localPosition = position;
}
}
#endregion
}
There is no problem in your code of loading assets from Resources. But in fact it may be because of your _animator variable. I am 99% sure that it is null. First get the Animator component like _animator = GetComponent<Animator>(); then assign its RuntimeAnimatorController.
I am creating some forms and I need to create masks and validation for some fields.
Is it implemented in anyway in JavaFX?
My example of the mask.
Using:
<MaskField mask="+7(DDD)DDD-DDDD"/>
<MaskField mask="AA DDD AAA" placeholder="__ ### ___"/>
etc
Restricting input from Richard's fxexperience post:
TextField field = new TextField() {
#Override public void replaceText(int start, int end, String text) {
// If the replaced text would end up being invalid, then simply
// ignore this call!
if (!text.matches("[a-z]")) {
super.replaceText(start, end, text);
}
}
#Override public void replaceSelection(String text) {
if (!text.matches("[a-z]")) {
super.replaceSelection(text);
}
}
};
If you want to create your use a mask and create your own control, take a look at Richard's MoneyField, which also includes a sample project and source. Along the same lines there are controls to restict input to Integers, Doubles or formatted web colors (e.g. #rrggbb) in the fxexperience repository. All of these follow a common theme where they subclass Control, provide some properties to be get and set which define the public interface and then also define a private backing skin which handles rendering of the UI based on the values set through the public interface.
I had the same needs. I created this field, called it SpecialTextField, and pushed into GitHub. Example also there. Hope this help.
NOTE: this only works correctly with JRE 1.8.0_25 or lower. With JRE 1.8.0_48 or 0_51, the caret position is always set to 0 after each character input.
No, this is not implemented in standard JavaFX. You need to use some library or do it yourself.
This is my implementation of static mask for text fields. It works for date, phone and other types of static masks:
/**
* Adds a static mask to the specified text field.
* #param tf the text field.
* #param mask the mask to apply.
* Example of usage: addMask(txtDate, " / / ");
*/
public static void addMask(final TextField tf, final String mask) {
tf.setText(mask);
addTextLimiter(tf, mask.length());
tf.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
String value = stripMask(tf.getText(), mask);
tf.setText(merge(value, mask));
}
});
tf.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(final KeyEvent e) {
int caretPosition = tf.getCaretPosition();
if (caretPosition < mask.length()-1 && mask.charAt(caretPosition) != ' ' && e.getCode() != KeyCode.BACK_SPACE && e.getCode() != KeyCode.LEFT) {
tf.positionCaret(caretPosition + 1);
}
}
});
}
static String merge(final String value, final String mask) {
final StringBuilder sb = new StringBuilder(mask);
int k = 0;
for (int i = 0; i < mask.length(); i++) {
if (mask.charAt(i) == ' ' && k < value.length()) {
sb.setCharAt(i, value.charAt(k));
k++;
}
}
return sb.toString();
}
static String stripMask(String text, final String mask) {
final Set<String> maskChars = new HashSet<>();
for (int i = 0; i < mask.length(); i++) {
char c = mask.charAt(i);
if (c != ' ') {
maskChars.add(String.valueOf(c));
}
}
for (String c : maskChars) {
text = text.replace(c, "");
}
return text;
}
public static void addTextLimiter(final TextField tf, final int maxLength) {
tf.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) {
if (tf.getText().length() > maxLength) {
String s = tf.getText().substring(0, maxLength);
tf.setText(s);
}
}
});
}
See also:
JavaFX 2.2 TextField maxlength
Supported by current javafx-2 platform by default - No, but go through this link , it has many insights and sample code for Form validation in javaFX
public class NumberTextField extends TextField {
private int maxLenght;
public NumberTextField(int maxLenght) {
super();
this.maxLenght = maxLenght;
}
#Override
public void replaceText(int start, int end, String text) {
if (validate(text)) {
super.replaceText(start, end, text);
}
}
#Override
public void replaceSelection(String text) {
if (validate(text)) {
super.replaceSelection(text);
}
}
private boolean validate(String text) {
if (this.getText() != null) {
}
boolean status = ("".equals(text) || text.matches("[0-9]"));
if (this.getText() == null) {
return status;
} else {
return (status && this.getText().length() < maxLenght);
}
}
}
In some cases I would validate the text property:
myTextField
.textProperty()
.addListener(
(obs, oldVal, newVal) ->
{
if(!newVal.matches("\\d+"))
textField.setText(oldV);
});
Unlucky: textField.setText(oldV); will enter the same function again, testing unnecessarily if oldVal matches.
If the TextField becomes a value that doesn't matches before this listener is added to the TextField, enter a not matching new value will cause a loop!!!
To avoid this, it will be safer to write:
String acceptableValue = "0";
myTextField
.textProperty()
.addListener(
(obs, oldVal, newVal) ->
{
if(!newVal.matches("\\d+"))
textField.setText(oldVal.matches("\\d+") ? oldV : acceptableValue);
});
I wrote a class that extends the TextField and apply the mask.
package com.model;
import java.text.NumberFormat;
import java.util.Locale;
/**
* ATENTION
* DO NOT FORGUET TO IMPORT IN FXML
* <?import com.view.TextFieldMoney?>
*
* */
import javafx.scene.control.TextField;
public class TextFieldMoney extends TextField {
private int maxlength;
private String valor = "";
public TextFieldMoney() {
this.maxlength = 11;
}
public void setMaxlength(int maxlength) {
this.maxlength = maxlength;
}
#Override
public void replaceText(int start, int end, String text) {
// Delete or backspace user input.
if (getText() == null || getText().equalsIgnoreCase("")) {
valor = "";
}
if (text.equals("")) {
super.replaceText(start, end, text);
} else{
text = text.replaceAll("[^0-9]", "");
valor += text;
super.replaceText(start, end, text);
if (!valor.equalsIgnoreCase(""))
setText(formata(valor));
}
}
#Override
public void replaceSelection(String text) {
// Delete or backspace user input.
if (text.equals("")) {
super.replaceSelection(text);
} else if (getText().length() < maxlength) {
// Add characters, but don't exceed maxlength.
// text = MascaraFinanceira.show(text);
if (text.length() > maxlength - getText().length()) {
// text = MascaraFinanceira.show(text);
text = text.substring(0, maxlength - getText().length());
}
super.replaceSelection(text);
}
}
/*
*Return the number without money mask
**/
public String getCleanValue(){
String cleanString = getText().replaceAll("[^0-9]", "");
Double cleanNumber = new Double(cleanString);
return String.valueOf(cleanNumber/100);
}
private String formata(Double valor) {
Locale locale = new Locale("pt", "BR");
NumberFormat nf = NumberFormat.getInstance(locale);
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
return nf.format(valor);
}
public String formata(String valor) {
double v = new Double(valor);
return formata(v/100);
}
}
And in the FXML where is
<TextField fx:id="valorTextField" GridPane.columnIndex="2" GridPane.rowIndex="2" />
put
<TextFieldMoney fx:id="valorTextField" GridPane.columnIndex="2" GridPane.rowIndex="2" />