Opening java file with button (javafx) [duplicate] - java

This question already has answers here:
JavaFX launch another application
(3 answers)
Closed 4 years ago.
I've got an app made in javafx and another class with menu in this project. In this menu I've got two buttons and one works (exit buuton) and I want buttonStart to open my Main class. How to launch it?
Button buttonStart = new Button("START GAME");
Button buttonExit = new Button("EXIT");
buttonExit.setOnMouseClicked(event -> System.exit(0));
My menu:
package pl.main;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Menu extends Application {
private BorderPane layout;
private Scene scene;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage window) throws Exception {
layout = new BorderPane();
scene = new Scene(layout, 720, 480);
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(10);
hbox.setStyle("-fx-background-color: #F9A825;");
Button buttonStart = new Button("START GAME");
buttonStart.setPrefSize(100, 20);
buttonStart.setStyle("-fx-background-color: #E65100;");
Button buttonExit = new Button("EXIT");
buttonExit.setPrefSize(100, 20);
buttonExit.setStyle("-fx-background-color: #E65100;");
buttonExit.setOnMouseClicked(event -> System.exit(0));
hbox.getChildren().addAll(buttonStart, buttonExit);
layout.setCenter(hbox);
window.setScene(scene);
window.show();
}
}
Class which I wanna launch:
package pl.main;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
public class Main extends Application {
private HashMap<KeyCode, Boolean> keys = new HashMap<KeyCode, Boolean>();
private ArrayList<Node> blocks = new ArrayList<Node>();
private Pane appRoot = new Pane();
private Pane gameRoot = new Pane();
private Pane uiRoot = new Pane();
private Node player;
private Point2D playerGoDown = new Point2D(0, 0);
private Point2D playerGoRight = new Point2D(0, 0);
private boolean canJump = true;
private int levelWidth;
private void initContent() {
Rectangle background = new Rectangle(720, 480);
// BackgroundFill(Color.WHITE);
levelWidth = LevelData.LEVEL1[0].length();
for (int i = 0; i < LevelData.LEVEL1.length; i++) {
String map = LevelData.LEVEL1[i] + LevelData.LEVEL2[i]+ LevelData.LEVEL1[i]+ LevelData.LEVEL2[i]+ LevelData.LEVEL1[i]+ LevelData.LEVEL2[i];
String line = map;
for (int j = 0; j < line.length(); j++) {
switch (line.charAt(j)) {
case '0':
break;
case '1':
Node block = createEntity(j * 30, i * 30, 30, 30, Color.ORANGE);
blocks.add(block);
break;
}
}
}
player = createEntity(0, 350, 40, 40, Color.YELLOW);
// a ????????????
player.translateXProperty().addListener((a, old, newValue) -> {
int offset = newValue.intValue();
//if (offset > 360 && offset < levelWidth - 360) {
gameRoot.setLayoutX(-(offset - 360));
//}
});
appRoot.getChildren().addAll(background, gameRoot, uiRoot);
}
private void update() {
if (isPressed(KeyCode.W) && player.getTranslateY() >= 0) {
jumpPlayer();
}
if (playerGoDown.getY() < 10) {
playerGoDown = playerGoDown.add(0, 1);
}
movePlayerY((int) playerGoDown.getY());
if (player.getTranslateX() <= levelWidth - 5) {
// movePlayerX(5);
movePlayerRight();
}
if (playerGoRight.getX() < 0) {
playerGoRight = playerGoRight.add(0, 1);
}
movePlayerX((int) playerGoRight.getX());
}
private void movePlayerX(int value) {
boolean movingRight = value > 0;
for (int i = 0; i < Math.abs(value); i++) {
for (Node block : blocks) {
if (player.getBoundsInParent().intersects(block.getBoundsInParent())) {
if (movingRight) {
if (player.getTranslateX() + 40 == block.getTranslateX()) {
return;
}
} else {
if (player.getTranslateX() == block.getTranslateX() + 60) {
return;
}
}
}
}
player.setTranslateX(player.getTranslateX() + (movingRight ? 1 : -1));
}
}
private void movePlayerY(int value) {
boolean movingDown = value > 0;
for (int i = 0; i < Math.abs(value); i++) {
for (Node block : blocks) {
if (player.getBoundsInParent().intersects(block.getBoundsInParent())) {
if (movingDown) {
if (player.getTranslateY() + 40 == block.getTranslateY()) {
canJump = true;
return;
}
} else {
if (player.getTranslateY() == block.getTranslateY() + 60) {
return;
}
}
}
}
player.setTranslateY(player.getTranslateY() + (movingDown ? 1 : -1));
}
}
private void jumpPlayer() {
if (canJump) {
playerGoDown = playerGoDown.add(0, -10);
canJump = false;
}
}
private void movePlayerRight() {
playerGoRight = playerGoRight.add(10, 0);
}
private Node createEntity(int x, int y, int w, int h, Color color) {
Rectangle entity = new Rectangle(w, h);
entity.setTranslateX(x);
entity.setTranslateY(y);
entity.setFill(color);
gameRoot.getChildren().add(entity);
return entity;
}
private boolean isPressed(KeyCode key) {
return keys.getOrDefault(key, false);
}
#Override
public void start(Stage primaryStage) throws Exception {
initContent();
Scene scene = new Scene(appRoot);
scene.setOnKeyPressed(event -> keys.put(event.getCode(), true));
scene.setOnKeyReleased(event -> keys.put(event.getCode(), false));
primaryStage.setTitle("Jetpack gameplay");
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setResizable(false);
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
update();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
}
In future I wanna change current Main.java into ordinary class because now I have two classes which works independently.

If you want to go on another page, you have to load the game scene.
Look at Scene class in JavaDoc.
Once you have your scene, you just have to add an ActionEvent to your button that will display your page.

Related

Conways Game of Life in JavaFX [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I try to add a method that let a cell get alive if it's clicked by the left mouse button but I don't know how. I tried to add a MouseClickListener but I couldn't connect it to my code. I'm new to JavaFx so it's pretty hard to overview all the functions and how to use them. Every other function of my code works perfectly so far. I hope that anyone of you know how to implement this method. Here is my code:
import com.google.gson.reflect.TypeToken;
import javafx.application.Application;
import javafx.animation.AnimationTimer;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.google.gson.Gson;
import javax.swing.*;
public class conway extends Application {
private static final int width = 500;
private static final int height = 500;
private static final int cellsize = 10;
private static Gson gson = new Gson();
private static class Life{
private final int reihe;
private final int zeile;
private Boolean[][] rules;
private int[][] grid;
private Random random=new Random();
private final GraphicsContext graphics;
public Life(int reihe, int zeile, GraphicsContext graphics){
this.reihe =reihe;
this.zeile =zeile;
this.graphics=graphics;
grid=new int[reihe][zeile];
this.rules = new Boolean[][]{{false, false, false, true, false, false, false, false, false, false},
{false, false, true, true, false, false, false, false, false, false}};
}
public void init(){
for(int i = 0; i< reihe; i++){
for(int j = 0; j< zeile; j++){
grid[i][j]=random.nextInt(2);
}
}
draw();
}
private void draw(){
graphics.setFill(Color.LAVENDER);
graphics.fillRect(0,0,width,height);
for(int i=0; i<grid.length;i++){
for(int j=0; j<grid[i].length; j++){
if(grid[i][j]==1){
graphics.setFill(Color.gray(0.5,0.5));
graphics.fillRect(i*cellsize, j*cellsize,cellsize,cellsize);
graphics.setFill(Color.PURPLE);
graphics.fillRect((i*cellsize)+1, (j*cellsize)+1, cellsize-2, cellsize-2);
}
else{
graphics.setFill(Color.gray(0.5,0.5));
graphics.fillRect(i*cellsize,j*cellsize,cellsize, cellsize);
graphics.setFill(Color.WHITE);
graphics.fillRect((i*cellsize)+1,(j*cellsize)+1,cellsize-2,cellsize-2);
}
}
}
}
private int countNeighbors(int i, int j){
int sum=0;
int iStart=i==0?0:-1;
int iEnd=i==grid.length - 1 ? 0:1;
int jStart=j==0?0:-1;
int jEnd=j==grid[0].length - 1 ? 0:1;
for (int k=iStart; k<=iEnd;k++){
for(int l=jStart;l<=jEnd;l++){
sum+=grid[i+k][l+j];
}
}
sum-=grid[i][j];
return sum;
}
public void tick(){
int[][] next=new int[reihe][zeile];
for(int i = 0; i< reihe; i++){
for(int j = 0; j< zeile; j++){
int nachbar= countNeighbors(i,j);
if(rules[grid[i][j]][nachbar] == true){
next[i][j] = 1;
}
}
}
grid=next;
draw();
}
public void safe() throws IOException {
JsonArray to_safe = new JsonArray();
Path pfad = Paths.get("C:\\Users\\Frodo\\IdeaProjects\\gameoflife\\only_safe_file_for_now.json");
if(Files.exists(pfad) == false) {
Files.createFile(pfad);
}
for(int i = 0; i<grid.length; i++){
JsonArray helper = new JsonArray();
for (int j = 0; j<grid[0].length; j++){
helper.add(grid[i][j]);
}
to_safe.add(helper);
}
Files.writeString(pfad, gson.toJson(to_safe));
}
public void load() throws IOException{
int saved_grid[][];
Path pfad = Paths.get("C:\\Users\\Frodo\\IdeaProjects\\gameoflife\\only_safe_file_for_now.json");
if(Files.exists(pfad) == false) {
return;
}
else {
String array_string = Files.readString(pfad);
saved_grid = gson.fromJson(array_string, new TypeToken<int[][]>(){}.getType());
if (saved_grid.length == 0) {
return;
}
}
grid = saved_grid;
draw();
}
}
public static void main(String[] args) {
launch();
}
public void start(Stage primaryStage) {
VBox root = new VBox(10);
Scene scene = new Scene(root, width, height + 100);
final Canvas canvas = new Canvas(width, height);
final boolean[] leftclick = new boolean[1];
leftclick[0] =false;
scene.setOnMouseClicked(e->{
if(e.getButton().equals(MouseButton.PRIMARY)){
if(leftclick[0]){
leftclick[0] =false;
}
else leftclick[0] =true;
}
});
Button reset = new Button("Reset");
Button step = new Button("Step");
Button run = new Button("Run");
Button stop = new Button("Stop");
Button safe_state = new Button("Safe");
Button load_button = new Button("Load");
Button terminate = new Button("Terminate");
root.getChildren().addAll(canvas, new HBox(10, reset, step, run, stop, safe_state, load_button, terminate));
primaryStage.setScene(scene);
primaryStage.show();
int rows = (int) Math.floor(height / cellsize);
int cols = (int) Math.floor(width / cellsize);
GraphicsContext graphics = canvas.getGraphicsContext2D();
Life life = new Life(rows, cols, graphics);
life.init();
AnimationTimer Animation = new AnimationTimer() {
private long lastUpdate=0;
#Override
public void handle(long now) {
if ((now - lastUpdate) >= TimeUnit.MILLISECONDS.toNanos(100)) {
life.tick();
lastUpdate = now;
}
}
};
reset.setOnAction(l -> life.init());
run.setOnAction(l -> Animation.start());
step.setOnAction(l -> life.tick());
stop.setOnAction(l -> Animation.stop());
safe_state.setOnAction(l-> {
try {
life.safe();
} catch (IOException e) {
e.printStackTrace();
}
});
load_button.setOnAction(l -> {
try {
life.load();
} catch (IOException e) {
e.printStackTrace();
}
});
terminate.setOnAction(l -> {
Stage stage = (Stage) terminate.getScene().getWindow();
stage.close();
});
}
}
Something in this direction should do the trick:
canvas.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
// is left click
if (t == MouseEvent.BUTTON1) {
grid[rows][cols] = 1;
draw();
}
}
});

