Resizing individual Text Objects - java

Over the last week or 2, I've been experimenting with different ways to manipulate shape and text objects in a scene using JavaFX.
Currently, I'm looking at creating new text objects and being able to manipulate their size.
So I have a scene, with a button that simply says "Text", that once pressed
creates a TextField whereby upon entering text into this field creates a new text object. There is also a slider which you're able to use to change the size of the text object. and you're able to drag the various Text objects about
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
public class CreatingNewText extends Application
{
private int size;
private TextField enterText;
private Slider sizeSlider;
private Button button;
public static void main(String [] args)
{
launch(args);
}
public void start(Stage primaryStage)
{
Pane root = new Pane();
// Button for creating new text Object
button = new Button("text");
button.setLayoutX(200);
// Slider for Size
sizeSlider = new Slider(0,255,0);
sizeSlider.setLayoutX(250);
sizeSlider.setLayoutY(0);
// Button functionality
button.setOnAction(e ->{
Text text = new Text(150,300,"Text");
// Moving created text
text.setOnMouseDragged(f ->{
text.setX(f.getX());
text.setY(f.getY());
});
text.setLayoutX(300);
text.setLayoutY(300);
text.setFont(Font.font("Phosphate"));
// Text entry field
enterText = new TextField();
text.textProperty().bind(enterText.textProperty());
// Slider functionality
text.setOnMouseEntered(g ->{
});
sizeSlider.valueProperty().addListener((ObservableValue
<? extends Number> ov, Number curVal, Number newVal) -> {
size = (int) sizeSlider.getValue();
Font fontSize = Font.font(size);
text.setFont(fontSize);
});
root.getChildren().addAll(enterText,text);
});
root.getChildren().addAll(button,sizeSlider);
Scene scene = new Scene(root,600,600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
The issues -
I cannot change the size of a specific text object - I understand that every time I create a new text object it assigns it to the "text" variable, and so upon altering the size with the slider all Text shapes associated with "text" will change also, how can this be corrected?
I am also sure the same thing is happening for the text field - every time the text button is pushed it just creates a new textfield which just sits on top of the old one. I have tried creating my textfield outside of the action event - similar to the slider, but cannot because the text object is local to the action event. Making "text" an instance variable just complicates things and I receive an "exception in application start method" error - So basically it doesn't work. Really what I want is just the one text field that can create multiple text objects
Apologies about the code. I am very inexperienced and it even looks a mess to me. Hope the question makes sense too

Look at this sample app made from your code. I think it demonstrates what you are trying to achieve :
Click on a text it become Red and you can adjust it's size with your slider
public class CreatingNewText extends Application {
private int size;
private TextField enterText;
private Slider sizeSlider;
private Button button;
private Text selected;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
Pane root = new Pane();
// Button for creating new text Object
button = new Button("text");
button.setLayoutX(200);
// Slider for Size
sizeSlider = new Slider(0, 255, 0);
sizeSlider.setLayoutX(250);
sizeSlider.setLayoutY(0);
// TextField
enterText = new TextField();
// Button functionality
button.setOnAction(e -> {
Text text = new Text(150, 300, "Text");
// Moving created text
text.setOnMouseDragged(f -> {
text.setX(f.getX());
text.setY(f.getY());
});
text.setLayoutX(300);
text.setLayoutY(300);
text.setFont(Font.font("Phosphate"));
text.textProperty().bind(enterText.textProperty());
text.addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
if (selected != null) {
selected.setFill(Color.BLACK);
}
selected = (Text) mouseEvent.getTarget();
selected.setFill(Color.RED);
});
root.getChildren().addAll(text);
});
sizeSlider.valueProperty().addListener((ObservableValue<? extends Number> ov, Number curVal, Number newVal) -> {
if (selected != null) {
size = (int) sizeSlider.getValue();
Font fontSize = Font.font(size);
selected.setFont(fontSize);
}
});
root.getChildren().addAll(button, sizeSlider, enterText);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}

Related

How to set an action to occur on pressing of any keyboard key in JavaFX?

So I want to do a title Menu for a video game project for college. I want to display a message press any key to continue... then when the user pressed any key, including the mouse, a method would run to set the stage to the next menu.
I posted all the relevant code bellow but short version is:
BackgroundImangeDisplayPane extends display pane and adds a background image.
TitleCard extends BackgroundImangeDisplayPane adds a VBox and 2 labels to the VBox
I'm using public void start(Stage primaryStage) throws Exception as the main, I set the setOnActionxxx methods here
I have tried using the set on action method on root and Vbox and non of them work... when I click nothing happens... But when I resize the window The root.setOnActionXXX "activates".
If I write the setOnAction methods on the TitleCard class It kind of works but then I cant switch the stage.
I will post the code bellow as well an explanation of the Scene structure its not to complicated:
// this will be the borderpane for every scene it recives a backgund
//images that will be present in every menu
public BackgroundImangeDisplayPane() {
try {
stream = new FileInputStream(imagePath.toString());
Image image = new Image(stream);
ImageView imageView = new ImageView();
imageView.setImage(image);
imageView.setFitWidth(1920);
imageView.setPreserveRatio(true);
this.getChildren().add(imageView);
BackgroundSize backgoundSize = new BackgroundSize(AUTO, AUTO, true, true, true, true);
BackgroundImage backgroundImage = new BackgroundImage(image, NO_REPEAT, NO_REPEAT, CENTER, backgoundSize);
Background background = new Background(backgroundImage);
this.setBackground(background);
} catch (Exception e) {
}
}
//This extends `BackgroundImangeDisplayPane` and places on top of it a A Vbox with two lables: the title and "press any key to continue..."
// it then adds styles to the labels
public class TitleCard extends BackgroundImangeDisplayPane {
Label title = new Label("Boats & Docks"); // lable 1
Label subtitle = new Label("Press any key to continue ..."); label2
public TitleCard(){
super();
VBox vbox = new VBox();
vbox.getChildren().add(title);
vbox.getChildren().add(subtitle);
this.setCenter(vbox);
this.setAlignment(vbox, Pos.CENTER);
vbox.setAlignment(Pos.CENTER);
title.setFont(new Font(170)); // set to Label
title.setTextFill(Color.SNOW);
title.setEffect(new DropShadow());
subtitle.setFont( new Font (30));
}
}
...
//Works as the "main" in javaFX
private Stage primaryStage;
#Override
public void start(Stage primaryStage) throws Exception {
TitleCard root = new TitleCard();
/*BasicMenu menu = new BasicMenu(5);
menu.ButtonSetOnAction(0, e -> changeScene() );
BackgroundImangeWithCustomMenu background = new
BackgroundImangeWithCustomMenu(menu,50,50);
root.setCenter(background);*/
Button b = new Button();
b.setOnAction(e -> changeSceneToLoginMenu());
System.out.println(root.getChildren().get(1).getClass());
root.getChildren().get(1).setFocusTraversable(true);
root.getChildren().get(1).setOnMouseClicked(e -> changeSceneToLoginMenu());
root.getChildren().get(1).setOnKeyPressed(e -> changeSceneToLoginMenu());
root.getChildren().get(0).setOnMouseClicked(e -> changeSceneToLoginMenu());
root.getChildren().get(0).setOnKeyPressed(e -> changeSceneToLoginMenu());
/*
root.setOnMouseClicked(e -> changeSceneToLoginMenu());
root.setOnKeyReleased(e -> changeSceneToLoginMenu());
root.setOnKeyPressed(e -> changeSceneToLoginMenu());
*/
Scene scene = new Scene(root, 1280, 720);
primaryStage.setScene(scene);
primaryStage.show();
this.primaryStage = primaryStage;
}
As proposed by James in comments, when a key is pressed on the scene, navigate to the next scene (or replace the root in the current scene, and remove the key press handler).
scene.setOnKeyPressed(e -> navigateToNextScene());
I managed to find a very simple working solution but I don't fully undestand why it does work. I Noticed that if I set the handler in the same class the node was instanciated the handler would work fine But if I tried to get the node with a method to the main fuction via root.getChildren().get(1) and then cast it to the VBox element the handler would not work.
As a solution I made the VBox a field and wrote a setter method for the VBox event Handler in the TitleCard Class. This fixed the problem.
I marked the code added as solution code with comments
public class TitleCard extends BackgroundImangeDisplayPane {
Label title = new Label("Boats & Docks"); // lable 1
Label subtitle = new Label("Press any key to continue ..."); label2
VBox vbox = new VBox; // solution code
public TitleCard(){
super();
VBox vbox = new VBox();
vbox.getChildren().add(title);
vbox.getChildren().add(subtitle);
this.setCenter(vbox);
this.setAlignment(vbox, Pos.CENTER);
vbox.setAlignment(Pos.CENTER);
title.setFont(new Font(170)); // set to Label
title.setTextFill(Color.SNOW);
title.setEffect(new DropShadow());
subtitle.setFont( new Font (30));
}
// Solution Code
public void setVBoxHandler(EventHandler<? super MouseEvent> value){
vbox.setOnMouseClicked(value);
}
}
Then I set the handler in the start method:
public void start(Stage primaryStage) throws Exception {
TitleCard root = new TitleCard();
VBox vBox =(VBox) root.getChildren().get(1);
root.setVBoxHandler(e->changeSceneToLoginMenu() ); // solution Code
Scene scene = new Scene(root, 1280, 720);
primaryStage.setScene(scene);
primaryStage.show();
this.primaryStage = primaryStage;
}
public void changeSceneToLoginMenu() {
System.out.println("It finally worked");
Scene currentScene = new Scene(new Group(),100,100); // just a demo
primaryStage.setScene(currentScene);
}
notes: The type of value on the method setVBoxHandler(EventHandler<? super MouseEvent> value) will depend on the setOnXXX method used. For example I tested and this soultion also works for buttons just need to change the type to EventHandler<ActionEvent> value.
Some coments on the question posted links on "how to use handlers", this posts used anomimous classes. I belived This way is outdated. I used lambdas in the code the end result is the same but more redable code
Just for reference if future readers are using anomimous classes the solution would be the same just change the way you set up the handler:
// lambdas
setVBoxHandler( e -> System.out.println("Code run if mouse is clicked "));
// anomimous classes
setVBoxHandler(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event){
System.out.println("Code run if mouse is clicked ");
}
});

