position Shapes on a canvas in JavaFX - java

I create Shape and I need to position on a Canvas
Class Square to draw a square and insert into a canvas position
public class Square{
//calculate the position of the rand column to
//draw and insert in the position of the canvas
public void drawSquare(int posX, int posY, GraphicsContext gc) {
//Square Shadow
//gc.rect(posX, posY, w, h);
gc.rect(posX + 1, posY + 53, 50, 50);
gc.fill();
gc.beginPath();
//Square
gc.beginPath();
gc.setFill(Color.WHITE);
gc.setStroke(Color.BLACK);
gc.setLineWidth(2);
//gc.rect(posX, posY, w, h);
gc.rect(posX + 1, posY + 53, 48, 48);
gc.fill();
gc.stroke();
}
}
New Canvas instance with height = 450 and width = 600
Canvas canvas = new Canvas();
canvas.setHeight(450);
canvas.setWidth(600);
and GraphicsContext to draw square
GraphicsContext gc = canvas.getGraphicsContext2D();
with this loop, draw 4 rows and 6 columns with square in canvas,
and my doubt is how to calculate the position of the line and column to draw square and insert in the position of the canvas when I call pieces.drawSquare(i, j, gc);, and method drawSquare creates the shape but the doubt is how to position them if it is more than one shape
for (int i = 0; i < 4; i++) { //4 rows
for (int j = 0; j < 6; i++) { //6 columns
Piece pieces = new Piece();
pieces.drawSquare(i, j, gc);
}
this image is the example,
and the objective is to fill in 4 rows and 6 columns
I have already thought about dividing the size and width of Canvas with the size and width of the shape but it is not working, maybe can have another solution

I think this can get you jump starting
public class Main extends Application {
private SimpleIntegerProperty rowProperty = new SimpleIntegerProperty(4); //default
private SimpleIntegerProperty columnProperty = new SimpleIntegerProperty(6);//default
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
root.setPadding(new Insets(5));
HBox top;
TextField rowField = new TextField();
rowField.setMaxWidth(60);
rowField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
try{ rowProperty.setValue(Integer.valueOf(newValue));}catch(NumberFormatException e){}
}
});
TextField colField = new TextField();
colField.setMaxWidth(60);
colField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
try{ columnProperty.setValue(Integer.valueOf(newValue));}catch(NumberFormatException e){}
}
});
top = new HBox(10,new Label("ROW FIELD"),rowField, new Label("COLUMN FIELD"),colField);
top.setAlignment(Pos.CENTER);
root.setStyle("-fx-background-color: white;");
root.setTop(top);
////////////////////////////////////////////////////////////////////////////////////
Canvas canvas = new Canvas(500,400);
canvas.getGraphicsContext2D().setFill(Color.BLACK);
canvas.getGraphicsContext2D().setStroke(Color.GOLD);
ChangeListener<Number> chan = new ChangeListener<Number>() {
int space = 2;
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
///i will draw here
canvas.getGraphicsContext2D().clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
int rectW = (int) canvas.getWidth();
rectW = rectW/columnProperty.intValue();
int rectH = (int) canvas.getHeight();
rectH = rectH/rowProperty.intValue();
System.out.println(rectW);
System.out.println(rectH);
for(int k = 0; k < canvas.getHeight()/rectH; k++){
for(int i =0; i< canvas.getWidth()/rectW; i++){
canvas.getGraphicsContext2D().fillRect((i*rectW) + (i*space),
(k*rectH) + (k*space),
rectW, rectH);
}
}
}
};
rowProperty.addListener(chan);
columnProperty.addListener(chan);
//////////////////////////////////////////////////////////////////////////////////////////
root.setCenter(canvas);
Label l = new Label("ENTER NUMBERS TO FIELDS TO SEE IT");
l.setStyle("-fx-background-color: blueviolet; -fx-text-fill: white;");
l.setPrefWidth(Double.MAX_VALUE);
l.setAlignment(Pos.CENTER);
root.setBottom(l);
Scene scene = new Scene(root,500,500);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) { e.printStackTrace(); }
}
public static void main(String[] args) {
launch(args);
}
}

Related

JavaFx: Update position every frame