JavaFX: Way to change value of programmatically created buttons

I'm trying to change the value of buttons which are created in a for loop. The value of the buttons must be saved in a hashmap which contains the id of the button and the value.
This is what I currently have:
private void createMap(int blocksX, int blocksY) {
// blocksX and blocksY are the amount of buttons to be placed
for (int x = 0; x < blocksX; x++) {
for (int y = 0; y < blocksY; y++) {
Button btn = new Button();
btn.setText("0");
btn.setPrefSize(32, 32);
btn.setLayoutX(32 * x);
btn.setLayoutY(32 * y);
btn.setId(String.valueOf(button_id));
map_list.put(button_id, 0);
button_id+=1;
items.getChildren().addAll(btn);
// If the user clicks a button, change the value of it...
btn.setOnAction(click -> {
if(btn.getText() == "0"){
changeButtonValue(Integer.parseInt(btn.getId()), 1);
btn.setText("1");
} else if(btn.getText() == "1") {
changeButtonValue(Integer.parseInt(btn.getId()), 0);
btn.setText("0");
}
});
}
}
}
But now the only item in the HashMap to be updated is the last created button. How can I change this so it will update all button values?
I completed the code to a runnable example. And I can't see your problem.
import java.util.HashMap;
import java.util.Map;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class FX01 extends Application {
public int button_id = 0;
public Map<Integer, Integer> map_list = new HashMap<>();
public AnchorPane items;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
items = new AnchorPane();
createMap(5, 5);
Scene scene = new Scene(items);
stage.setScene(scene);
stage.show();
}
private void createMap(int blocksX, int blocksY) {
// blocksX and blocksY are the amount of buttons to be placed
for (int x = 0; x < blocksX; x++) {
for (int y = 0; y < blocksY; y++) {
Button btn = new Button();
btn.setText("0");
btn.setPrefSize(32, 32);
btn.setLayoutX(32 * x);
btn.setLayoutY(32 * y);
btn.setId(String.valueOf(button_id));
map_list.put(button_id, 0);
button_id+=1;
items.getChildren().addAll(btn);
// If the user clicks a button, change the value of it...
btn.setOnAction(click -> {
if(btn.getText() == "0"){
changeButtonValue(Integer.parseInt(btn.getId()), 1);
btn.setText("1");
} else if(btn.getText() == "1") {
changeButtonValue(Integer.parseInt(btn.getId()), 0);
btn.setText("0");
}
});
}
}
}
private void changeButtonValue(int id, int value) {
map_list.put(id, value);
System.out.println("map_list: " + map_list);
}
}