Java FX component that appears from top and goes down

Does exists a Java FX component like one that appears from top and goes down, as in the gif below?
I was able to implement a demo based on transition of pane. It looks like:
The weakness of this approach is it doesn't work with a Window which has standard border, buttons, etc. A developer is responsible to build a nice window based on a Pane.
The other problem is resizing of the parent window will resize the sub pane as well. But if you have not resizable parent dialog it should not be a problem.
You are welcome to copy-paste this code and play with it:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
final SubPane subPane = new SubPane();
final TranslateTransition dialogAnimator =
new TranslateTransition(new Duration(500), subPane);
final Button showSubPaneButton = new Button("Slide a sub pane");
showSubPaneButton.setOnAction(event -> {
dialogAnimator.setToY(10);
dialogAnimator.play();
});
subPane.setCloseAction(event -> {
dialogAnimator.setToY(-subPane.getHeight());
dialogAnimator.play();
});
final Pane rootPane = new StackPane(showSubPaneButton, subPane);
rootPane.setPrefWidth(400);
rootPane.setPrefHeight(300);
// By default hide the given pane by moving to the top.
Platform.runLater(() -> subPane.setTranslateY(-subPane.getHeight()));
primaryStage.setTitle("Drop slided dialog");
primaryStage.setScene(new Scene(rootPane));
primaryStage.show();
}
}
class SubPane extends BorderPane {
private final Button dialogButton = new Button("Close");
SubPane() {
final Pane centralPane = new StackPane(dialogButton);
centralPane.setStyle(
"-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);-fx-padding: 10;" +
"-fx-background-color: firebrick;-fx-background-radius: 10;");
setCenter(centralPane);
final Pane blankLeftPane = new StackPane();
blankLeftPane.setPrefWidth(100);
setLeft(blankLeftPane);
final Pane blankRightPane = new StackPane();
blankRightPane.setPrefWidth(100);
setRight(blankRightPane);
final Pane blankBottomPane = new StackPane();
blankBottomPane.setPrefHeight(200);
setBottom(blankBottomPane);
}
void setCloseAction(final EventHandler<ActionEvent> closeCallback) {
dialogButton.setOnAction(closeCallback);
}
}
If you're talking about the dialog window, ControlsFX have something similar NotificationPane.