I am currently writing a board game in JavaFx. For that, I have a class Board which contains a list of Field. A Field has just a y and an x value as a position. In the start-Method of my application I create an object of the board game which creates in its constructor some fields and adds it to the list. Now I get the field-list from the boardgame, iterate over it and then draw a circle on the given position.
Now my question: How do I get to change the coordinates where the circle is drawn at runtime for moving/animating the field? Is there a way to "link" my field object coordinates to the drawn circle (maybe extending the class, so that it is drawable directly or so) or do I have to delete all Elements out of the stage and add new circles with the new position of my fields?
The field might be later a bit more complex (graphic, text, EventListner etc.) So the solution should be valid not only for a shape.
Here is the relevant code:
Main.java:
public class Main extends Application {
Stage window;
int windowWidth = 1000;
int windowHeight = 1000;
#Override
public void start(Stage primaryStage) throws Exception{
window = primaryStage;
Group group = new Group();
group.getChildren().add(button1);
Scene scene1 = new Scene(group, windowWidth, windowHeight);
scene1.setFill(Color.rgb(100,100,100, 0.2));
Board board = new Board();
for (Field f : board.getFields()) {
//Make circles out of the fields
Circle circle = new Circle(calculatePercentageX(f.getXPos()), calculatePercentageY(f.getYPos()), 20, Color.RED);
group.getChildren().add(circle);
}
window.setScene(scene1);
window.show();
}
public static void main(String[] args) {
launch(args);
}
public int calculatePercentageX(int xPx) {
System.out.println(xPx + " und " + windowWidth + " und " + 100);
return (int)Math.round(windowWidth/100*xPx);
}
public int calculatePercentageY(int yPx) {
return (int)Math.round(windowHeight/100*yPx);
}
}
Board.java
public class Board {
List<Field> fields = new LinkedList<>();
public Board() {
//generate fields (id, xPos, yPos)
fields.add(new Field(0, 10, 10));
fields.add(new Field(1, 20, 20));
fields.add(new Field(2, 40, 30));
fields.add(new Field(3, 40, 60));
fields.add(new Field(4, 60, 20));
}
public List<Field> getFields() {
return fields;
}
}
Field.java
public class Field {
protected int id = 0;
protected int xPos = 0;
protected int yPos = 0;
public Field(int id, int xPos, int yPos){
this.id = id;
this.xPos = xPos;
this.yPos = yPos;
}
public int getXPos(){
return xPos;
}
public int getYPos(){
return yPos;
}
}

Automatic resizing of rectangles in a Pane using Java FX-8