Compilation probs Java Dialog Box

I am tasked with creating a DVD Collection application that displays Three columns and five row of stuff. I have written the code for this to work but keep on getting compilation errors( CANNOT FIND SYMBOL ==> class DVDColletionApp ) that I am having a hard time debugging.
Below is the code in question. Assistance would be greatly appreciated.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
public class DVDCollectionApp extends Application {
private DVDCollection model;
private ListView<String> tList;
private ListView<Integer> yList, lList;
public DVDCollectionApp() {
model = DVDCollection.example1();
}
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();
// Create the labels
HBox labelPane = new HBox();
labelPane.setPadding(new Insets(0,0,0,10));
labelPane.setSpacing(10);
Label label1 = new Label("Title");
label1.setMinSize(300,30);
label1.setPrefSize(2000,30);
Label label2 = new Label("Year");
label2.setMinSize(60,30);
label2.setPrefSize(60,30);
Label label3 = new Label("Length");
label3.setMinSize(60,30);
label3.setPrefSize(60,30);
labelPane.getChildren().addAll(label1, label2, label3);
borderPane.setTop(labelPane);
// Create the lists
GridPane listPane = new GridPane();
listPane.setPadding(new Insets(10));
listPane.setHgap(10);
tList = new ListView<String>();
listPane.add(tList, 0, 0);
tList.setMinSize(300,60);
tList.setPrefSize(2000,2000);
yList = new ListView<Integer>();
listPane.add(yList, 1, 0);
yList.setMinSize(60,60);
yList.setPrefSize(60,500);
lList = new ListView<Integer>();
listPane.add(lList, 2, 0);
lList.setMinSize(60,60);
lList.setPrefSize(60,500);
borderPane.setCenter(listPane);
// Create the button pane
HBox buttonPane = new HBox();
buttonPane.setPadding(new Insets(10));
buttonPane.setSpacing(10);
Button addButton = new Button("Add");
addButton.setStyle("-fx-font: 12 arial; -fx-base: rgb(0,100,0); -fx-text-fill: rgb(255,255,255);");
addButton.setPrefSize(90,30);
Button deleteButton = new Button("Delete");
deleteButton.setStyle("-fx-font: 12 arial; -fx-base: rgb(200,0,0); -fx-text-fill: rgb(255,255,255);");
deleteButton.setPrefSize(90,30);
Button statsButton = new Button("Stats");
statsButton.setStyle("-fx-font: 12 arial;");
statsButton.setPrefSize(90,30);
buttonPane.getChildren().addAll(addButton, deleteButton, statsButton);
borderPane.setBottom(buttonPane);
addButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent actionEvent) {
String title = javax.swing.JOptionPane.showInputDialog("Please enter the DVD Title: ");
String year = javax.swing.JOptionPane.showInputDialog("Please enter the DVD Year: ");
String length = javax.swing.JOptionPane.showInputDialog("Please enter the DVD Duration: ");
if ((title != null) && (year != null) && (length != null) && (title.length() > 0) && (year.length() > 0) && (length.length() > 0)) {
DVD d = new DVD(title, Integer.parseInt(year), Integer.parseInt(length));
model.add(d);
update(model, -1);
}
}
});
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent actionEvent) {
if (tList.getSelectionModel().getSelectedItem() != null) {
model.remove(tList.getSelectionModel().getSelectedItem());
update(model, -1);
}
}
});
tList.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent mouseEvent) {
model.setSelectedDVD(tList.getSelectionModel().getSelectedIndex());
update(model, tList.getSelectionModel().getSelectedIndex());
}
});
yList.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent mouseEvent) {
model.setSelectedDVD(yList.getSelectionModel().getSelectedIndex());
update(model, yList.getSelectionModel().getSelectedIndex());
}
});
lList.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent mouseEvent) {
model.setSelectedDVD(lList.getSelectionModel().getSelectedIndex());
update(model, lList.getSelectionModel().getSelectedIndex());
}
});
// Populate the lists
DVD[] theList = model.getDVDList();
String[] titles = new String[theList.length];
Integer[] years = new Integer[theList.length];
Integer[] lengths = new Integer[theList.length];
for (int i=0; i<theList.length; i++) {
titles[i] = theList[i].getTitle();
years[i] = theList[i].getYear();
lengths[i] = theList[i].getDuration();
}
tList.setItems(FXCollections.observableArrayList(titles));
yList.setItems(FXCollections.observableArrayList(years));
lList.setItems(FXCollections.observableArrayList(lengths));
primaryStage.setTitle("My DVD Collection");
primaryStage.setScene(new Scene(borderPane, 600, 300));
primaryStage.show();
}
// Update the view to reflect the model
public void update(DVDCollection model, int selectedDVD) {
DVD[] theList = model.getDVDList();
String[] titles = new String[theList.length];
Integer[] years = new Integer[theList.length];
Integer[] lengths = new Integer[theList.length];
for (int i=0; i<theList.length; i++) {
titles[i] = theList[i].getTitle();
years[i] = theList[i].getYear();
lengths[i] = theList[i].getDuration();
}
tList.setItems(FXCollections.observableArrayList(titles));
yList.setItems(FXCollections.observableArrayList(years));
lList.setItems(FXCollections.observableArrayList(lengths));
tList.getSelectionModel().select(selectedDVD);
yList.getSelectionModel().select(selectedDVD);
lList.getSelectionModel().select(selectedDVD);
}
public static void main(String[] args) {
launch(args);
}
}
Have you checked that java files are being compiled correctly?
The class DVDCollection doesn't seem to be imported, the DVDCollectionApp class must be in a .java of the same name and if you're using an IDE be sure to do a clean&build.

