How to display progressbar 0 to value - javafx

i want to show result 80 percent when i got result.(start 0 to myresult=80)
but my progressbar is show result 0 until 100 (max of procress bar)
#FXML
private ProgressBar progress;
#Override
public void initialize(URL url, ResourceBundle rb) {
double percent = 0.8;
progress.setProgress(percent);
progress.progressProperty().bind(task.progressProperty());
Thread th = new Thread(task);
th.start();
// TODOs
}
public Task<Void> task = new Task<Void>() {
#Override
public Void call() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
System.out.println(i + 1);
updateProgress(i + 1, 10);
}
return null;
}
};
thank you for comment

Instead of binding to the progress property of the task, bind to the progress property multiplied by 0.8. This way you convert the [0, 1] range of the task progress to range [0, 0.8]:
progress.progressProperty().bind(task.progressProperty().multiply(0.8));

Related

How to use Javafx and scenebuilder to draw on canvas (Group element)

i am new to scenebuilder and fx and need some help.
I have the class Puffer , TestMain and MainViewController.
I tried to paint on the canvas and it worked.I tried Puffer and it worked too.
Now I wanted to use scenebuilder and have my problems.I would like to draw the Group from Puffer on the canvas with a button and don't know what's the best solution.I already tried to modify Puffer without any result.
public class Puffer {
Group root = new Group();
public void draw() {
for (int x = 0; x < 800; x++) {
for (int y = 0; y < 600; y++) {
Complex z0 = new Complex(0.11, 0.123); //!!!!!!!!!!!!! under 1
Complex c = new Complex(x / 400.0 - 2, 1 - y / 400.0);
if (isBounded(iterate(z0, c))) {
drawPoint(x, y, root);
}
}
}
// primaryStage.setScene(new Scene(root, 800, 600));
// primaryStage.show();
}
public void drawPoint(int x, int y, Group root) {
int max = 255;
int min = 0;
int range = max - min + 1;
Line line = new Line(x, y, x, y);
// line.setStroke(Color.rgb((int)(Math.random() * range) + min,(int)(Math.random() * range) + min,(int)(Math.random() * range) + min));
root.getChildren().add(line);
}
public Complex iterate(Complex z0, Complex c) {
Complex zn = z0;
for (int i = 0; i < 20; i++) {
zn.square().add(c);
}
return zn;
}
public boolean isBounded(Complex zn) {
return zn.module() < 2;
}
public class MainViewController {
#FXML
Canvas canvas;
// Event Listener on Button.onAction
#FXML
public void btnOkClicked(ActionEvent event) {
System.out.println("Test");
}
#FXML
public void drawCanvas(){
// GraphicsContext gc = canvas.getGraphicsContext2D();
// gc.setLineWidth(3);
// gc.setStroke(Color.BLACK);
// System.out.println("drawCanvas");
//
// try {
// canvas.setOnMousePressed(event -> {
// System.out.println("Mouse click");
// gc.beginPath();
// gc.lineTo(event.getSceneX(), event.getSceneY());
// gc.stroke();
// });
//
// canvas.setOnMouseDragged(event -> {
// System.out.println("Mouse dragged");
// gc.lineTo(event.getSceneX(), event.getSceneY());
// gc.stroke();
// });
// }catch (Exception e){
// System.out.println(e);
// System.exit(0);
// }
}
public class TestMain extends Application {
#Override
public void start(Stage s1) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("MainView.fxml"));
Scene scene = new Scene(root);
s1.setTitle("Test");
s1.setScene(scene);
s1.show();
}catch(Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}

JavaFX How to Handle Input With Very High Framerate?

I'm on Ubuntu 20.04 using OpenJavaFX. I want to have the user press the escape key to toggle the display of a menu. Due to the very high frame rate, I'm struggling to achieve this.
The simple program:
class
AutoScalingCanvas extends Region {
private final Canvas canvas;
public AutoScalingCanvas(double canvasWidth, double canvasHeight) {
this.canvas = new Canvas(canvasWidth, canvasHeight);
getChildren().add(canvas);
}
public GraphicsContext getGraphicsContext2D() {
return canvas.getGraphicsContext2D();
}
#Override
protected void layoutChildren() {
double x = getInsets().getLeft();
double y = getInsets().getTop();
double w = getWidth() - getInsets().getRight() - x;
double h = getHeight() - getInsets().getBottom() - y;
// preserve aspect ratio while also staying within the available space
double sf = Math.min(w / canvas.getWidth(), h / canvas.getHeight());
canvas.setScaleX(sf);
canvas.setScaleY(sf);
positionInArea(canvas, x, y, w, h, -1, HPos.CENTER, VPos.CENTER);
}
}
public class
Gui extends Application
{
long target_ns_per_frame = 1_000_000_00 / 60;
boolean in_menu;
boolean esc_down;
#Override
public void
start(Stage primary_stage) throws Exception
{
primary_stage.setTitle("GUI");
AutoScalingCanvas canvas = new AutoScalingCanvas(1280, 720);
Scene scene = new Scene(canvas);
scene.setFill(Color.BLACK);
primary_stage.setScene(scene);
GraphicsContext gc = canvas.getGraphicsContext2D();
scene.setOnKeyPressed(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
esc_down = (event.getCode() == KeyCode.ESCAPE);
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.ESCAPE)
{
esc_down = false;
}
}
});
new AnimationTimer()
{
#Override
public void
handle(long total_elapsed_time_ns)
{
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, 1280, 720);
if (esc_down)
{
in_menu = !in_menu;
}
if (in_menu)
{
gc.setFill(Color.BLUE);
gc.fillRect(300, 300, 200, 200);
}
else
{
gc.setFill(Color.RED);
gc.fillRect(100, 100, 100, 100);
}
long elapsed_time_ns = System.nanoTime() -
total_elapsed_time_ns;
if (elapsed_time_ns < target_ns_per_frame)
{
long time_remaining_ms = (target_ns_per_frame - elapsed_time_ns)
/ 1000;
try {
Thread.sleep(time_remaining_ms);
}
catch (InterruptedException e)
{
}
}
}
}.start();
primary_stage.show();
}
}
If run without Thread.sleep() the framerate is around 600fps. As a result, pressing the escape key once will be seen as down for a number of frames (due to the speed limit of my human finger) thereby triggering the toggle multiple times. This is obviously not intended. So, I tried to cap the framerate at 60fps. However, with the sleeping, the program runs very slow (perhaps I'm sleeping on the wrong thread?)
How best to keep track of the input to achieve this toggling behavior?
First, you should never block the FX Application Thread by calling Thread.sleep() on it. That will prevent the UI from being updated, or events being handled, until the sleep() is complete.
If the intention is simply that each time the user presses the ESCAPE key that the menu is toggled, then your code is way too complex. Simply toggle a flag indicating if the menu should be painted in the onReleased handler, and check the flag in AnimationTimer.handle():
public class Gui extends Application {
boolean inMenu;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("GUI");
AutoScalingCanvas canvas = new AutoScalingCanvas(1280, 720);
Scene scene = new Scene(canvas);
scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
GraphicsContext gc = canvas.getGraphicsContext2D();
scene.setOnKeyReleased(event -> {
if (event.getCode() == KeyCode.ESCAPE) {
inMenu = ! inMenu;
}
});
new AnimationTimer() {
#Override
public void handle(long now) {
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, 1280, 720);
if (inMenu) {
gc.setFill(Color.BLUE);
gc.fillRect(300, 300, 200, 200);
} else {
gc.setFill(Color.RED);
gc.fillRect(100, 100, 100, 100);
}
}
}.start();
primaryStage.show();
}
}
If you want to optimize repaints only to when they are needed, simply introduce another flag indicating a repaint is necessary:
public class Gui extends Application {
private boolean inMenu;
private boolean repaintRequested = true ;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("GUI");
AutoScalingCanvas canvas = new AutoScalingCanvas(1280, 720);
Scene scene = new Scene(canvas);
scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
GraphicsContext gc = canvas.getGraphicsContext2D();
scene.setOnKeyReleased(event -> {
if (event.getCode() == KeyCode.ESCAPE) {
inMenu = ! inMenu;
repaintRequested = true ;
}
});
new AnimationTimer() {
#Override
public void handle(long now) {
if (repaintRequested) {
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, 1280, 720);
if (inMenu) {
gc.setFill(Color.BLUE);
gc.fillRect(300, 300, 200, 200);
} else {
gc.setFill(Color.RED);
gc.fillRect(100, 100, 100, 100);
}
repaintRequested = false ;
}
}
}.start();
primaryStage.show();
}
}
I didn't try any of this, so I can only nudge you in a general direction.
You could add another boolean variable esc_handled you set to true at the end of your handle method. Then you can add one more check to the method if the event has already been handled and if it has, you skip the handling step.
The following code achieves this:
add variable
boolean in_menu;
boolean esc_down;
boolean esc_handled;
check for esc_handled (inside handle) and set event to handled
if (esc_down && !esc_handled)
{
in_menu = !in_menu;
esc_handled = true;
}
on release esc set esc_handled to false
scene.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.ESCAPE)
{
esc_down = false;
esc_handled = false;
}
}
});
It looks like you're using the animation timer to do some kind of sampling of the state of the in or out and the press/release of the escape key. You don't need to do that at all.
You're trying to turn the key press/release events into a state, which makes sense, but you simply need to toggle that state in the event handler. Since the show/hide action is in response to an event, you can just call the draw routine directly from the event. So then the event will toggle the state and call the screen redraw:
public class Gui extends Application {
boolean in_menu;
GraphicsContext gc;
#Override
public void start(Stage primary_stage) throws Exception {
primary_stage.setTitle("GUI");
AutoScalingCanvas canvas = new AutoScalingCanvas(1280, 720);
primary_stage.setScene(new Scene(canvas));
gc = canvas.getGraphicsContext2D();
showOrHideMenu();
new Scene(canvas).setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ESCAPE) {
in_menu = !in_menu;
showOrHideMenu();
}
});
primary_stage.show();
}
private void showOrHideMenu() {
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, 1280, 720);
if (in_menu) {
gc.setFill(Color.BLUE);
gc.fillRect(300, 300, 200, 200);
} else {
gc.setFill(Color.RED);
gc.fillRect(100, 100, 100, 100);
}
}
}
Alternatively (and this is probably more "JavaFX"), you can make the In/Out Menu state observable, and then put a change listener on the state to do the repaint:
public class Gui extends Application {
BooleanProperty in_menu = new SimpleBooleanProperty(false);
GraphicsContext gc;
#Override
public void start(Stage primary_stage) throws Exception {
primary_stage.setTitle("GUI");
AutoScalingCanvas canvas = new AutoScalingCanvas(1280, 720);
Scene scene = new Scene(canvas);
primary_stage.setScene(scene);
gc = canvas.getGraphicsContext2D();
showOrHideMenu(false);
scene.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ESCAPE) {
in_menu.set(!in_menu.get());
}
});
in_menu.addListener(((observable, oldValue, newValue) -> showOrHideMenu(newValue)));
primary_stage.show();
}
private void showOrHideMenu(boolean inMenu) {
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, 1280, 720);
if (inMenu) {
gc.setFill(Color.BLUE);
gc.fillRect(300, 300, 200, 200);
} else {
gc.setFill(Color.RED);
gc.fillRect(100, 100, 100, 100);
}
}
}

