JavaFX bounds issue? - javafx

So, using JAVAfx, which I painfully downloaded, I need to be able to move this ball, but not let it leave the bounds. Right now, I have it all set up, it just leaves the area. What am i doing wrong? Any tutors don't know anything about JavaFX, so I'm having trouble getting past this. Right now I tried to work it out, but keep getting this error Cannot Make a Static Reference to Bound
'''
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.geometry.Bounds;
public class MoveBall extends Application {
// create buttons
Button left = new Button();
Button right = new Button();
Button up = new Button();
Button down = new Button();
Circle ball = new Circle(30, 30, 30);
// action event class
EventHandler<ActionEvent> event = new EventHandler<ActionEvent>() {
// handle them
#Override
public void handle(ActionEvent event) {
// movement of ball
if (event.getSource().equals(left) && ball.getLayoutX() >= (Bounds.getMaxX() + ball.getRadius())) {
ball.setCenterX(ball.getCenterX() - 5);
}
if (event.getSource().equals(right)) {
ball.setCenterX(ball.getCenterX() + 5);
}
if (event.getSource().equals(up)) {
ball.setCenterY(ball.getCenterY() - 5);
}
if (event.getSource().equals(down) && ball.getCenterY() < 400)) {
ball.setCenterY(ball.getCenterY() + 5);
}
}
};
// main method
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Ball Movement");
ball.setStroke(Color.BLACK);
ball.setFill(null);
// button location
left.setLayoutX(100);
left.setLayoutY(210);
left.setText("Left");
// button event
left.setOnAction(event);
// similar for all button
right.setLayoutX(150);
right.setLayoutY(210);
right.setText("Right");
right.setOnAction(event);
// button location
up.setLayoutX(200);
up.setLayoutY(210);
up.setText("Up");
// button event
up.setOnAction(event);
// similar for all button
down.setLayoutX(250);
down.setLayoutY(210);
down.setText("Down");
down.setOnAction(event);
Group root = new Group();
// add to a group
root.getChildren().add(left);
root.getChildren().add(right);
root.getChildren().add(up);
root.getChildren().add(down);
root.getChildren().add(ball);
primaryStage.setScene(new Scene(root, 400, 250, Color.WHITE));
// show the scene
primaryStage.show();
}
}
'''

Related

Issues with JavaFX Translate