JavaFX draw Multi shape using multiple points

I have an arraylist of Point. I want to draw lines out the points. Here is what I have done.
for (int i = 0; i < arrPoint.size(); i++) {
Point startPoint = arrPoint.get(i);
Point endPoint = null;
if (i == arrPoint.size()) {
endPoint = arrPoint.get(0);
} else {
endPoint = arrPoint.get(i + 1);
}
Line line = new Line();
line.setStartX(startPoint.getCoordinateX());
line.setEndX(endPoint.getCoordinateX());
line.setStartY(startPoint.getCoordinateY());
line.setEndY(endPoint.getCoordinateY());
box.getChildren().add(line);
}
My Point cass is like
public class Point {
private double coordinateX;
private double coordinateY;
public Point(double coordinateX, double coordinateY) {
this.coordinateX = coordinateX;
this.coordinateY = coordinateY;
}
public void setCoordinateX(double coordinateX) {
this.coordinateX = coordinateX;
}
public void setCoordinateY(double coordinateY) {
this.coordinateY = coordinateY;
}
public double getCoordinateX() {
return coordinateX;
}
public double getCoordinateY() {
return coordinateY;
}
}
My code is displayed blank. I am new to JavaFx. Can I get any help?
You need to have the points before you can loop over the points to draw.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Draw line");
Group g = new Group();
Scene scene = new Scene(g, 550, 550,Color.web("0x0000FF",1.0));
ObservableList<Point> arrPoint = FXCollections.observableArrayList();
Point point1 = new Point(100, 200);
Point point2 = new Point(300, 400);
arrPoint.addAll(point1, point2);
for (int i = 0; i < arrPoint.size()-1; i++) {
Point startPoint = arrPoint.get(i);
Point endPoint = null;
if (i == arrPoint.size()) {
endPoint = arrPoint.get(0);
} else {
endPoint = arrPoint.get(i + 1);
}
Line line = new Line();
line.setStartX(startPoint.getCoordinateX());
line.setEndX(endPoint.getCoordinateX());
line.setStartY(startPoint.getCoordinateY());
line.setEndY(endPoint.getCoordinateY());
g.getChildren().add(line);
}
primaryStage.setScene(scene);
primaryStage.show();
}
}
I hope it can help you some.