JavaFX bind layout property doesn't work for dynamically added node

In my program, in a service, I created a stopwatch (Label) that counts the time of loading data from DB.
Now, I want to pin the label to the appropriate table so I tried to use the bind method but it doesn't work.
Notice that I created in the FXML file test label, and it does work.
public class PutDataService extends Service {
CanvasTableView tableView;
Label labelTimer;
Timer timer;
public PutDataService(CanvasTableView canvasTableView) {
this.tableView = canvasTableView;
labelTimer = new Label("Time: ");
timer = new Timer();
Label testLabel = (Label) Controller.getInstance().getTarget().getAnchorPane().lookup("#testLabel");
testLabel.setManaged(false);
testLabel.layoutXProperty().bind(tableView.layoutXProperty());
testLabel.layoutYProperty().bind(tableView.layoutYProperty().subtract(20.0));
testLabel.toFront();
Platform.runLater(() -> {
Controller.getInstance().getTarget().getAnchorPane().getChildren().add(labelTimer);
labelTimer.setManaged(false);
labelTimer.layoutXProperty().bind(tableView.layoutXProperty());
labelTimer.layoutYProperty().bind(tableView.layoutYProperty().subtract(20.0));
labelTimer.toFront();
});
labelTimer.layoutXProperty().addListener((observableValue, number, t1) -> System.out.println(labelTimer.layoutXProperty().getValue()));//changed !
setOnSucceeded((EventHandler<WorkerStateEvent>) workerStateEvent -> {
//Unbind here
Controller.getInstance().getTarget().getAnchorPane().getChildren().remove(labelTimer);
timer.cancel();
timer.purge();
});
}
#Override
protected Task createTask() {
return new Task() {
#Override
protected Object call() throws Exception {
//Start the stop watch , counts every 1 sec
timer.schedule(new TimerTask() {
int i = 0;
#Override
public void run() {
Platform.runLater(() -> labelTimer.textProperty().setValue(getTimeMessage(i)));
i++;
}
}, 0, 1000);
tableView.putData();
return null;
}
};
}
}
What am I done wrong?