I have this sample:
package bit.fxtest2;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class TransformTest2 extends Application {
#Override
public void start(Stage stage) {
stage.setTitle("TransformTest2");
var bp = new BorderPane();
bp.setCenter(new DragPane());
var scene = new Scene(bp, 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
private static class DragPane extends Pane {
ObjectProperty<Transform> xform = new SimpleObjectProperty<>(new Translate(0, 0));
public DragPane() {
ObjectProperty<Point2D> mouseDown = new SimpleObjectProperty<>();
setOnMousePressed(e -> {
var mousePress = new Point2D(e.getX(), e.getY());
mouseDown.set(mousePress);
});
setOnMouseDragged(e -> {
var dragPoint = new Point2D(e.getX(), e.getY());
var delta = dragPoint.subtract(mouseDown.get());
var t = new Translate(delta.getX(), delta.getY());
xform.set(xform.get().createConcatenation(t));
mouseDown.set(dragPoint);
System.out.println("mp = " + mouseDown);
updateTransform();
});
populate();
updateTransform();
}
private void populate() {
ObservableList<Node> children = getChildren();
children.clear();
children.add(new Line(0, 0, 200, 0));
children.add(new Line(200, 0, 200, 200));
children.add(new Line(200, 200, 0, 200));
children.add(new Line(0, 200, 0, 0));
}
private void updateTransform() {
ObservableList<Transform> transforms = getTransforms();
transforms.clear();
transforms.add(xform.get());
}
}
}
If you run the code, two things happen.
First, as you start dragging, the box drags, but it starts getting very jerky, and bounces back and forth. If you print out the mouse motions they move back and forth.
Second, after you've dragged the box, say, down and to the right, you'll notice that you can no longer drag it in the upper left area of the window.
This is because the Translate is affecting the Pane itself, not necessarily the contents of the Pane. Since the OnMouse handlers are on the Pane itself, and the Pane is no longer in the upper left area, no handlers are called.
So, two questions.
First, why the jerky behavior?
Second, how can I apply Transforms (not just translate) to the children of a pane, and not the pane itself?
The answer to the first question (the jerkiness) is that it's because your calculations for the transform are incorrect.
When the dragging is processed, the pane is translated by the amount that was dragged. This leaves the coordinates of the mouse relative to the pane as being the same as they were when the mouse was first pressed.
For example, suppose you click on the pane at (100,100), so mouseDown contains the value (100,100). You then drag it, so suppose when the drag event is processed the mouse has moved to (102,101) in the pane's coordinate system. Then delta will be (2,1), so the pane will be translated by (an additional) (2,1), after which the mouse will again be over the point (100,100) in the pane's coordinate system.
Therefore, the correct thing to do here is not to change the value of mouseDown.
Simply removing the line
mouseDown.set(dragPoint);
fixes that issue.
For the second issue: As long as the user starts the drag inside the actual pane, then it all works fine; this seems to be the natural thing to do.
But if you really want to be able to drag from anywhere in the window, you can place the nodes to be dragged in a Group and apply the translation to the group. Note that this time, because the Pane is not moving, you do need to update the mouseDown value:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class TransformTest2 extends Application {
#Override
public void start(Stage stage) {
stage.setTitle("TransformTest2");
var bp = new BorderPane();
bp.setCenter(new DragPane());
var scene = new Scene(bp, 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
private static class DragPane extends Pane {
ObjectProperty<Transform> xform = new SimpleObjectProperty<>(new Translate(0, 0));
Group group ;
public DragPane() {
ObjectProperty<Point2D> mouseDown = new SimpleObjectProperty<>();
group = new Group();
getChildren().add(group);
setOnMousePressed(e -> {
var mousePress = new Point2D(e.getX(), e.getY());
mouseDown.set(mousePress);
});
setOnMouseDragged(e -> {
var dragPoint = new Point2D(e.getX(), e.getY());
var delta = dragPoint.subtract(mouseDown.get());
var t = new Translate(delta.getX(), delta.getY());
xform.set(xform.get().createConcatenation(t));
mouseDown.set(dragPoint);
System.out.println("mp = " + mouseDown);
updateTransform();
});
populate();
updateTransform();
}
private void populate() {
ObservableList<Node> children = group.getChildren();
children.clear();
children.add(new Line(0, 0, 200, 0));
children.add(new Line(200, 0, 200, 200));
children.add(new Line(200, 200, 0, 200));
children.add(new Line(0, 200, 0, 0));
}
private void updateTransform() {
ObservableList<Transform> transforms = group.getTransforms();
transforms.clear();
transforms.add(xform.get());
}
}
}
If you don't want the additional node, you can achieve the same effect by handling the mouse events on the scene, and update the transforms for the pane.

Java FX nested event handler I want to block the parent handler when child handler is called

I have a fxml Mouse event handler method where every time I click a Pane a pop up dialog box appears on the screen asking for information. When OK is clicked on the dialog, a circle with text is added to a stack pane and the stack pane is then added to the pane where the user clicked.
However I am trying to implement a event handler where I can move the stack pane around by dragging the stack pane with the mouse. My event handler works but every time I finish dragging the stack pane the pop up dialog pops up. I do not want the pop up dialog to pop up when moving the circle how would I change my code to do this is there a way of blocking the pop up handler?
Thank you.
My Handler method:
#FXML
private void handleAddVertex(MouseEvent event) {
boolean okClicked = main.showAddVertexPopUp(this);
if(okClicked) {
String vertexText = "";
if(getSelectedDataChoice().equals("Integer")) {
vertexText = dataModel.getListOfIntVertices().get(dataModel.getListOfIntVertices().size() - 1).toString();
}else if(getSelectedDataChoice().equals("Double")){
vertexText = dataModel.getListOfDoubleVertices().get(dataModel.getListOfDoubleVertices().size() - 1).toString();
}else {
vertexText = dataModel.getListOfStringVertices().get(dataModel.getListOfStringVertices().size() - 1).toString();
}
EventHandler<MouseEvent> circleOnMousePressedEventHandler =
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
orgTranslateX = ((StackPane)(t.getSource())).getTranslateX();
orgTranslateY = ((StackPane)(t.getSource())).getTranslateY();
}
};
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler =
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
((StackPane)(t.getSource())).setTranslateX(newTranslateX);
((StackPane)(t.getSource())).setTranslateY(newTranslateY);
}
};
double x = event.getX();
double y = event.getY();
Circle vertex = new Circle(x, y, 20, Color.WHITE);
vertex.setStroke(Color.BLACK);
Text text = new Text (vertexText);
StackPane stack = new StackPane();
stack.getChildren().addAll(vertex, text);
stack.setLayoutX(x);
stack.setLayoutY(y);
stack.setOnMousePressed(circleOnMousePressedEventHandler);
stack.setOnMouseDragged(circleOnMouseDraggedEventHandler);
centerPane.getChildren().add(stack);
}
}
To stop an Event from propagating you use Event.consume().
Marks this Event as consumed. This stops its further propagation.
From your description, it appears handleAddVertex is a MOUSE_CLICKED handler. You'll have to add another EventHandler to the newly created StackPane that consumes MOUSE_CLICKED events.
stack.setOnMouseClicked(Event::consume);
This will stop the MOUSE_CLICKED event from bubbling up to the Node which has the handleAddVertex handler.
For more information on event processing in JavaFX, see JavaFX: Handling Events.
Here's a small example where you can see the difference between consuming and not consuming the event:
import java.util.function.Predicate;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
private CheckBox consumeClickEventsCheckBox;
#Override
public void start(Stage primaryStage) throws Exception {
consumeClickEventsCheckBox = new CheckBox("Consume click events");
consumeClickEventsCheckBox.setSelected(true);
HBox top = new HBox(consumeClickEventsCheckBox);
top.setPadding(new Insets(10));
top.setAlignment(Pos.CENTER);
Pane center = new Pane();
center.setBorder(new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, null, null)));
center.setOnMouseClicked(this::handleAddCircle);
Rectangle clip = new Rectangle();
clip.widthProperty().bind(center.widthProperty());
clip.heightProperty().bind(center.heightProperty());
center.setClip(clip);
BorderPane root = new BorderPane(center);
root.setTop(top);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private void handleAddCircle(MouseEvent event) {
event.consume();
Alert confirm = new Alert(AlertType.CONFIRMATION);
confirm.initOwner(((Node) event.getSource()).getScene().getWindow());
confirm.setHeaderText(null);
confirm.setContentText("Do you want to add a circle here?");
if (confirm.showAndWait().filter(Predicate.isEqual(ButtonType.OK)).isPresent()) {
Circle circle = new Circle(event.getX(), event.getY(), 25);
circle.setOnMousePressed(this::handleCirclePressed);
circle.setOnMouseDragged(this::handleCircleDragged);
circle.setOnMouseClicked(this::handleCircleClicked);
((Pane) event.getSource()).getChildren().add(circle);
}
}
private Point2D origin;
private void handleCirclePressed(MouseEvent event) {
event.consume();
origin = new Point2D(event.getX(), event.getY());
}
private void handleCircleDragged(MouseEvent event) {
event.consume();
Circle circle = (Circle) event.getSource();
circle.setTranslateX(circle.getTranslateX() + event.getX() - origin.getX());
circle.setTranslateY(circle.getTranslateY() + event.getY() - origin.getY());
}
/*
* Will consume the MOUSE_CLICKED event only if the CheckBox is selected. You can test
* the behavior of consuming the event by toggling the CheckBox.
*/
private void handleCircleClicked(MouseEvent event) {
if (consumeClickEventsCheckBox.isSelected()) {
event.consume();
}
}
}