JavaFX Pagination: setPageCount(int) calls the page factory again but does not show the page

Pre-story:
Ok so i had another problem with a custom pagination control and thought i had figure out why it didn't work as expected. However it still didn't work. So i created a min example to find out what was happening and if something else in my code was messing it up.
Problem
When setting the page count, the page factory gets called again, but the page that is being returned is not displayed. And I just can't figure out why.
Additional information for the code example:
If you comment out the setPageCount(4) the "initial page" will load. However when you do not comment it out, everything will only work if you switch pages or resize.
Edit: I was also wondering why the page factory is called at all if my current page is lower then the new page count. seems so weird - shouldn't it only call the page factory, if my new page count is lower then my current page index in addition to changing the current page index to 0?
Code - Minimal Working Example
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Pagination;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
Pagination pagination = new Pagination();
pagination.setPageFactory( index -> {
TilePane tilePane = new TilePane();
System.out.println("Trace: start: createTilePane");
System.out.println("TilePane: " + tilePane);
tilePane.widthProperty().addListener( observable -> {
System.out.println("WidthProperty-Listener");
System.out.println("tilePane: w: " + tilePane.getWidth() + "; h: " + tilePane.getHeight());
});
tilePane.heightProperty().addListener( observable -> {
System.out.println("HeightProperty-Listener");
System.out.println("tilePane: w: " + tilePane.getWidth() + "; h: " + tilePane.getHeight());
pagination.setPageCount(4);
});
tilePane.setOnMouseClicked( event -> {
System.out.println("Trace: onMouseClicked()");
System.out.println("tilePane: " + tilePane);
});
tilePane.setBackground(new Background(new BackgroundFill(Color.BEIGE, null, null)));
System.out.println("Trace: end: createTilePane");
return tilePane;
});
root.getChildren().add(pagination);
Scene scene = new Scene(root, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
}
You can do it like this. I'm using spinners to be more flexible in the demonstration:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Pagination;
import javafx.scene.control.Spinner;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TilesOnAGrid extends Application {
Pagination pagination = new Pagination();
Spinner<Integer> totalSpinner = new Spinner<Integer>(0, 30, 12);
Spinner<Integer> rowSpinner = new Spinner<Integer>(1, 5, 2);
Spinner<Integer> colSpinner = new Spinner<Integer>(1, 5, 2);
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
pagination.setPageFactory(new Callback<Integer, Node>() {
#Override
public Node call(Integer index) {
StackPane page = new StackPane();
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(0, 10, 0, 10));
int total = totalSpinner.getValue();
int rows = rowSpinner.getValue();
int cols = colSpinner.getValue();
int offset = rows * cols * index;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
offset++;
if (offset > total)
break;
StackPane container = new StackPane();
container.setStyle("-fx-background-color:lightgrey");
Label label = new Label("Item Nr. " + offset);
container.getChildren().add(label);
GridPane.setRowIndex(container, row);
GridPane.setColumnIndex(container, col);
GridPane.setHgrow(container, Priority.ALWAYS);
GridPane.setVgrow(container, Priority.ALWAYS);
grid.getChildren().add(container);
}
}
page.getChildren().add(grid);
return page;
}
});
totalSpinner.valueProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
rowSpinner.valueProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
colSpinner.valueProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
HBox toolbar = new HBox();
toolbar.setPadding(new Insets(5,5,5,5));
toolbar.setSpacing(5);
toolbar.getChildren().addAll(new Label("Total"), totalSpinner, new Label("Columns"), colSpinner, new Label("Rows"), rowSpinner);
root.setTop(toolbar);
root.setCenter(pagination);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
layoutItems();
}
private void layoutItems() {
int total = totalSpinner.getValue();
int rows = rowSpinner.getValue();
int cols = colSpinner.getValue();
int pages = (int) Math.ceil(total / (double) (rows * cols));
pagination.setPageCount(pages);
}
public static void main(String[] args) {
launch(args);
}
}
Regarding your code, you shouldn't change the page count in the factory. And if you need the changes depending on width / height, you can add a listener to root
root.heightProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
root.widthProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
or whatever your pagination container is and calculate the rows / columns accordingly.
Edit
Here's an example which considers cell width and height when you click the "Use Resizing" checkbox, i. e. controls the pagination while you resize the parent. Changing rows/columns should work now as well. I'm sending a custom event to trigger an update.
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.Pagination;
import javafx.scene.control.Spinner;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TilesOnAGrid extends Application {
StackPane currentPageContainer = null;
Pagination pagination = new Pagination();
double minColWidth = 300;
double minRowHeight = 300;
Spinner<Integer> totalSpinner = new Spinner<Integer>(0, 30, 12);
Spinner<Integer> rowSpinner = new Spinner<Integer>(1, 5, 2);
Spinner<Integer> colSpinner = new Spinner<Integer>(1, 5, 2);
BorderPane root;
CheckBox useResizeCheckBox;
#Override
public void start(Stage primaryStage) throws Exception {
root = new BorderPane();
pagination.setPageFactory(new Callback<Integer, Node>() {
#Override
public Node call(Integer index) {
currentPageContainer = createPage(index);
currentPageContainer.addEventHandler(MyEvent.UPDATE, new MyEventHandler());
return currentPageContainer;
}
});
root.heightProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
root.widthProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
pagination.currentPageIndexProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
pagination.pageCountProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
totalSpinner.valueProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
rowSpinner.valueProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
colSpinner.valueProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> layoutItems());
Label totalLabel = new Label("Total");
Label rowsLabel = new Label("Rows");
Label columnsLabel = new Label("Columns");
useResizeCheckBox = new CheckBox("Use Resizing");
useResizeCheckBox.selectedProperty().addListener((ChangeListener<Boolean>) (observable, oldValue, newValue) -> {
rowSpinner.setVisible(!newValue);
colSpinner.setVisible(!newValue);
rowsLabel.setVisible(!newValue);
columnsLabel.setVisible(!newValue);
layoutItems();
});
HBox toolbar = new HBox();
toolbar.setPadding(new Insets(5, 5, 5, 5));
toolbar.setSpacing(5);
toolbar.getChildren().addAll(useResizeCheckBox, totalLabel, totalSpinner, columnsLabel, colSpinner, rowsLabel, rowSpinner);
root.setTop(toolbar);
root.setCenter(pagination);
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
layoutItems();
}
public int getRows() {
if (useResizeCheckBox.isSelected()) {
return (int) Math.ceil(root.getBoundsInParent().getHeight() / minRowHeight);
} else {
return rowSpinner.getValue();
}
}
public int getCols() {
if (useResizeCheckBox.isSelected()) {
return (int) Math.ceil(root.getBoundsInParent().getWidth() / minColWidth);
} else {
return colSpinner.getValue();
}
}
private void layoutItems() {
int total = totalSpinner.getValue();
int rows = getRows();
int cols = getCols();
int pages = (int) Math.ceil(total / (double) (rows * cols));
pagination.setPageCount(pages);
if (currentPageContainer != null) {
MyEvent myEvent = new MyEvent(pagination.getCurrentPageIndex());
currentPageContainer.fireEvent(myEvent);
}
}
public StackPane createPage(Integer index) {
StackPane page = new StackPane();
page.getChildren().setAll(getGrid(index));
return page;
}
public GridPane getGrid(Integer index) {
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(0, 10, 0, 10));
int total = totalSpinner.getValue();
int rows = getRows();
int cols = getCols();
int offset = rows * cols * index;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
offset++;
StackPane container = new StackPane();
Label label;
if (offset <= total) {
container.setStyle("-fx-background-color:lightgrey");
label = new Label("Item Nr. " + offset);
} else {
label = new Label("");
}
container.getChildren().add(label);
GridPane.setRowIndex(container, row);
GridPane.setColumnIndex(container, col);
GridPane.setHgrow(container, Priority.ALWAYS);
GridPane.setVgrow(container, Priority.ALWAYS);
grid.getChildren().add(container);
}
}
return grid;
}
static class MyEvent extends Event {
public static final EventType<MyEvent> UPDATE = new EventType<>(Event.ANY, "UPDATE");
int index = 1;
public MyEvent(int index) {
super(UPDATE);
this.index = index;
}
public int getIndex() {
return index;
}
}
private class MyEventHandler implements EventHandler<MyEvent> {
#Override
public void handle(MyEvent event) {
currentPageContainer.getChildren().setAll(getGrid(event.getIndex()));
}
}
public static void main(String[] args) {
launch(args);
}
}
I "just" had to use Platform.runlater to set the pagination and rethink the flow of the whole thing. There is still some optimisation to be done, but the core problem of the question is answered.
This is the solution:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Pagination;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
private static final double CELL_HEIGHT = 60;
private static final double CELL_WIDTH = 100;
private static final double CELL_H_GAP = 10;
private static final double CELL_V_GAP = 10;
private static final int ITEM_COUNT = 100;
private Pagination pagination;
private int itemCount; // Count of items that fit on a page
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
pagination = new Pagination();
pagination.setPageFactory(this::pageFactory);
root.getChildren().add(pagination);
Scene scene = new Scene(root, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
private StackPane pageFactory( int pageIndex ) {
TilePane page = new TilePane();
StackPane pageContainer = new StackPane(page);
pageContainer.setAlignment(Pos.CENTER);
initPage(page);
addListeners(pageContainer, page);
fillPage(page, pageIndex);
return pageContainer;
}
private void initPage( TilePane page ) {
page.setHgap(CELL_H_GAP);
page.setVgap(CELL_V_GAP);
page.setBackground(new Background(new BackgroundFill(Color.BEIGE, null, null)));
}
private void addListeners ( StackPane pageContainer, TilePane page) {
pageContainer.heightProperty().addListener( observable -> {
if (pageContainer.getWidth() != 0 && pageContainer.getHeight() != 0) {
onResize(pageContainer, page);
}
});
pageContainer.widthProperty().addListener( observable -> {
if (pageContainer.getWidth() != 0 && pageContainer.getHeight() != 0) {
onResize(pageContainer, page);
}
});
}
private void onResize ( StackPane pageContainer, TilePane page ) {
int itemCountHorizontal = 1;
int itemCountVertical = 1;
int itemCount;
int pageCount;
itemCountHorizontal += ( pageContainer.getWidth() - CELL_WIDTH - 1 ) / ( CELL_WIDTH + CELL_H_GAP );
itemCountVertical += (pageContainer.getHeight() - CELL_HEIGHT - 1 ) / ( CELL_HEIGHT + CELL_V_GAP );
itemCount = itemCountHorizontal * itemCountVertical;
itemCount = ( itemCount == 0 ) ? 1 : itemCount;
pageCount = ITEM_COUNT / itemCount + 1;
page.setMinWidth( (CELL_WIDTH * itemCountHorizontal) + (CELL_H_GAP * (itemCountHorizontal-1)) );
page.setMaxWidth( (CELL_WIDTH * itemCountHorizontal) + (CELL_H_GAP * (itemCountHorizontal-1)) );
page.setMinHeight( (CELL_HEIGHT * itemCountVertical) + (CELL_V_GAP * (itemCountVertical-1)) );
page.setMaxHeight( (CELL_HEIGHT * itemCountVertical) + (CELL_V_GAP * (itemCountVertical-1)) );
if ( pagination.getPageCount() != pageCount ) {
Platform.runLater( () -> {
pagination.setPageCount(pageCount);
});
} else if ( this.itemCount != itemCount ){
// If item count changed, rebuild the page
this.itemCount = itemCount;
page.getChildren().clear();
fillPage(page, pagination.getCurrentPageIndex());
}
}
private void fillPage ( TilePane page, int pageIndex ) {
int startIndex = pageIndex * itemCount;
int endIndex = Math.min( ITEM_COUNT, startIndex+itemCount );
for ( int i = startIndex; i < endIndex; i++ ) {
page.getChildren().add(cellFactory("C" + (i+1)));
}
}
private Pane cellFactory( String cellText ) {
StackPane cell = new StackPane();
cell.setMaxHeight(CELL_HEIGHT);
cell.setMinHeight(CELL_HEIGHT);
cell.setMaxWidth(CELL_WIDTH);
cell.setMinWidth(CELL_WIDTH);
cell.setAlignment(Pos.CENTER);
cell.setBackground(new Background(new BackgroundFill(Color.LIGHTGRAY, null, null)));
cell.getChildren().add(new Label(cellText));
return cell;
}
}

Categories