Relocation of an image after a detection of a collision

I have figured out how to detect the collision of the rectangle and the image but where I am having problems is when I call the method to relocate the image it does it like 10 times in a row then won't work again.
I am making my first game in JavaFX. Im trying to make a basic snake game but haven't been able to figure out what is wrong with relocating the food after the snake collides with it.
public class Main extends Application {
Stage window;
Scene mainScene;
private final int WIDTH = 500;
private final int HEIGHT = 500;
Timeline timeline;
private Direction action = Direction.RIGHT;
private Rectangle snakeHead;
private final int speed = 3;
private int xSpeed = 3;
private int ySpeed = 3;
private int snakeW = 20;
private int snakeH = 20;
private BoundingBox snakeBox;
private BoundingBox foodBox;
private ImageView food;
private Random rand = new Random();
private double foodX;
private double foodY;
enum Direction {
LEFT,RIGHT,UP,DOWN;
}
private Parent createContent(){
Pane root = new Pane();
//food = new Food();
food = new ImageView(new Image("resources/apple.png"));
food.setFitHeight(25);
food.setFitWidth(25);
food.setPreserveRatio(true);
newFood();
foodBox = new BoundingBox(foodX,foodY,20,20);
snakeHead = new Rectangle(snakeW,snakeH);
snakeHead.setTranslateX(200);
snakeHead.setTranslateY(200);
snakeBox = new BoundingBox(snakeHead.getTranslateX(),snakeHead.getTranslateY(),snakeW,snakeH);
timeline = new Timeline(new KeyFrame(Duration.millis(16), e-> {
//Snake movement
if(action == Direction.LEFT) {snakeHead.setTranslateX(snakeHead.getTranslateX() - xSpeed);}
if(action == Direction.RIGHT) {snakeHead.setTranslateX(snakeHead.getTranslateX() + xSpeed);}
if(action == Direction.UP) {snakeHead.setTranslateY(snakeHead.getTranslateY() - ySpeed);}
if(action == Direction.DOWN) {snakeHead.setTranslateY(snakeHead.getTranslateY() + ySpeed);}
//Stops snake at edges of screen
if(snakeHead.getTranslateX() <= 0){
xSpeed = 0;
if(action == Direction.RIGHT){xSpeed = speed;}
}
if(snakeHead.getTranslateX() >= WIDTH - snakeW){
xSpeed = 0;
if(action == Direction.LEFT){xSpeed = speed;}
}
if(snakeHead.getTranslateY() <= 0){
ySpeed = 0;
if(action == Direction.DOWN){ySpeed = speed;}
}
if(snakeHead.getTranslateY() >= HEIGHT - snakeH){
ySpeed = 0;
if(action == Direction.UP){ySpeed = speed;}
}
//TODO: Detect Collisions
if(foodBox.intersects(snakeHead.getTranslateX(),snakeHead.getTranslateY (),snakeW,snakeH)){
newFood();
System.out.println("Collision");
}
}));
timeline.setCycleCount(Timeline.INDEFINITE);
root.getChildren().addAll(snakeHead,food);
return root;
}
private void newFood() {
foodX = rand.nextInt(500);
foodY = rand.nextInt(500);
food.setTranslateX(foodX);
food.setTranslateY(foodY);
System.out.println("X " + foodX);
System.out.println("Y " + foodY);
}
private void startGame() {
timeline.play();
}
private void stopGame() {
timeline.stop();
}
#Override
public void start(Stage primaryStage) throws Exception{
window = primaryStage;
mainScene = new Scene(createContent(),WIDTH,HEIGHT);
mainScene.setOnKeyPressed(e-> {
switch(e.getCode()) {
case UP: action = Direction.UP; break;
case DOWN: action = Direction.DOWN; break;
case LEFT: action = Direction.LEFT; break;
case RIGHT: action = Direction.RIGHT; break;
}
});
window.setTitle("Snake");
window.setResizable(false);
window.setScene(mainScene);
window.show();
startGame();
}
public static void main(String[] args) {
launch(args);
}
}
What I'm looking for is when the rectangle hits the apple it relocates. I have been struggling with this for awhile and don't know what to do. Im a fairly new programmer still.
You can check for intersection of snake's and food's boundsInParent.
if(food.getBoundsInParent().intersects(snakeHead.getBoundsInParent())){
newFood();
System.out.println("Collision");
}