I am trying to create a grid of rectangles that will be contained inside a pane using JavaFX. I want these rectangles to be automatically resized to occupy the space available based on the size of the Pane, with a small gap between the rectangles.
The code I am using right now is this, the createVisual function is called to generate the group containing the pane :
public class Visualizer extends NodePart {
private VBox m_vbox;
private AnchorPane m_pane;
public static class ResizableRectanble extends javafx.scene.shape.Rectangle {
public ResizableRectangle(double w, double h) {
super(w,h);
}
#Override
public boolean isResizable() {
return true;
}
#Override
public void resize(double width, double height) {
setWidth(width);
setHeight(height);
}
}
#Override
protected Group createVisual() {
final Group group = new Group() {
#Override
public boolean isResizable() {
return true;
}
#Override
public void resize(double w, double h) {
m_pane.setPrefSize(w,h);
}
};
m_pane = new AnchorPane();
m_pane.setStyle("-fx-background-color : lightcyan; -fx-border-color: silver; -fx-border-width: 3;");
m_pane.setPrefSize(100, 100);
m_pane.setMouseTransparent(false);
m_vbox = new VBox(3.0);
m_vbox.setFillWidth(true);
m_vbox.setMouseTransparent(false);
for(int i=0; i<16; i++) {
HBox hbox = new HBox(3.0);
hbox.setAlignment(Pos.CENTER);
for(int j=0; j<4; j++) {
Rectangle rect = new ResizableRectangle(50.0,50.0);
rect.setStyle("-fx-fill: lime; -fx-border-color: red; -fx-border-width: 3;");
hbox.setHgrow(rect, Priority.ALWAYS);
hbox.getChildren().add(rect);
hbox.setFillHeight(true);
}
}
m_vbox.setVGrow(hbox, Priority.ALWAYS);
m_pane.setTopAnchor(m_vbox, 5.0);
m_pane.setBottomAnchor(m_vbox, 5.0);
m_pane.getChildren().add(m_vbox);
group.getChildren().add(m_pane);
return group;
}
}
This does not really work as the width of the rectangle is not changed from the initial value when the group size change. The height of the rectangles is also very small and there is a lot more than 3.0 pixel between them.
I have also tried to set up left and right anchor on m_vbox, but it does not seem to work as the rectangles get resized to less than half the size of the pane with that.
I have tried using a GridPane and constraints on the columns and row, but it does not work either as there is overlap. I would prefer to use the VBox and HBox combination if possible.
This function is called by Eclipse GEF (Graphical Editing Framework) to create a node in a graph. I am using GEF version 5 in Eclipse Neon.
I am a beginner with JavaFX, any help would be much appreciated !
Edit, the code I have tried using GridPane :
public class Visualizer extends NodePart {
private GridPane m_gridPane;
public static class ResizableRectanble extends javafx.scene.shape.Rectangle {
public ResizableRectangle(double w, double h) {
super(w,h);
}
#Override
public boolean isResizable() {
return true;
}
#Override
public void resize(double width, double height) {
setWidth(width);
setHeight(height);
}
}
#Override
protected Group createVisual() {
final Group group = new Group() {
#Override
public boolean isResizable() {
return true;
}
#Override
public void resize(double w, double h) {
m_gridPane.setPrefSize(w,h);
}
};
m_gridPane = new GridPane();
m_gridPane.setStyle("-fx-background-color : lightcyan; -fx-border-color: silver; -fx-border-width: 3;");
m_gridPane.setPrefSize(100, 100);
m_gridPane.setMouseTransparent(false);
for(int i=0; i<16; i++) {
for(int j=0; j<4; j++) {
if(i == 0) {
ColumnConstraints cc = new ColumnConstraints();
cc.setFillWidth(true);
cc.setHgrow(Priority.ALWAYS);
m_gridPane.getColumnConstraints().add(cc);
}
Rectangle rect = new ResizableRectangle(50.0,50.0);
rect.setStyle("-fx-fill: lime; -fx-border-color: red; -fx-border-width: 3;");
m_gridPane.add(rect, j, i);
}
RowConstraints rc = new RowConstraints();
rc.setFillHeight(true);
rc.setVgrow(Priority.ALWAYS);
m_gridPane.getRowConstraints().add(rc);
}
group.getChildren().add(m_gridPane);
return group;
}
}
Edit 2 : The code using GridPane works and the nodes are not overlapping. However, the borders of the rectangles are not shown, which led me to believe that there was overlapping.

Extend content of a Scrollpane if smaller than viewport

