Getting an input with javaFX - java

I am trying to use a text field to get an input which represents the radius to draw a circle.
I have tried creating the circle inside processreturn.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.TextField;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class Task5 extends Application {
int rad;
int x = 200;
private TextField input;
public void start(Stage stage) {
input = new TextField();
input.setPrefWidth(50);
input.setAlignment(Pos.CENTER);
input.setOnAction(this::processReturn);
System.out.print(rad);
Circle circle = new Circle();
// Setting the properties of the circle
circle.setCenterX(x);
circle.setCenterY(200);
circle.setRadius(rad);
// Creating a Group object
Group root = new Group(circle, input);
// Creating a scene object
Scene scene = new Scene(root, 600, 300, Color.LIGHTBLUE);
// Setting title to the Stage
stage.setTitle("Drawing a Circle");
// Adding scene to the stage
stage.setScene(scene);
// Displaying the contents of the stage
stage.show();
System.out.print(rad);
}
public void processReturn(ActionEvent event) {
rad = Integer.parseInt(input.getText());
System.out.println("rad is" + rad);
}
}
Currently it seems that the variable rad is changing but it is not updating the circle in the Group instance. Is it possible to update the group or create another group that has a the circle with the updated rad?

Related

Javafx how to change another Stage from a separate Controller?