search a word by key enter

i have a problem with my searching method.
With this method, I can enter a word in the textfield and display the word in the textarea. However, this only happens once if i let it run. I need to expand it so, that every time I click on "enter," the program should continue with searching in the textarea. How can i do this?
And please give me code examples. i have only 2 days left for my presentation.
Thanks a lot for the helps
textfield.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
String text = textarea.getText();
Labeled errorText = null;
if (textfield.getText() != null && !textfield.getText().isEmpty()) {
index = textarea.getText().indexOf(textfield.getText());
textarea.getText();
if (index == -1) {
errorText.setText("Search key Not in the text");
} else {
// errorText.setText("Found");
textarea.selectRange(index, index + textfield.getLength());
}
}
}
}
});
There's an overloaded version of the indexOf method allowing you to search starting at a specific index. Keep track of the index of your last find and start searching from this position:
#Override
public void start(Stage primaryStage) throws Exception {
TextField textField = new TextField("foo");
TextArea textarea = new TextArea();
for (int i = 0; i < 10; i++) {
textarea.appendText("foo\nbarfoobarfoofoo\n");
}
textField.setOnAction(evt -> {
String searchText = textField.getText();
if (searchText.isEmpty()) {
return; // searching for empty text doesn't make sense
}
int index = textarea.getSelection().getEnd();
// in case of the first search, start at the beginning
// TODO: adjust condition/starting index according to needs
if (textarea.getSelection().getLength() == 0) {
index = 0;
}
// find next occurrence
int newStartIndex = textarea.getText().indexOf(searchText, index);
// mark occurrence
if (newStartIndex >= 0) {
textarea.selectRange(newStartIndex, newStartIndex + searchText.length());
}
});
Scene scene = new Scene(new VBox(textField, textarea));
primaryStage.setScene(scene);
primaryStage.show();
}
Edit
If you are not satisfied with searching the element after the selection ( or after the cursor, if there is no range selected), you could save the data of the end of the last match:
#Override
public void start(Stage primaryStage) throws Exception {
TextField textField = new TextField("foo");
TextArea textarea = new TextArea();
for (int i = 0; i < 10; i++) {
textarea.appendText("foo\nbarfoobarfoofoo\n");
}
class SearchHandler implements EventHandler<ActionEvent> {
int index = 0;
#Override
public void handle(ActionEvent event) {
String searchText = textField.getText();
String fullText = textarea.getText();
if (index + searchText.length() > fullText.length()) {
// no more matches possible
// TODO: notify user
return;
}
// find next occurrence
int newStartIndex = textarea.getText().indexOf(searchText, index);
// mark occurrence
if (newStartIndex >= 0) {
index = newStartIndex + searchText.length();
textarea.selectRange(newStartIndex, index);
} else {
index = fullText.length();
// TODO: notify user
}
}
}
SearchHandler handler = new SearchHandler();
textField.setOnAction(handler);
// reset index to search from start when changing the text of the TextField
textField.textProperty().addListener((o, oldValue, newValue) -> handler.index = 0);
Scene scene = new Scene(new VBox(textField, textarea));
primaryStage.setScene(scene);
primaryStage.show();
}

Resources