I want to make a ScrollPane with a custom Pane inside, that has two Children. One that holds my objects and one just for the background. I want to make it so if I zoom out, and the content is smaller than the viewport, then the size of the content would expand, filling in the new place in the viewport. And if I zoom back then it would remain the same, and I have now a larger content in area. The new width of the content would be: originalWidth + viewportWidth - scaledWidth.
I have made the grid, and the zooming works, but I can't make it so that it resizes the content. I have tried to set the content size when zooming to the current viewport size, but it does not work.
Question:
What am I doing wrong?
The layout is defined in fxml. Another than ScrollPane content set to fill height and width nothing out of ordinary there.
CustomPane class:
public class CustomPane extends StackPane implements Initializable {
#FXML
StackPane view;
#FXML
AnchorPane objectPane;
#FXML
GriddedPane background;
private DoubleProperty zoomFactor = new SimpleDoubleProperty(1.5);
private BooleanProperty altStatus = new SimpleBooleanProperty(false);
public CustomPane() {
super();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getClassLoader().getResource("CustomCanvas.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
objectPane.setStyle("-fx-background-color: transparent");
objectPane.prefWidthProperty().bind(prefWidthProperty());
objectPane.prefHeightProperty().bind(prefHeightProperty());
objectPane.getChildren().add(new Circle(512, 378, 20, Color.RED));
}
public void zoom(ScrollPane parent, Node node, double factor, double x, double y) {
Timeline timeline = new Timeline(60);
// determine scale
double oldScale = node.getScaleX();
double scale = oldScale * factor;
double f = (scale / oldScale) - 1;
// determine offset that we will have to move the node
Bounds bounds = node.localToScene(node.getBoundsInLocal());
double dx = (x - (bounds.getWidth() / 2 + bounds.getMinX()));
double dy = (y - (bounds.getHeight() / 2 + bounds.getMinY()));
// timeline that scales and moves the node
timeline.getKeyFrames().clear();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.millis(100), new KeyValue(node.translateXProperty(), node.getTranslateX() - f * dx)),
new KeyFrame(Duration.millis(100), new KeyValue(node.translateYProperty(), node.getTranslateY() - f * dy)),
new KeyFrame(Duration.millis(100), new KeyValue(node.scaleXProperty(), scale)),
new KeyFrame(Duration.millis(100), new KeyValue(node.scaleYProperty(), scale))
);
timeline.play();
Bounds viewportBounds = parent.getViewportBounds();
if (bounds.getWidth() < viewportBounds.getWidth()) {
setMinWidth(viewportBounds.getWidth());
requestLayout();
}
if (getMinHeight() < viewportBounds.getHeight()) {
setMinHeight(viewportBounds.getHeight());
requestLayout();
}
}
public final Double getZoomFactor() {
return zoomFactor.get();
}
public final void setZoomFactor(Double zoomFactor) {
this.zoomFactor.set(zoomFactor);
}
public final DoubleProperty zoomFactorProperty() {
return zoomFactor;
}
public boolean getAltStatus() {
return altStatus.get();
}
public BooleanProperty altStatusProperty() {
return altStatus;
}
public void setAltStatus(boolean altStatus) {
this.altStatus.set(altStatus);
}
}
Controller class:
public class Controller implements Initializable {
public ScrollPane scrollPane;
public CustomPane customPane;
public AnchorPane anchorPane;
public Tab tab1;
#Override
public void initialize(URL location, ResourceBundle resources) {
scrollPane.viewportBoundsProperty().addListener((observable, oldValue, newValue) -> {
customPane.setMinSize(newValue.getWidth(), newValue.getHeight());
});
scrollPane.requestLayout();
tab1.getTabPane().addEventFilter(KeyEvent.KEY_PRESSED, event1 -> {
if (event1.getCode() == KeyCode.ALT)
customPane.setAltStatus(true);
});
tab1.getTabPane().addEventFilter(KeyEvent.KEY_RELEASED, event1 -> {
if (event1.getCode() == KeyCode.ALT)
customPane.setAltStatus(false);
});
scrollPane.setOnScroll(event -> {
double zoomFactor = 1.5;
if (event.getDeltaY() <= 0)
zoomFactor = 1 / zoomFactor;
customPane.setZoomFactor(zoomFactor);
if (customPane.getAltStatus())
customPane.zoom(scrollPane, customPane, customPane.getZoomFactor(), event.getSceneX(), event.getSceneY());
});
}
}
GriddedPane class:
public class GriddedPane extends Pane implements Initializable {
DoubleProperty gridWidth = new SimpleDoubleProperty(this, "gridWidth", 10);
DoubleProperty gridHeight = new SimpleDoubleProperty(this, "gridHeight", 10);
public GriddedPane() {
super();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#Override
protected void layoutChildren() {
getChildren().clear();
setMouseTransparent(true);
toBack();
for (int i = 0; i < getHeight(); i += getGridWidth())
getChildren().add(makeLine(0, i, getWidth(), i, "x"));
for (int i = 0; i < getWidth(); i += getGridHeight())
getChildren().add(makeLine(i, 0, i, getHeight(), "y"));
}
public void redrawLines() {
for (Node n : getChildren()) {
Line l = (Line) n;
if (l.getUserData().equals("x")) {
l.setEndX(getWidth());
} else if (l.getUserData().equals("y")) {
l.setEndY(getHeight());
}
}
}
private Line makeLine(double sx, double sy, double ex, double ey, String data) {
final Line line = new Line(sx, sy, ex, ey);
if (ex % (getGridWidth() * 10) == 0.0) {
line.setStroke(Color.BLACK);
line.setStrokeWidth(0.3);
} else if (ey % (getGridHeight() * 10) == 0.0) {
line.setStroke(Color.BLACK);
line.setStrokeWidth(0.3);
} else {
line.setStroke(Color.GRAY);
line.setStrokeWidth(0.1);
}
line.setUserData(data);
return line;
}
public double getGridWidth() {
return gridWidth.get();
}
public DoubleProperty gridWidthProperty() {
return gridWidth;
}
public void setGridWidth(double gridWidth) {
this.gridWidth.set(gridWidth);
}
public double getGridHeight() {
return gridHeight.get();
}
public DoubleProperty gridHeightProperty() {
return gridHeight;
}
public void setGridHeight(double gridHeight) {
this.gridHeight.set(gridHeight);
}
}
Not really sure if I unterstood what you want to achieve. But if your goal is to make the content of the scrollPane never get smaller than the scrollPane's width, this does the job for me:
public class Zoom extends Application {
#Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView(new Image(someImage));
ScrollPane scrollPane = new ScrollPane(imageView);
StackPane root = new StackPane(scrollPane);
imageView.fitWidthProperty().bind(scrollPane.widthProperty());
imageView.fitHeightProperty().bind(scrollPane.heightProperty());
scrollPane.setOnScroll(evt -> {
boolean zoomOut = evt.getDeltaY() < 0;
double zoomFactor = zoomOut ? -0.2 : 0.2;
imageView.setScaleX(imageView.getScaleX() + zoomFactor);
imageView.setScaleY(imageView.getScaleY() + zoomFactor);
if (zoomOut) {
Bounds bounds = imageView.getBoundsInParent();
if (bounds.getWidth() < scrollPane.getWidth()) {
imageView.setScaleX(1);
imageView.setScaleY(1);
}
}
});
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Display 2d array as grid in JavaFX

for my Java coursework I have to create a grid based animation. Basically I currently have a 2d array containing certain values, which change each time the program is run. For example it could be a 20x20 2d array, or a 32x32 etc. Inside the array certain values are stored, chars represent animals, and numbers represent food. The animals smell the food and then move towards the food after each cycle of the program, hence their position in the array change after each cycle. How the program works isn't really relevant to the question I'm asking.
Basically I now have to implement this in JavaFX (it currently works in the console, displaying the array as a grid each cycle). I was just wondering which control would be best to use in JavaFX to display a 2d array, or if perhaps someone could point me in the right direction of how to start coding this?
I'm new to java (and JavaFX) so am not sure of which controls to use...
I wouldn't use a control. I'd rather create a node for each of the items in the array and put them on the scene. Something like this:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class NodeDemo extends Application {
private double sceneWidth = 1024;
private double sceneHeight = 768;
private int n = 10;
private int m = 10;
double gridWidth = sceneWidth / n;
double gridHeight = sceneHeight / m;
MyNode[][] playfield = new MyNode[n][m];
#Override
public void start(Stage primaryStage) {
Group root = new Group();
// initialize playfield
for( int i=0; i < n; i++) {
for( int j=0; j < m; j++) {
// create node
MyNode node = new MyNode( "Item " + i + "/" + j, i * gridWidth, j * gridHeight, gridWidth, gridHeight);
// add node to group
root.getChildren().add( node);
// add to playfield for further reference using an array
playfield[i][j] = node;
}
}
Scene scene = new Scene( root, sceneWidth, sceneHeight);
primaryStage.setScene( scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class MyNode extends StackPane {
public MyNode( String name, double x, double y, double width, double height) {
// create rectangle
Rectangle rectangle = new Rectangle( width, height);
rectangle.setStroke(Color.BLACK);
rectangle.setFill(Color.LIGHTBLUE);
// create label
Label label = new Label( name);
// set position
setTranslateX( x);
setTranslateY( y);
getChildren().addAll( rectangle, label);
}
}
}
This way you can create animated movement of the nodes easily with a PathTransition. Like this shuffle mechanism:
import java.util.Random;
import javafx.animation.Animation.Status;
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class NodeDemo extends Application {
private double sceneWidth = 1024;
private double sceneHeight = 768;
private int n = 10;
private int m = 10;
double gridWidth = sceneWidth / n;
double gridHeight = sceneHeight / m;
MyNode[][] playfield = new MyNode[n][m];
#Override
public void start(Stage primaryStage) {
Group root = new Group();
// initialize playfield
for( int i=0; i < n; i++) {
for( int j=0; j < m; j++) {
// create node
MyNode node = new MyNode( "Item " + i + "/" + j, i * gridWidth, j * gridHeight, gridWidth, gridHeight);
// add node to group
root.getChildren().add( node);
// add to playfield for further reference using an array
playfield[i][j] = node;
}
}
Scene scene = new Scene( root, sceneWidth, sceneHeight);
primaryStage.setScene( scene);
primaryStage.show();
animate();
}
private void animate() {
Random random = new Random();
int ai = random.nextInt(n);
int aj = random.nextInt(m);
int bi = random.nextInt(n);
int bj = random.nextInt(m);
// make sure that A and B are never the same
if( ai == bi && aj == bj) {
ai++;
if( ai >= n)
ai = 0;
}
MyNode nodeA = playfield[ai][aj];
nodeA.toFront();
MyNode nodeB = playfield[bi][bj];
nodeB.toFront();
// swap on array to keep array consistent
playfield[ai][aj] = nodeB;
playfield[bi][bj] = nodeA;
// A -> B
Path pathA = new Path();
pathA.getElements().add (new MoveTo ( nodeA.getTranslateX() + nodeA.getBoundsInParent().getWidth() / 2.0, nodeA.getTranslateY() + nodeA.getBoundsInParent().getHeight() / 2.0));
pathA.getElements().add (new LineTo( nodeB.getTranslateX() + nodeB.getBoundsInParent().getWidth() / 2.0, nodeB.getTranslateY() + nodeB.getBoundsInParent().getHeight() / 2.0));
PathTransition pathTransitionA = new PathTransition();
pathTransitionA.setDuration(Duration.millis(1000));
pathTransitionA.setNode( nodeA);
pathTransitionA.setPath(pathA);
pathTransitionA.play();
// B -> A
Path pathB = new Path();
pathB.getElements().add (new MoveTo ( nodeB.getTranslateX() + nodeB.getBoundsInParent().getWidth() / 2.0, nodeB.getTranslateY() + nodeB.getBoundsInParent().getHeight() / 2.0));
pathB.getElements().add (new LineTo( nodeA.getTranslateX() + nodeA.getBoundsInParent().getWidth() / 2.0, nodeA.getTranslateY() + nodeA.getBoundsInParent().getHeight() / 2.0));
PathTransition pathTransitionB = new PathTransition();
pathTransitionB.setDuration(Duration.millis(1000));
pathTransitionB.setNode( nodeB);
pathTransitionB.setPath(pathB);
pathTransitionB.play();
pathTransitionA.setOnFinished( new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if( pathTransitionB.getStatus() == Status.RUNNING)
return;
animate();
}
});
pathTransitionB.setOnFinished( new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if( pathTransitionA.getStatus() == Status.RUNNING)
return;
animate();
}
});
}
public static void main(String[] args) {
launch(args);
}
public static class MyNode extends StackPane {
public MyNode( String name, double x, double y, double width, double height) {
// create rectangle
Rectangle rectangle = new Rectangle( width, height);
rectangle.setStroke(Color.BLACK);
rectangle.setFill(Color.LIGHTBLUE);
// create label
Label label = new Label( name);
// set position
setTranslateX( x);
setTranslateY( y);
getChildren().addAll( rectangle, label);
}
}
}
And here's an example about how you could handle the cells via subclassing. But that's just one way to do it:
public class NodeDemo extends Application {
private double sceneWidth = 1024;
private double sceneHeight = 768;
private int n = 10;
private int m = 10;
double gridWidth = sceneWidth / n;
double gridHeight = sceneHeight / m;
MyNode[][] playfield = new MyNode[n][m];
#Override
public void start(Stage primaryStage) {
Group root = new Group();
// initialize playfield
for( int i=0; i < n; i++) {
for( int j=0; j < m; j++) {
MyNode node = null;
// create bug
if( i == 0 && j == 0) {
node = new Bug( "Bug", Color.ORANGE, i, j);
}
// create food
else if( i == 5 && j == 5) {
node = new Food( "Food", Color.GREEN, i, j);
}
// create obstacle
else if( i == 3 && j == 3) {
node = new Obstacle( "Obstacle", Color.GRAY, i, j);
}
// add node to group
if( node != null) {
root.getChildren().add( node);
// add to playfield for further reference using an array
playfield[i][j] = node;
}
}
}
Scene scene = new Scene( root, sceneWidth, sceneHeight);
primaryStage.setScene( scene);
primaryStage.show();
// move bugs
animate();
}
private void animate() {
// TODO
}
public static void main(String[] args) {
launch(args);
}
private class Food extends MyNode {
public Food(String name, Color color, double x, double y) {
super(name, color, x, y);
}
}
private class Obstacle extends MyNode {
public Obstacle(String name, Color color, double x, double y) {
super(name, color, x, y);
}
}
private class Bug extends MyNode {
public Bug(String name, Color color, double x, double y) {
super(name, color, x, y);
}
}
private class MyNode extends StackPane {
public MyNode( String name, Color color, double x, double y) {
// create rectangle
Rectangle rectangle = new Rectangle( gridWidth, gridHeight);
rectangle.setStroke( color);
rectangle.setFill( color.deriveColor(1, 1, 1, 0.7));
// create label
Label label = new Label( name);
// set position
setTranslateX( x * gridWidth);
setTranslateY( y * gridHeight);
getChildren().addAll( rectangle, label);
}
}
}
You can start looking at the "Getting Started" section at the documentation. Focus on the simple examples like the HelloWorld and LoginForm sample programs.
For you structure you'll probably want to use a GridPane.