I have multiple stages in my program, each with their own controller class. For simplicity I will focus on just two: the Main stage and the Add stage. My program is a projectile simulator program, so the Main stage will show the simulation, while the Add stage allows the user to add projectiles.
The problem I am experiencing is that when the user adds a projectile in the Add stage, it needs to then add the projectile to the Main stage so that it can be displayed. I am having troubles with communicating this new projectile between the two stages.
I have tried using the FXMLLoader.getController() method, to then run MainController.add( newSphere ), but there is a NullPointerException on the controller. The controller should not be null and the new sphere should have been passed to the add method, so that the Sphere can be displayed on the Main Stage.
Application Class
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class App extends Application
{
private FXMLLoader fxmlLoader = new FXMLLoader( getClass().getResource("/Main.fxml") );
public void start( Stage primaryStage ) throws Exception
{
Parent root = fxmlLoader.load();
Scene scene = new Scene( root, 900, 600 );
primaryStage.setTitle("Projectile Simulator");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main( String[] args )
{
launch(args);
}
}
Main Controller
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;
public class MainController
{
private Group group = new Group();
/**
* Creates the Add Stage when the user presses the Add button.
* #param event
*/
public void handleAddMenuAction( ActionEvent event )
{
Stage addStage = new Stage();
try
{
Parent root = FXMLLoader.load( getClass().getResource("/Add.fxml") );
Scene scene = new Scene(root, 300, 250);
addStage.setScene(scene);
addStage.setResizable(false);
addStage.setTitle("Add Simulation");
addStage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
// Adds the sphere to the group.
public void addSphere( Sphere newSphere )
{
group.getChildren().add( newSphere );
}
}
Add Controller
There are other features, such as setting the position and velocity of the projectile etc, but I have left them out for simplicity.
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.shape.Sphere;
public class AddController
{
#FXML private TextField txtRadius;
#FXML private void handleAddButtonAction()
{
FXMLLoader loader = new FXMLLoader( getClass().getResource("/Main.fxml") );
MainController mainController = loader.getController();
String szRadius = txtRadius.getText();
double dRadius;
dRadius = Double.parseDouble( szRadius );
Sphere sphere = new Sphere();
sphere.setRadius( dRadius );
mainController.addSphere( sphere);
}
}

Layout bounds of a group and invisible elements in JavaFX

I have a number of nodes in a group, whose visibility I would like to control using the visibleProperty(). I have observed that turning visibility of an element off affects the layout bounds of the group. They are recalculated as if the element wasn't there at all, not just wasn't visible. Is there a way to keep the presence of a node, but just turn off its visibility, so that the layout bounds were adjusted as if the node was there the whole time?
Example to ilustrate the problem, let's assume that the nodes are circles below.
Circle c1 = new Circle(0.0, 0.0, 3); // radius is 3
Circle c2 = new Circle(10.0, 10.0, 3);
Circle c3 = new Circle(20.0, 20.0, 3);
Group g = new Group();
g.getChildren().addAll(c1, c2, c3);
Bounds b1 = g.getLayoutBounds();
c3.visibleProperty().setValue(false);
Bounds b2 = g.getLayoutBounds();
Above bounds b and b2 will span:
b1 = BoundingBox [minX:-3.0, minY:-3.0, minZ:0.0, width:26.0, height:26.0, depth:0.0, maxX:23.0, maxY:23.0, maxZ:0.0]
b2 = BoundingBox [minX:-3.0, minY:-3.0, minZ:0.0, width:16.0, height:16.0, depth:0.0, maxX:13.0, maxY:13.0, maxZ:0.0]
Bounds b2 are calculated after turning off the visibility of circle c3, so they shrinked with respect to the original bounds b1. I would like to have the method of having the bounds expanded to b1, even though some elements in the group are not visible.
Edit
Minimal reproducible example:
package sample;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.HBox;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Circle c1 = new Circle(0.0, 0.0, 3); // radius is 3
Circle c2 = new Circle(10.0, 10.0, 3);
Circle c3 = new Circle(20.0, 20.0, 3); // radius is 3
Circle c4 = new Circle(30.0, 30.0, 3);
Group g1 = new Group();
Group g2 = new Group();
g1.getChildren().addAll(c1, c2);
g2.getChildren().addAll(c3, c4);
Group main = new Group(g1, g2);
CheckBox checkBox1 = new CheckBox("Show");
g2.visibleProperty().bind(checkBox1.selectedProperty());
Bounds b1 = main.getLayoutBounds();
System.out.println(b1);
checkBox1.selectedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
System.out.println(main.getLayoutBounds());
}
});
HBox hbox = new HBox(checkBox1, main);
Scene scene = new Scene(hbox, 400, 300);
primaryStage.setTitle("Hello Stackoverflow, are you happy now?");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Now, any time you select the checkbox, not only 2 of 4 circles appear, but you will also see that layout bounds of the group change. The problem is that I need to know all the time the layout bounds as if all the groups were visible. I can't store the bounds value when they are all visible, because for simplicity I included here only 4 circles, while in real application, they are in thousands and they are moving around also when not visible, and there are also other objects of different sizes bound to them, which may expand the layout bounds of the main group even more.
Updated solution.
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Shape;
public class ShapesGroup extends Group {
public final BooleanProperty transparentProperty = new SimpleBooleanProperty();
private final ObservableList<Shape> shapes = FXCollections.observableArrayList();
public ShapesGroup() {
Bindings.bindContent(getChildren(), shapes);
shapes.addListener((ListChangeListener<Shape>) change -> {
while (change.next()) {
if (change.wasAdded()) {
for (Shape shape : change.getAddedSubList()) {
shape.fillProperty().addListener((ChangeListener<Paint>) (observable, oldFill, newFill) -> {
transparentProperty.addListener((ChangeListener<Boolean>) (observable1, oldTransparent, newTransparent) -> {
if (!newTransparent) {
shape.setFill(oldFill);
}
});
});
transparentProperty.addListener((ChangeListener<Boolean>) (observable, oldValue, newValue) -> {
if (newValue) {
shape.setFill(Color.TRANSPARENT);
}
});
}
}
}
});
}
public ObservableList<Shape> getShapes() {
return shapes;
}
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class MainApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Rectangle rectangle = new Rectangle(40, 40, Color.YELLOW);
Circle circle = new Circle(20, Color.RED);
ShapesGroup group = new ShapesGroup();
group.getShapes().addAll(rectangle, circle);
StackPane stackPane = new StackPane(group);
Button button = new Button("Switch");
VBox vBox = new VBox(stackPane, button);
VBox.setVgrow(stackPane, Priority.ALWAYS);
Scene scene = new Scene(vBox, 400, 400);
stage.setScene(scene);
stage.show();
button.setOnAction(event -> {
group.transparentProperty.set(!group.transparentProperty.get());
});
}
}

Javafx - Text Animation not smooth on Embedded Device