JavaFX: ProgressBar with timeline; reset both if completed

I am building an application which is an exam. All the questions are shown on different screens, all with a progressbar showing how much time the user has left.
When the progressbar is full, the screen with another question is shown and the progressbar and timeline should be resetted.
When the time is up, the next screen is shown and the timeline resets, but the progressbar (shown in code as 'PRGB') remains full and it will not reset to an empty progressbar. This is my code:
public void timeBar() throws Exception{
Timeline timeline = new Timeline(
new KeyFrame(Duration.ONE, new KeyValue(PRGB.progressProperty(), 0)),
new KeyFrame(Duration.seconds(Main.time), e-> {
}, new KeyValue(PRGB.progressProperty(), 1))
);
timeline.setCycleCount(1);
timeline.play();
timeline.setOnFinished(event -> {
Main.setPane(questionNumber);
questionNumber++;
timeline.play();
//in here the progressbar has to be resetted
});
}
Update:
I have deleted my ProgressBar from SceneBuilder, and made a new one on which I then run the code below (with a few alterations taking by your suggestions). But now the progressbar does reset it self, but it does not show the progress: it stays empty.
public void timeBar() throws Exception{
Timeline timeline = new Timeline(
//I only use two keyframes instead of three
new KeyFrame(Duration.seconds(Main.time), e-> {
}, new KeyValue(PRGB.progressProperty(), 1))
);
timeline.setCycleCount(1);
timeline.play();
timeline.setOnFinished(event -> {
Main.setPane(questionNumber);
questionNumber++;
//The setProgress is added
PRGB.setProgress(0.0F);
timeline.play();
});
}
This can probably be done better. In this example, 3 seconds is given for each question with 1 second at the end of each question to load the next question. Code from here.
import java.util.concurrent.atomic.AtomicInteger;
import javafx.animation.KeyFrame;
import javafx.animation.PauseTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage stage)
{
Label lblCurrentQuestion = new Label();
ProgressBar prgb = new ProgressBar(0);
int numberOfQuestions = 5;//Number of questions
int timeForEachQuestion = 3;//3 second to do each questions
AtomicInteger currentProgressCounter = new AtomicInteger(0);
AtomicInteger currentQuestionCounter = new AtomicInteger(1);
Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), (event) -> {
if (currentProgressCounter.get() == timeForEachQuestion + 1) {
//Go to next question!
prgb.setProgress(0);
currentProgressCounter.set(0);
currentQuestionCounter.incrementAndGet();
}
lblCurrentQuestion.setText("Question " + currentQuestionCounter.get());
prgb.setProgress(currentProgressCounter.getAndIncrement() / (double) timeForEachQuestion);
}));
fiveSecondsWonder.setCycleCount(numberOfQuestions * (timeForEachQuestion + 1));
fiveSecondsWonder.play();
fiveSecondsWonder.setOnFinished(event -> {
PauseTransition wait = new PauseTransition(Duration.seconds(1));
wait.setOnFinished((e) -> {
/*YOUR METHOD*/
lblCurrentQuestion.setText("Quiz done!");
prgb.setProgress(0);
wait.playFromStart();
});
wait.play();
});
Scene scene = new Scene(new StackPane(new VBox(lblCurrentQuestion, prgb)), 500, 500);
stage.setScene(scene);
stage.show();
}
}
You have a call to timeline.play() in your setOnFinished() call. Remove that call so that the progress bar doesn't get reset to full.
Also, you should reset your progress bar by doing progressBar.setProgress(0.0F); in the setOnFinished()