Can you write two different Java FX scenes as two separate classes?

I'm a beginning Java programmer, finishing up the "Java 101" class at my local university. I'm also pushing myself to learn some extra topics on the side, including Java FX. I've worked through the Java FX tutorials on Oracle's website, plus sat through some YouTube videos, plus read "Java FX for Dummies" (which was the best book I could find for a beginner.) All of this material has taught me a lot of the basics, but some stuff that (should be) relatively simple escapes me.
For example: Let's say I have a Java FX program that uses multiple scenes on one stage. When the user clicks a "Switch!" button, the second scene is swapped out for the first. Easy. I can do all of this in one .java file, no problem. (See code below)
But my .java class file is getting really long and cumbersome to troubleshoot. It would be great if I could define/declare/initialize one scene as one class in one .java file and the second scene as another class in another .java file. This would make keeping track of the components of each scene much, much easier. The problem is, I can't figure out how to do this.
I'd imagine that you would write a Scene1.java class and then a Scene2.java class, and simply pass the stage object between the two when you want to switch scenes. But I can't find an example of how this is done, and all my attempts result in compiler errors or really scary runtime errors.
Does anyone know how this can be done? If so, what would I have to do to modify the SwitchScenes2() method below to create the new Scene2 object and pass it the stage?
Thanks! RAO
/*
JavaFXExample.java
*/
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.event.*;
import javafx.geometry.*;
public class JavaFXExample extends Application{
public static void main(String[] args){
launch(args);
}
Button btnSw1;
Button btnSw2;
Button btnClose;
HBox hbox1;
VBox vbox1;
Scene scene1;
Scene scene2;
Stage stage;
#Override public void start(Stage primaryStage){
btnSw1 = new Button("Switch Scenes!");
btnSw1.setOnAction(
e -> SwitchScenes2() );
btnSw2 = new Button("Switch back!");
btnSw2.setOnAction(
e -> SwitchScenes1() );
btnClose = new Button();
btnClose.setText("Close me!");
btnClose.setOnAction(e -> CloseWindowClick());
hbox1 = new HBox(10);
hbox1.getChildren().addAll(btnSw1);
vbox1 = new VBox(10);
vbox1.getChildren().addAll(btnSw2, btnClose);
scene1 = new Scene(hbox1, 300, 300);
scene2 = new Scene(vbox1, 200, 400);
stage = primaryStage;
stage.setScene(scene1);
stage.setTitle("Example App");
stage.show();
}
public void SwitchScenes1(){
stage.setScene(scene1);
}
public void SwitchScenes2(){
stage.setScene(scene2);
}
public void CloseWindowClick(){
stage.close();
}
}
Pete as I understand you wish to separate one big java file into small files,create Java classes in each class create method(function) that will return layout(HBox,VBox, Flowpane or ....)then in your main create an object of that Java class and use those methods to build on big application.
in my sample I made one main and one separated class with one function,just to show you how its works. In my main there is 2 lables, 2 buttons one layout and one object of the separated class, by clicking the buttons scenes will change
My Main:
public class SwitchSceneSample extends Application {
public static void main(String[] args) {
launch(args);
}
Stage window;
Scene scene1, scene2;
#Override
public void start(Stage primaryStage) throws Exception {
// I am using window as primaryStage
window = primaryStage;
// Label 1
Label label1 = new Label("Welcome to the first scene!");
// Label 2
Label label2 = new Label("This is second scene!");
// Button 1, by pressing this button primaryStage will be set as scene 2
Button button1 = new Button("Go to scene 2");
button1.setOnAction(e -> window.setScene(scene2));
// Button 2, by pressing this button primaryStage will be set as scene 1
Button button2 = new Button("Click to go scene 1");
button2.setOnAction(e -> window.setScene(scene1));
// Creating an object of the class'LayoutOne.java'
LayoutOne l1 = new LayoutOne();
// set my scene 1(by calling method called 'sceneView1()' from class 'LayoutOne.java')
scene1 = new Scene(l1.sceneView1(label1, button1), 200, 200);
// Set my scene 2 inside my main class
StackPane layout2 = new StackPane();
layout2.getChildren().addAll(label2, button2);
scene2 = new Scene(layout2, 600, 300);
// Making my
window.setScene(scene1);
window.setTitle("Scene Switch Sample");
window.show();
}
}
My Second Class:
public class LayoutOne {
public VBox sceneView1(Label label, Button button) {
// Layout 1 - children are laid out in vertical column
VBox layout1 = new VBox(20);
layout1.getChildren().addAll(label, button);
return layout1;
}
}
What you will want to do is create separate classes that both have functions to return the scene. From there you will want to initialize these classes and with a button call a function that will add data to these scene or create a new blank scene (as a quick way to "delete" the scene). But if you want a more professional way to switch between scenes like this you will want to check out the TabPane().
Scene1 scene1 = new Scene1();
Scene2 scene2 = new Scene2();
TabPane tabPane = new TabPane();
Tab tab1 = new Tab();
tab1.setContent(scene1);
tabPane.getTabs().add(tab1);
Tab tab2 = new Tab();
tab2.setContent(scene2);
tabPane.getTabs().add(tab2);
Create a Manager class that contain the main method & initialize the first screen. eg.
public class VMCSManager extends Application {
private Parent content;
private static VMCSManager instance;
public VMCSManager() {
instance=this;
}
public static void main(String[] args) {
launch(args);
}
public static VMCSManager getInstance() {
return instance;
}
#Override
public void start(Stage primaryStage) throws Exception {
initializePanel();
Scene scene = new Scene(content);
stageStyle(primaryStage);
primaryStage.setScene(scene);
primaryStage.show();
}
private void initializePanel() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("fxml/SimulatorDisplay.fxml"));
content = loader.load();
}
public void openCustomerPanel() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("fxml/CustomerDisplay.fxml"));
content = loader.load();
Scene scene = new Scene(content);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Create main controller class for the first screen. eg;
public class SimulatorController implements Initializable{
#FXML
public void clickCustomer (ActionEvent event) throws IOException{
log.info("Starting Customer Panel");
VMCSManager.getInstance().openCustomerPanel();
}
#FXML
public void clickMaintainer(ActionEvent event) throws IOException{
log.info("Starting Maintainer Panel");
VMCSManager.getInstance().openMaintainerPanel();
}
}
Lastly Create the controller class for the specified screen. eg`
public class CustomerController extends SimulatorController{
#FXML
private Label brand1Lbl;
#FXML
private Label brand2Lbl;
#FXML
private Label brand3Lbl;
#FXML
private Label brand4Lbl;
#FXML
private Label brand5Lbl;
#FXML
private Label statusLbl1;
#FXML
private Label statusLbl2;
private static final Logger log=LoggerFactory.getLogger(CustomerController.class);
public CustomerController() {
context= new BuyingStateContext();
}
public void initialize(URL location, ResourceBundle resources) {
this.location = location;
this.rb = resources;
coinsValidityFlash.setVisible(false);
insertCoinTxt.setDisable(true);
brand1Btn.setStyle("-fx-background-color: #CACACA;");
brand2Btn.setStyle("-fx-background-color: #CACACA;");
brand3Btn.setStyle("-fx-background-color: #CACACA;");
brand4Btn.setStyle("-fx-background-color: #CACACA;");
brand5Btn.setStyle("-fx-background-color: #CACACA;");
populateVending();
}
.
.
.
}
`