We are currently working on a JavaFX Project for which we need to implement Text animation like movement from Left to Right with variant speeds. Execution environment for the application is an Embedded device - Stick PC.
We have used Translate Transition API https://docs.oracle.com/javase/8/javafx/api/javafx/animation/TranslateTransition.html for achieving animation effect but we are facing smoothness issues in it. Text is moving with jerks and movement speed is slow compared to animation in Laptop/Desktop
package application;
import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
public class SampleAnimationTest extends Application {
// private final Logger logger = Logger.getLogger("genLog");
#Override
public void start(Stage primaryStage) throws Exception {
StackPane group = new StackPane();
Rectangle rectangle = new Rectangle();
rectangle.setHeight(1080);
rectangle.setWidth(1920);
rectangle.setFill(Color.WHITE);
rectangle.setTranslateX(0);
rectangle.setTranslateY(0);
rectangle.setCache(true);
rectangle.setCacheHint(CacheHint.SPEED);
Text text = new Text("THIS IS A LONG TEXT FOR TESTING TEXT ANIMATION IN JAVAFX");
text.setFill(Color.BLACK);
text.setUnderline(false);
text.setFont(Font.font("Meiryo", 509.3899));
text.setTextAlignment(TextAlignment.CENTER);
text.setCache(true);
text.setCacheHint(CacheHint.SPEED);
TranslateTransition tt = new TranslateTransition();
tt.setNode(text);
Rectangle rClip = new Rectangle();
rClip.setWidth(rectangle.getWidth());
rClip.setHeight(rectangle.getHeight());
rClip.translateXProperty().bind(rectangle.translateXProperty());
group.getChildren().add(rectangle);
group.getChildren().add(text);
group.setClip(rClip);
Group group2 = new Group();
group2.getChildren().add(group);
Scene scene = new Scene(group2, 1920, 1080);
primaryStage.setMaximized(true);
primaryStage.setTitle("Decorations Example");
primaryStage.setScene(scene);
primaryStage.show();
tt.fromXProperty().bind(rectangle.translateXProperty().add(rectangle.getLayoutBounds().getWidth()));
tt.toXProperty().bind(rectangle.translateXProperty().subtract(text.getLayoutBounds().getWidth()));
tt.setRate(0.077364);
tt.setInterpolator(Interpolator.LINEAR);
tt.setCycleCount(Timeline.INDEFINITE);
tt.playFromStart();
}
public static void main(String[] args) {
launch(args);
}
}

Changing an Int value to a String in object oriented programming

