Error using sub-string method with textfield - javafx

We are have an error when we try to obtain the first few character of a string
First we tried to remove the last two offending characters
That produced the same error we are seeing when we try to obtain the first few characters
The On Key Typed method is attached to a textfield when MAX character are exceeded a custom alert
is fired. We have looked at many ways to remove or get sub-strings in various SO questions before posting
The string entered will never be the same hence we do not know the specific character to replace
Here is the code and a screen shot of the ERROR notice that the "o" in front of the original text
The string we are entering is "This is a test to see how many yo"
We are trying to obtain only the "This is a test to see how many"
The System.out.println(strNew) is exactly that but when strNew is add to the textfield the "o" shows up
Our question is how to prevent this ?
OR What is the cause of the odd text that is palaced in the textfield?
Here is the Minimal Code to test
public class Atest extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
The Controller
public class testController implements Initializable {
#FXML
TextField txtDesc;
#FXML
private void handleButtonAction(ActionEvent event) {
txtDesc.setText("Thanks");
}
#FXML
private void descLEN(){
txtDesc.setOnKeyTyped(event ->{
int maxCharacters = 10;
if(txtDesc.getText().length() > maxCharacters)
event.consume();
});
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
We have no idea how to post FXML Code all you need is a TextField
with the id txtDesc and set the OnKeyTyped to descLEN

Because you are consumed with the Custom Alert you may not like our answer
I call this We Hear You Knocking but You Can NOT Come In Your event is consume
OK the answer suggested by Sedrick is great but we have only used 3 Lines of Code
No Custom Alert just 30 Character and a bunch of consuming ha ha
#FXML
private void onType(){
txtDescription.setOnKeyTyped(event ->{
int maxCharacters = 30;
if(txtDescription.getText().length() > maxCharacters)event.consume();
});
All right 7 lines if you count the FXML tab and the declaration and formatting

Related

JavaFX Button invisble, but can be pressed issue

EDIT:
I've determined that the following line is the cause:
primaryStage.initStyle(StageStyle.UNIFIED);
Can any explain why it would be causing this issue?
JDK: 13.0.1
FX: 13
Eclipse: 2019-09 R (4.13.0)
Maybe I'm going crazy, because I feel like I do pretty good with JavaFX... But for some reason, the buttons don't appear, but I can press them, and my logger says the buttons are pressed. I can press the exit button (although invisible), and it quits as expected... so why are the button invisible?
I've attempted to set visibility to true, but that did nothing too. The button sizes appear to be set properly too.
public class test extends Application {
private Button gameButton = new Button("Game");
private Button mapEditorButton = new Button("Map Editor");
private Button exitButton = new Button("Exit");
private static final int buttonHeight = 25;
private static final int buttonWidth = 100;
private static final int screenwidth = 350;
private static final int screenHeight = 150;
private Scene theScene;
private Stage primaryStage;
private VBox root = new VBox(30);
private HBox top = new HBox(10);
public void start(Stage stage) {
primaryStage = stage;
setButtonSizes();
root.setPrefSize(screenwidth, screenHeight);
root.resize(screenwidth, screenHeight);
root.setAlignment(Pos.CENTER);
root.getChildren().addAll(top, exitButton);
top.getChildren().addAll(gameButton, mapEditorButton);
top.setAlignment(Pos.CENTER);
theScene = new Scene(root);
primaryStage.setTitle("Menu Selector");
primaryStage.setWidth(screenwidth);
primaryStage.setHeight(screenHeight);
primaryStage.setResizable(false);
primaryStage.initStyle(StageStyle.UNIFIED);
primaryStage.setScene(theScene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private void setButtonSizes() {
gameButton.setMinSize(buttonWidth, buttonHeight);
gameButton.setMaxSize(buttonWidth, buttonHeight);
gameButton.setPrefSize(buttonWidth, buttonHeight);
mapEditorButton.setMinSize(buttonWidth, buttonHeight);
mapEditorButton.setMaxSize(buttonWidth, buttonHeight);
mapEditorButton.setPrefSize(buttonWidth, buttonHeight);
exitButton.setMinSize(buttonWidth, buttonHeight);
exitButton.setMaxSize(buttonWidth, buttonHeight);
exitButton.setPrefSize(buttonWidth, buttonHeight);
}
}
Here's an image of the problem:
After commenting out lines of your code to try to discover what was causing the behavior, I found that it was this line...
primaryStage.initStyle(StageStyle.UNIFIED);
Then I looked at the javadoc for class StageStyle. It states...
Specifies the style for this stage. This must be done prior to making the stage visible. The style is one of: StageStyle.DECORATED, StageStyle.UNDECORATED, StageStyle.TRANSPARENT, or StageStyle.UTILITY
Hmm, UNIFIED isn't mentioned there. Nonetheless, your code compiles and runs without error, so UNIFIED must be a valid value. So then I looked at the javadoc for UNIFIED and read this...
This is a conditional feature, to check if it is supported see javafx.application.Platform.isSupported
So running this method...
Platform.isSupported(ConditionalFeature.UNIFIED_WINDOW)
returned true on my Windows 10 64-bit machine running [Oracle] JDK 13.0.1
Despite this, using StageStyle.UNIFIED causes a problem. My guess is it may be a bug. In any case, if you remove this line (or comment it out), you will see your buttons.

How to use setOnAction event on javafx

I would like to validate if a textfield is empty or not using javafx.
I am confused of event handlers. I want to confirm :
- whether there are many ways to use setOnAction :
submit.setOnAction((new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
System.out.println("Hello World");
}
}));
or
submit.setOnAction(e -> handle(e));
what is the difference between these two choices?
whether the second choice can not use the ActionEvent
submit.setOnAction(e -> handle());
but then what is the purpose of defining e?
I would like to validate textfields in my application.
public class AppGUI extends Application{
public static void main(String[] args)
{
launch();
}
public void start(Stage topView)
{
createUI(topView);
}
private void createUI(Stage topView)
{
TextField name = TextField();
Button submit = new Button("Submit");
submit.setOnAction(e -> validate());
}
private boolean validate()
{
// if textfield is empty, return false. else, return true.
}
I am lost here. Is it okay if the e in setOnAction is not used in validate? How do I pass the value of textfield to validate()? is making the textfields private variables the only way? (because I have so many text fields I wonder if its a good option).
in createUI method, how do i say if validate() returns false, show error message and if true, do something else?
Thank you and sorry for bothering
what is the difference between these two choices?
In second option lambdas are used (appeared since Java 8)
but then what is the purpose of defining e?
For a button your method have a signature like this setOnAction(EventHandler<ActionEvent> handler) You should see EventHandler tutorials and an ActionEvent javadoc. For instance, from e you can get the object on which the Event initially occurred this way e.getSource()
It is ok if you don't use e in validate.
To pass the value of textfield your method should have signature like this
boolean validate(String text);
Code example:
private void createUI(Stage topView){
TextField name = TextField();
Button submit = new Button("Submit");
submit.setOnAction(e -> {
boolean validated = validate(name.getText());
if(validated) System.out.println("validated");
}
}
private boolean validate(String text){
return text != null && !text.isEmpty();
}

stop for X seconds before running next function in JAVA FXML (using SCENEBUILDER)

I've used Scenebuilder to place few shapes in my GUI (simplified version of my project). I would like the shapes to change colours but wait 2 seconds between changing colours. I want these changes to happen in my controller class after a button is pressed.
Circle1.setFill(YELLOW)
Wait(2 seconds)
Circle2.setFill(BLUE)
I'm not sure how to do that. I have read online about threading, but I don't really understand how to implement that from my Main and into my Controller class. Also, I could not really find any examples online. My Main class looks like:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("File.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
Please help. Also, if you could provide an example would be helpful for me to understand as I could not really find one online that gives an example of this.
Answering this question is easiest through an example I believe. So I've created a small Traffic Light application, since it allows me to use Circle and a timed sequence similar to your problem, whilst being a familiar concept for all.
I'll be using java.util.Timer alongside java.util.TimerTask for handling the sequence of lights. You may choose to use some animation / time line in JavaFX, but I think that is overkill for this kind of task.
I include the three files used in this project:
FXMLTrafficLight.fxml - which defines my FXML layout
FXMLTrafficLightController.java - my FXML controller
TrafficLightApplication.java - for completeness my subclass of Application, this is just the boiler plate.
FXMLTrafficLight.fxml
Not a fancy layout, just a VBox with three circles redLight, amberLight and greenLight, plus two Button objects startLights and stopLights used to start and stop the timer.
<VBox fx:id="root" id="VBox" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxtimer.FXMLTrafficLightController">
<children>
<Circle fx:id="redLight" radius="100"></Circle>
<Circle fx:id="amberLight" radius="100"></Circle>
<Circle fx:id="greenLight" radius="100"></Circle>
<Button fx:id="startLights" text="Start Lights" onAction="#startLights"></Button>
<Button fx:id="stopLights" text="Start Lights" onAction="#stopLights"></Button>
</children>
</VBox>
FXMLTrafficLightController.java
I've included the model/state in the controller for simplicity. Whether a light is red / amber / green is determined by a boolean flag. The initial state is set in the initialize() method, and is updated by calling updateState().
When startLights(ActionEvent) is invoked (the EventHandler for startLights) a new Timer is constructed with a TimerTask implementation that first invokes updateState() on the thread created by the Timer and then invokes updateLights() which changes the color of the lights based on the current state on the JavaFX Application Thread using Platform.runLater(Runnable).
Note: the TimerTask itself will not be run on the JavaFX Application Thread, hence the need to use Platform.runLater(Runnable) for updating the GUI.
When stopLights(ActionEvent) is invoked, it will cancel the Timer.
Note that both startLights(ActionEvent) and stopLights(ActionEvent) toggle which Button objects are enabled on the interface as well.
public class FXMLTrafficLightController implements Initializable {
#FXML
private Circle redLight;
#FXML
private Circle amberLight;
#FXML
private Circle greenLight;
#FXML
private Button startLights;
#FXML
private Button stopLights;
private Timer timer;
private static final int DELAY = 2000; // ms
private boolean red, amber, green;
#Override
public void initialize(URL url, ResourceBundle rb) {
red = true;
amber = false;
green = false;
stopLights.setDisable(true);
updateLights();
}
#FXML
private void startLights(ActionEvent e) {
toggleButtons();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
// Not run on the JavaFX Application Thread!
updateState();
// Using Platform.runLater(Runnable) to ensure updateLights()
// is run on the JavaFX Application Thread
Platform.runLater(new Runnable() {
#Override
public void run() {
updateLights();
}
});
}
}, 0, DELAY); // no initial delay, trigger again every 2000 ms (DELAY)
}
#FXML
private void stopLights(ActionEvent e) {
toggleButtons();
timer.cancel();
}
private void toggleButtons() {
startLights.setDisable(!startLights.isDisable());
stopLights.setDisable(!stopLights.isDisable());
}
private void updateState() {
if (red && !amber && !green) {
amber = true;
} else if (red && amber && !green) {
red = false;
amber = false;
green = true;
} else if (!red && !amber && green) {
green = false;
amber = true;
} else {
red = true;
amber = false;
green = false;
}
}
private void updateLights() {
redLight.setFill(red ? Color.RED : Color.GREY);
amberLight.setFill(amber ? Color.ORANGE : Color.GREY);
greenLight.setFill(green ? Color.GREEN : Color.GREY);
}
}
TrafficLightApplication.java
For completeness... Just the standard boiler plate with file names changed.
public class TrafficLightApplication extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLTrafficLight.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

How can I use .setText on a non-Static Label from a different Class [duplicate]

I have written a controller for two windows /stages.
The first window is opened in the MainClass. The second in the Controller, if the user clicks onto a button.
How can I get the TextFields from second.fxml in the applyFor()-method?
Thanks.
#FXML
protected void requestNewAccount(ActionEvent event) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("second.fxml")); // TextFields in there
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Second Window");
Scene scene = new Scene(root);
String css = MainOnlineCustomer.class.getResource("/style.css").toExternalForm();
scene.getStylesheets().clear();
scene.getStylesheets().add(css);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
logger.error(e);
}
}
/**
* closes the "second"-Window
* #param event
*/
#FXML
protected void cancel(ActionEvent event) {
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
#FXML
protected void applyFor(ActionEvent event) {
// get values from TextField in second.fxml here!!!
}
It's not good to share controllers between fxmls unless they serve the same purpose. Here both fxml seem to serve a different purpose (account management, login or something similar for one of them and creating a new account for the other). What is even worse is that those classes do not share the same controller instance, which means the small (and probably only) benefit you could get from using the same controller, is not used here. You should better use different controllers.
Since you use Modality.APPLICATION_MODAL as modality, I'd recommend using showAndWait instead of show to open the new stage. This will enter a nested event loop, which allows the UI to remain responsive and continues after the invocation of showAndWait once the stage is closed.
Furthermore add a method to the controller of second.fxml that allows you to retrieve the result.
Example
This creates a Person object with given name and family name.
"primary window (opening the "inner" stage)
FXMLLoader loader = new FXMLLoader(getClass().getResource("second.fxml"));
Stage subStage = new Stage();
subStage.initModality(Modality.APPLICATION_MODAL);
subStage.setTitle("Second Window");
Scene scene = new Scene(loader.load());
subStage.setScene(scene);
subStage.showAndWait();
Optional<Person> result = loader.<Supplier<Optional<Person>>>getController().get();
if (result.isPresent()) {
// do something with the result
}
controller for "inner" content
public class SecondController implements Supplier<Optional<Person>> {
#FXML
private TextField givenName;
#FXML
private TextField familyName;
private boolean submitted = false;
// handler for submit action
#FXML
private void submit() {
submitted = true;
givenName.getScene().getWindow().hide();
}
// handler for cancel action
#FXML
private void cancel() {
givenName.getScene().getWindow().hide();
}
#Override
public Optional<Person> get() {
return submitted ? Optional.of(new Person(givenName.getText(), familyName.getText())) : Optional.empty();
}
}
Note that you can gain access to any data available to the controller this way. I wouldn't recommend accessing any nodes (like TextFields) directly though, since this makes changing the UI harder.
Using the Supplier interface here is not necessary, but I chose to do this to achieve a loose coupling between SecondController and the main window.

How do I automatically trigger enter key in Javafx

Nowadays I am working on raspberry pi and I write some programs in java , javafx platforms.I just would like to inform you that I am simply beginner on javafx.
According to that I just would like to trigger ENTER key after changing my textfield.Working principle of my program is like this;
1)I have created one masterform fxml and it is directing all other pages with one textfield.
2)I created main method that let me to use keyboard to enter some specific String values to assign them to textfield for page alteration.
3)I have a bridge java page, it includes global variables to use everywhere in project.So Firstly I set value from keyboard to these global variables.These global variables are created as stringproperty for adding actionlistener for any change.
4)Then I set these global variables to textfield.
5)Textfield indicates relevant values from keyboard.But Unfortunately I can not forward the pages without pressing to enter key.In this case ı would like to trigger this textfield.But unfortunately ı have no idea how to trigger texfield without pressing enter key.Therefore I decided to make auto trigger to enter key for this textfield.
I simply used robot method;
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ENTER);
But it didn't work.Because After I set the global variable to textfield for first time.It does not define the value of the textfield is changed.It determines after pressing the enter key.
So how can I trigger this textfield after getting value of my global variables.I would like to pass how to set pages, I will show you how my program works.
Example of my code is;
Main method
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
for (String strBarcode = scanner.nextLine(); !strBarcode.isEmpty();
strBarcode = scanner.nextLine()) {
if (strBarcode.equals("distribution")){
Global.G_MOD.set("distribution");
System.out.println(Global.G_MOD.get());
}
}}
GlobalVariables.java(bridge page)
public class Global{
public static StringProperty G_MOD = new SimpleStringProperty("");
}
My MasterController Page for javafx
public class masterformController implements Initializable {
#FXML
public TextField tbxBarcode;
#FXML
void onchangetbxBarcode(ActionEvent event) {
if(Global.G_MOD.get().equals("distribution")){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/puttolightfx/fxml/page1.fxml"));
Parent rootpage1 = (Parent)loader.load();
pnPages.getChildren().clear();
pnPages.getChildren().add(rootpage1);
} catch (IOException ex) {
Logger.getLogger(masterformController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
Global.G_MOD.addListener(new ChangeListener(){
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
String Newvalue = (String)newValue;
tbxBarcode.setText(Global.G_MOD.get());}
});
}
}
So Everything is working, just I have to trigger textfield when the global value : Global.G_MOD is indicated on texfield.Then it will pass to another page according to global value of Global.G_MOD : "distribution".
SOLUTION(SOLVED):
I solved my problem using thread on listener of the textfield.I gave up to trigger enter key automatically and focused on textfield change.
I simply decided to use thread to change .fxml pages in textfield listener.
Platform.runLater(new Runnable() {
#Override
public void run() {
//if you change the UI, do it here !
}
});
EDITED CODE :
tbxBarcode.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
String Newvalue=(String)newValue;
System.out.println(tbxBarcode.getText());
Platform.runLater(new Runnable() {
#Override
public void run() {
if(Global.G_MOD.get().equals("distribution")){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/puttolightfx/fxml/page1.fxml"));
Parent rootpage1 = (Parent)loader.load();
pnPages.getChildren().clear();
pnPages.getChildren().add(rootpage1);
} catch (IOException ex) {
Logger.getLogger(masterformController.class.getName()).log(Level.SEVERE, null, ex);
}
}
// }
}
});
});
Try using
textField.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.ENTER, true, true, true, true));
According to the docs
public KeyEvent(EventType<KeyEvent> eventType,
String character,
String text,
KeyCode code,
boolean shiftDown,
boolean controlDown,
boolean altDown,
boolean metaDown)
Constructs new KeyEvent event with null source and target and KeyCode object directly specified.
Parameters:
eventType - The type of the event.
character - The character or sequence of characters associated with the event
text - A String describing the key code
code - The integer key code
shiftDown - true if shift modifier was pressed.
controlDown - true if control modifier was pressed.
altDown - true if alt modifier was pressed.
metaDown - true if meta modifier was pressed.
Since:
JavaFX 8.0
You can refer https://docs.oracle.com/javase/8/javafx/api/javafx/scene/input/KeyEvent.html
Edit 1
You need to identify the moment when Enter key event must be triggered.
For example:
If your textfield allows a limited number of characters, then you can add the above mentioned code in the following way:
txtField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (newValue.length()>30) {
txtField.setText(oldValue);
txtField.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.ENTER, true, true, true, true));
}
}
});
This is just an example. It can fire your event multiple times, so you need to write the code to fire the event just once.

Resources