Javafx: instance label not displayed

I am new in Javafx (and Java).
I am trying to display a label "title" to different scenes. Therefore this label in a instance variable. I create it using the method title().
The problem is that the title does not appear in my scenes. I tried to initialize it at class level, or inside the start(), or inside scene1(). Nothing works but when I create a local label inside the scene1() method.
Thanks in advance for your help.
ps: full repo here if needed
private Label title;
public void start(Stage primaryStage) {
title();
scene1();
scene2();
[some more code...]
}
public Node title() {
title = new Label();
title.setText("SNAKE");
title.setTextFill(Color.YELLOW);
title.setFont(Font.font(STYLESHEET_MODENA, FontWeight.BOLD, 80));
return title;
}
public Scene scene1() {
Label lbl1scene1 = new Label("Welcome to Game !");
Label lbl2scene1 = new Label("Click to start the game");
Button btnStart = new Button("Start the game now!");
btnStart.setOnAction(e -> {
runGame();
});
VBox vbox1 = new VBox(title, lbl1scene1, lbl2scene1, btnStart);
vbox1.setAlignment(Pos.CENTER);
vbox1.setSpacing(10);
scene1 = new Scene(vbox1, width, height);
return scene1;
}
I am trying to display a label "title" to different scenes.
Please note that a node can have only a single parent.
Create multiple instances using local variables instead of a title member field.