JavaFX 8 Changing the opacity of the stage does not work with StageStyle.TRANSPARENT (bug or my fault?)

I'm trying to build a FadeIn/Out animation on a window (stage). If the mouse moves into the stage it should fade in and if the mouse leaves it should fade out.
I created a Timeline that modifies the stage.opacityProperty() to achieve this. I ran into problems when I set the stage style transparent like this stage.initStyle(StageStyle.TRANSPARENT);. If I do so, the fading will not be visible. The Timeline plays the animation, but the opacity change will not be rendered by JavaFX. When setting the stageStyle to default, everything works fine and the window plus its decoration will fade in and out.
I want this effect to work in TRANSPARENT stage style so i tried the following:
I put a label onto the scene and change its textproperty in another Timeline. I now update the label text every 400msecs. If i do so, the opacity change will be rendered on every label-change.
This brings me to the conclusion, that modifying the opacity in TRANSPARENT stage style, will not result in a repaint of the stage.
Modifying the label text will result in repaint. Does this mean, that i cannot fade a stage in TRANSPARENT stage style, if the content does not change?
Is this a bug or am I doing something wrong?
I've made an SSCCE that reproduces the problem. If you remove the line stage.initStyle(StageStyle.TRANSPARENT); the fadeIn/out animation will run smoothly.
package de.schuette.jfx.stage_opacity_bug;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class FadeApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
private Label label;
#Override
public void start(Stage stage) {
if (stage == null)
throw new IllegalArgumentException("No stage was set.");
this.label = new Label("HALLO WELT");
Scene scene = new Scene(label, 300, 300);
scene.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) {
stage.close();
}
});
stage.setScene(scene);
stage.setOpacity(1);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setTitle("Opacity change does result in repaint when stage style is transparent.");
stage.setAlwaysOnTop(true);
stage.show();
Platform.runLater(() -> {
Timeline t = new Timeline(new KeyFrame(Duration.millis(0),
new KeyValue(stage.opacityProperty(), 1)), new KeyFrame(
Duration.millis(500), new KeyValue(stage.opacityProperty(),
0)));
t.setAutoReverse(true);
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
});
Platform.runLater(() -> {
Timeline t = new Timeline(new KeyFrame(Duration.millis(400), e -> {
label.textProperty().set(String.valueOf(Math.random()));
}));
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
});
}
}
I'm currtently working with
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Windows 7 x64 Professional
With the help of the JavaFX developer team I was able to find a workaround for this problem. Using a custom linear interpolator that changes the scene's fill property and immediately change it back to its original value will cause a repaint on the stage. This is done by the "bugFixInterpolator" in the code below:
package de.schuette.jfx.stage_opacity_bug;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class FadeApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
private Label label;
/*
* (non-Javadoc)
*
* #see javafx.application.Application#start(javafx.stage.Stage)
*/
#Override
public void start(Stage stage) {
if (stage == null)
throw new IllegalArgumentException("No stage was set.");
this.label = new Label("HELLO WORLD");
Scene scene = new Scene(label, 300, 300);
scene.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE) {
stage.close();
}
});
stage.setScene(scene);
stage.setOpacity(1);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setTitle("Opacity change does result in repaint when stage style is transparent.");
stage.setAlwaysOnTop(true);
stage.show();
Interpolator bugFixInterpolator = new Interpolator() {
#Override
protected double curve(double t) {
Paint fill = scene.getFill();
scene.setFill(Color.RED);
scene.setFill(fill);
return t;
}
#Override
public String toString() {
return "Interpolator.LINEAR";
}
};
Timeline t = new Timeline(new KeyFrame(Duration.millis(0),
new KeyValue(stage.opacityProperty(), 1, bugFixInterpolator)),
new KeyFrame(Duration.millis(500), new KeyValue(stage
.opacityProperty(), 0, bugFixInterpolator)));
t.setAutoReverse(true);
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
t = new Timeline(new KeyFrame(Duration.millis(400), e -> {
label.textProperty().set(String.valueOf(Math.random()));
}));
t.setCycleCount(Timeline.INDEFINITE);
t.playFromStart();
}
}