I am making a simple game on JavaFX right now.
The picture of my program is here
So far, my code is generating random monsters using a random number generator, and my health will decrease a random number each time I hit the explore button.
I also added a stats box. This box will display my current health, hunger, and hydration levels.
My problem is, is that I am not sure how I am supposed to change the values in my stats box. Every time my character gets hit by a monster, I want the health text to change. When I do :
dStatBox.setText(mainCharacter.getHealthLevel());
It says that I must convert the int to a string. How can I go about doing this?
My whole code is below:
import java.util.Random;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class Game extends Application {
public static TextArea dialogue = new TextArea();
public static TextArea dStatBox = new TextArea();
Button exploreButton;
Random r = new Random();
int ogreDamage = r.nextInt(20) + 1;
public void start(Stage primaryStage) {
Character mainCharacter = new Character("Nikki");
BorderPane pane = new BorderPane();
HBox top = new HBox();
VBox gameBox = new VBox();
VBox explore = new VBox();
VBox statBox = new VBox();
exploreButton = new Button("Explore");
Label stats = new Label("Stats");
stats.setFont(Font.font(30));
stats.setFont(Font.font("Helvetica", FontWeight.BOLD, FontPosture.REGULAR, 24));
statBox.setPadding(new Insets(10,10,10,10));
statBox.setSpacing(10);
statBox.setMaxHeight(300);
statBox.setPrefWidth(300);
statBox.getChildren().addAll(stats, dStatBox);
statBox.setAlignment(Pos.TOP_CENTER);
dStatBox.setEditable(false);
dStatBox.setText("Health: 100/100\n");
Label label = new Label("Game Dialogue");
label.setFont(Font.font(30));
label.setFont(Font.font("Helvetica", FontWeight.BOLD, FontPosture.REGULAR, 24));
gameBox.setPadding(new Insets(10,10,10,10));
gameBox.setSpacing(10);
dialogue.setMaxHeight(200);
dialogue.setMaxWidth(470);
dialogue.setWrapText(true);
dialogue.setEditable(false);
gameBox.getChildren().addAll(label, dialogue, exploreButton);
gameBox.setAlignment(Pos.CENTER);
top.getChildren().addAll(gameBox, statBox);
top.setAlignment(Pos.TOP_LEFT);
pane.setTop(top);
dialogue.appendText("Welcome to Wild Berries - the Ultimate Survival Game\n");
dialogue.appendText("How long can you survive for? Only time will tell...\n");
exploreButton.setOnAction(e -> {
Random r = new Random();
int ogreDamage = r.nextInt(20) + 1;
int randomInt = r.nextInt(3) + 1;
dialogue.appendText("You begin to explore the wild...\n");
if(randomInt == 1) {
dialogue.appendText("A wild Ogre has appeared!\n");
dialogue.appendText("You have been hurt. -" + ogreDamage + " HP.\n");
mainCharacter.setHealthLevel(mainCharacter.getHealthLevel() - ogreDamage);
dialogue.appendText(mainCharacter.getHealthLevel());
if(mainCharacter.getHealthLevel() <= 0) {
dialogue.appendText("You have died. Thank you for playing.");
}
}
if(randomInt == 2) {
dialogue.appendText("A wild Goblin has appeared!\n");
}
if(randomInt == 3) {
dialogue.appendText("A wild Ghost has appeared!\n");
}
});
Scene scene = new Scene(pane, 800, 450);
primaryStage.setScene(scene);
primaryStage.setTitle("Wild Berries GUI");
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
I'm assuming that mainCharacter.getHealthLevel() is returning an int. You should do dStatBox.setText("Health: " + mainCharacter.getHealthLevel());
As simple as this:
int healthLevel = mainCharacter.getHealthLevel();
String.valueOf(healthLevel);
//or
Integer.toString(healthLevel);

javafx pane not being created

My JavaFx code does not work as it should do. I am trying to create 10X10 text matrix populated with either a 1 or 0, so it looks similar to a 2d array filled with 1's and 0's. When I put the code that is currently in the MatrixPane class in main it works fine, but with this code it just sets the scene but it looks like no pane is added or created.
If anyone can help me I would greatly appreciate it.
I realize I have Imported some unused things, I am using them for other parts of the program.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.FlowPane;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.scene.shape.Arc;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.geometry.Pos;
import javafx.collections.ObservableList;
public class Button1 extends Application
{
public void start(Stage primaryStage)
{
GridPane pane = new GridPane();
MatrixPane Matrix = new MatrixPane();
pane.getChildren().add(Matrix);
Scene scene = new Scene(pane, 700, 500);
primaryStage.setTitle("1 window "); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public static void main(String[] args)
{
Application.launch(args);
}
}
class MatrixPane extends Pane
{
double HEIGHT = 500;
double WIDTH = 200;
private GridPane pane1 = new GridPane();
public MatrixPane()
{
}
public void fillmatrix()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
TextField text = new TextField(Integer.toString((int)(Math.random() * 2)));
text.setMinWidth(WIDTH / 8.0);
text.setMaxWidth(WIDTH / 10.0);
text.setMinHeight(HEIGHT / 8.0);
text.setMaxHeight(HEIGHT / 10.0);
this.pane1.add(text, j, i);
}
}
}
}
Call fillMatrix(); method from Button1.start()
Add GridPane to MatrixPane in MatrixPane construcor
private GridPane pane1 = new GridPane();
public MatrixPane() {
getChildren().add(pane1);
}
This will work.
Well I checked your code and you are excessively using GridPane. First you have a class named MatrixPane which inherits Pane, but also this class has a property GridPane. Finally, you use GridPane once again to add MatrixPane!
So, what I did is to use composition, but first I change the start method
public void start(Stage primaryStage) {
GridPane pane = new GridPane();
MatrixPane Matrix = new MatrixPane();
//pane.getChildren().add(Matrix);
Matrix.fillmatrix();
Scene scene = new Scene(Matrix.getPane1(), 700, 500);
...
So here the scene is going to receive the data of pane1, this attribute has the values stored when fillmatrix was called.
Then I add the getter method in MatrixPane for the attribute pane1
class MatrixPane {
double HEIGHT = 500;
double WIDTH = 200;
private GridPane pane1 = new GridPane();
public GridPane getPane1() {
return pane1;
}
...

Categories

Resources