Getting error in textfield while converting decimal to various data types

This is my first post on StackOverflow. I'm having an issue within my program for setting up a decimal-hex-binary converter. The idea is to have three textfields: decimal, hex, binary on top of each other(in one VBox) and the labels: decimal, hex, binary, on matching those text field positions. I've acquired that with this code:
GridPane paneForVBoxes = new GridPane();
paneForVBoxes.setPadding(new Insets(10, 10, 10, 10));
paneForVBoxes.setVgap(10);
paneForVBoxes.setHgap(10);
VBox units = new VBox(12);
units.setAlignment(Pos.CENTER_LEFT);
Label lbDec = new Label("Decimal");
Label lbHex = new Label("Hex");
Label lbBin = new Label("Binary");
units.getChildren().addAll(lbDec, lbHex, lbBin);
VBox textFields = new VBox(5);
TextField tfDec = new TextField();
tfDec.setPrefColumnCount(19);
tfDec.setAlignment(Pos.CENTER_RIGHT);
TextField tfHex = new TextField();
tfHex.setPrefColumnCount(19);
tfHex.setAlignment(Pos.CENTER_RIGHT);
TextField tfBin = new TextField();
tfBin.setPrefColumnCount(19);
tfBin.setAlignment(Pos.CENTER_RIGHT);
textFields.getChildren().addAll(tfDec, tfHex, tfBin);
paneForVBoxes.add(units, 0, 0);
paneForVBoxes.add(textFields, 1, 0);
So the idea is to then give a live update of conversion to each textfield as you type in a value, for example: In the dec textfield you type 11, in the hex and bin fields 1A and 1011 automatically appear, respectively.
I achieve this to a point, but when I delete all characters in my textfields I receive NumberFormatExceptions and I have no idea how to get around this. This is what I've attempted to fix the problem:
please note This is only the coding for decimal to binary fields, with a simple fix to this I can apply that to the rest of my code that has yet to be developed.
note also I have tried Integer.parseInt(s) within and around tfDec.setText("0"); but eclipse truly does not like that
tfDec.setOnKeyReleased(e -> {
if (tfDec.equals("")) {
tfDec.setText("0");
}
else {
String bin = Integer.toBinaryString(Integer.parseInt(tfDec.getText()));
tfBin.setText(bin);
}
});
/Whole code/
package application;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Elias16_5 extends Application {
#Override
public void start(Stage primaryStage) {
try {
GridPane paneForVBoxes = new GridPane();
paneForVBoxes.setPadding(new Insets(10, 10, 10, 10));
paneForVBoxes.setVgap(10);
paneForVBoxes.setHgap(10);
VBox units = new VBox(12);
units.setAlignment(Pos.CENTER_LEFT);
Label lbDec = new Label("Decimal");
Label lbHex = new Label("Hex");
Label lbBin = new Label("Binary");
units.getChildren().addAll(lbDec, lbHex, lbBin);
VBox textFields = new VBox(5);
TextField tfDec = new TextField();
tfDec.setPrefColumnCount(19);
tfDec.setAlignment(Pos.CENTER_RIGHT);
TextField tfHex = new TextField();
tfHex.setPrefColumnCount(19);
tfHex.setAlignment(Pos.CENTER_RIGHT);
TextField tfBin = new TextField();
tfBin.setPrefColumnCount(19);
tfBin.setAlignment(Pos.CENTER_RIGHT);
textFields.getChildren().addAll(tfDec, tfHex, tfBin);
paneForVBoxes.add(units, 0, 0);
paneForVBoxes.add(textFields, 1, 0);
tfDec.setOnKeyReleased(e -> {
if (tfDec.equals("")) {
tfDec.setText("0");
}
else {
String bin = Integer.toBinaryString(Integer.parseInt(tfDec.getText()));
tfBin.setText(bin);
}
});
Scene scene = new Scene(paneForVBoxes, 300, 100);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("Data Conversion");
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
You should try StringUtils.
So this code:
if (tfDec.equals("")) {
will be
if (StringUtils.isBlank(tfDec.getText())) {
Read more here:
StringUtils.isBlank() vs String.isEmpty()
Also, in the first line, it should be
tfDec.getText().equals("")
not
tfDec.equals("")
Though setOnKeyReleased() works in this scenario but this is not the optimum solution. This method will be triggered whenever any key is released whether it makes any difference to the text in the textfield or not. For example, when the textfield is empty and the user is pressing BackSpace.
A better approach will be to add a change listener on the textProperty() of the TextField. This will only be triggered when the text of the textfield changes :
tfDec.textProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue.isEmpty()) {
tfBin.setText(Integer.toBinaryString(Integer.parseInt(newValue)));
} else {
tfBin.setText("0");
}
});
I am not sure if you have studied "try/catch" blocks. If so, then rather than trying to prevent the exception, why not catch the exception and deal with it. For example if someone types "G" and the exception occurs, then you can print "invalid" in the bin field and/or pop up a dialog that warns the users that only 0-9 are allowed in the decimal text field.
You have the statement tfDec.equals(""). Does that ever come back true? I am really surprised that a TextField can be compared to a string in the first place. I would have expected more like tfDec.getText().equals("");

Categories