Refresh label in JAVAFX

So i have this code in which i'm trying to do a scene for my game. I'm really a beginner in a Java and especially JAVAFX world and doing this as a school project (Once again..) and trying to figure out a way to refresh my label.
I've found one URL from stackoverflow, which was a similar issue but didn't work for my problem (or was i too stupid to make it work..) anyways, link is here
This is the part where the problem occurs - i have a text box, from which you have to enter player names. Every time a user inputs player name the label shows how many names have been entered, according to the nimedlist.size() which holds the names inside.
Label mängijate_arv = new Label("Mängijaid on sisestatud: "+nimedlist.size());
// if we press enter, program will read the name
nimiTekst.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
}
}
}
});
startBox.getChildren().addAll(sisestus_mängijad, nimiTekst, mängijate_arv,
startButton2);
This is the whole code:
package application;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Baila2 extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(final Stage peaLava) {
final Group root = new Group();
final BorderPane piir = new BorderPane();
piir.setPrefSize(960, 540);
final Text tekst = new Text();
tekst.setText("JOOMISMÄNG");
tekst.setFont(Font.font("Verdana", 40));
VBox nupudAlam = new VBox();
Button startButton = new Button("Start");
nupudAlam.setSpacing(20);
Button reeglidButton = new Button("Reeglid");
nupudAlam.setAlignment(Pos.CENTER);
startButton.setId("btn3");
startButton.setMaxWidth(160);
reeglidButton.setMaxWidth(160);
reeglidButton.setId("btn3");
nupudAlam.getChildren().addAll(startButton, reeglidButton);
piir.setTop(tekst);
piir.setAlignment(tekst, Pos.CENTER);
piir.setCenter(nupudAlam);
root.getChildren().add(piir);
// START NUPP TÖÖ
startButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(final ActionEvent event) {
final ArrayList nimedlist = new ArrayList();
piir.setVisible(false);
final BorderPane startPiir = new BorderPane();
final VBox startBox = new VBox();
Button startButton2 = new Button("ALUSTA!");
startButton2.setId("btn2");
startButton2.setMaxWidth(160);
startPiir.setPrefSize(960, 540);
final Text startTekst = new Text();
startTekst.setText("JOOMISMÄNG");
startTekst.setFont(Font.font("Verdana", 40));
startPiir.setTop(startTekst);
startPiir.setAlignment(startTekst, Pos.CENTER);
final TextField nimiTekst = new TextField();
nimiTekst.setText(null);
nimiTekst.setMaxWidth(250);
Label sisestus_mängijad = new Label(
"Sisesta 3-9 mängija nimed:");
sisestus_mängijad.setFont(Font.font("Verdana", 30));
sisestus_mängijad.setTextFill(Color.ORANGE);
Label mängijate_arv = new Label("Mängijaid on sisestatud: "+nimedlist.size());
// kui vajutatakse ENTER,siis loeme nime
nimiTekst.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
}
}
}
});
startBox.getChildren().addAll(sisestus_mängijad, nimiTekst, mängijate_arv,
startButton2);
startBox.setSpacing(20);
startBox.setAlignment(Pos.CENTER);
startPiir.setCenter(startBox);
root.getChildren().add(startPiir);
}
});
// aknasündmuse lisamine
peaLava.setOnHiding(new EventHandler<WindowEvent>() {
public void handle(WindowEvent event) {
// luuakse teine lava
final Stage kusimus = new Stage();
// küsimuse ja kahe nupu loomine
Label label = new Label("Kas tõesti tahad kinni panna?");
Button okButton = new Button("Jah");
Button cancelButton = new Button("Ei");
// sündmuse lisamine nupule Jah
okButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
kusimus.hide();
}
});
// sündmuse lisamine nupule Ei
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
peaLava.show();
kusimus.hide();
}
});
// nuppude grupeerimine
FlowPane pane = new FlowPane(10, 10);
pane.setAlignment(Pos.CENTER);
pane.getChildren().addAll(okButton, cancelButton);
// küsimuse ja nuppude gruppi paigutamine
VBox vBox = new VBox(10);
vBox.setAlignment(Pos.CENTER);
vBox.getChildren().addAll(label, pane);
// stseeni loomine ja näitamine
Scene stseen2 = new Scene(vBox);
kusimus.setScene(stseen2);
kusimus.show();
}
}); // siin lõpeb aknasündmuse kirjeldus
// stseeni loomine ja näitamine
Scene stseen1 = new Scene(root, 960, 540, Color.GREEN);
peaLava.setTitle("BAILA 2.0");
// peaLava.setResizable(false);
stseen1.getStylesheets().add(
getClass().getClassLoader().getResource("test.css")
.toExternalForm());
peaLava.setScene(stseen1);
peaLava.show();
}
}
Sorry about Estonian language, it's compulsory in our school to write in our native language..
You can just do
nimiTekst.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
mängijate_arv.setText("Mängijaid on sisestatud: "+nimedlist.size());
}
}
}
});
If you are not using Java 8 (you appear not to be, since you are implementing all the handlers the old, long way...), you will have to declare mängijate_arv as final:
final Label mängijate_arv = new Label("Mängijaid on sisestatud: "+nimedlist.size());
If you want to be extra cool with this, you can use bindings instead. You will have to make nimidlist an observable list:
final ObservableList<String> nimedlist = FXCollections.observableArrayList();
and then:
mängijate_arv.bind(Bindings.format("Mängijaid on sisestatud: %d", Bindings.size(nimedList)));
and don't put the mängijate_arv.setText(...) call in the handler. This solution is nicer in many ways, as if you remove items from the list (or add other items elsewhere in your code), then the label will still remain properly updated without any additional code.
One other thing: it's a bit better to use an action handler on the text field, instead of a low-level key event handler:
nimiTekst.setOnAction(new EventHandler<ActionEvent>() {
public void handle(final ActionEvent keyEvent) {
if (nimiTekst.getText() != null) {
nimedlist.add(nimiTekst.getText());
nimiTekst.setText(null);
mängijate_arv.setText("Mängijaid on sisestatud: "+nimedlist.size());
}
}
});
(Sorry if I mangled your variable names. My Estonian is a bit weak ;). Your school's policy is a good one, for what it's worth.)

Resources