How to change the set color in a for loop?

My circles change color, but while the smallest one always remains red, the largest does not remain blue. Whenever I attempt to change my code from what it is now, all circles become the same color, and just change shade when the slider is moved. I would like there to just be more shades in between the red and blue as the slider increases. Could you please explain the changes I need to make? I understand everything I'm doing, except the color changing part.
public class SliderLab1 extends JFrame {
JSlider slider;
GPanel graphicsPanel;
public SliderLab1() {
super("Slider/Shapes Demo");
setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE );
JPanel outerPanel = new JPanel();
graphicsPanel = new GPanel(); //for shapes
JPanel sliderPanel = new JPanel();
setup(sliderPanel);
outerPanel.add(graphicsPanel);
outerPanel.add(sliderPanel);
add(outerPanel);
pack();
setVisible(true);
}
private void setup(JPanel p) {
slider = new JSlider(
JSlider.VERTICAL,4,20,8);
slider.setMinorTickSpacing(1);
slider.setMajorTickSpacing(4);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener( new SLstn() );
p.add(slider);
}
private class SLstn implements ChangeListener {
public void stateChanged(ChangeEvent e) {
int x = slider.getValue();
System.out.println(x);
graphicsPanel.setCount(x);
graphicsPanel.repaint();
}
}
private class GPanel extends JPanel {
int count = 8;
int size = 400;
int stepSize = (int)size/count;
public GPanel() {
setPreferredSize(
new Dimension(size,size));
setBackground(Color.BLACK);
}
public void setCount(int n) {
count=n;
stepSize = (int)size/count;
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setStroke(new BasicStroke(3) );
for(int i = count; i>=0; i--){
Color myC = new Color(((255/stepSize)*(stepSize-i)), 0, (255/stepSize)*i );
g.setColor(myC);
for (int j = 0; j <= count; j++) {
g.drawOval(0,(size-(stepSize*i)),stepSize*i,stepSize*i);
g.fillOval(0,(size-(stepSize*i)),stepSize*i,stepSize*i);
}
}
}
}
public static void main(String[] args) {
new SliderLab1();
}
}
Simply replace:
Color myC = new Color(((255/stepSize)*(stepSize-i)), 0, (255/stepSize)*i );
by:
final Color myC = new Color(((255 / count) * (count - i)), 0, (255 / count) * i);
You don't want to work with stepSize at this point, using count should do the trick :)
I hope it helps!

Categories