I am creating a chess game and i am stuck at one thing for a couple of days.
So i want to create event when user moves over a figure the image of figure replaces to another image with border and when user moves away the image must return to normal. Here is full code.
Folder for Project is called sample,Folder for images is Called Sprites.
Folder for classes is called Figures.I will link the images for black pawn.
package sample;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import sample.Figures.*;
public class Main extends Application {
#Override
public void start(Stage primaryStage){
primaryStage.setTitle("ChessGame");
primaryStage.getIcons().add(new Image("/sample/Chess-icon.png"));
GridPane root = new GridPane();
final GridPane group = new GridPane();
group.setPadding(new Insets(15, 25, 25, 25));
for (int i = 0 ; i < 8 ; i++) {
for (int j = 0 ; j < 8 ; j++) {
Rectangle rectangle = new Rectangle( 50, 50);
if(j % 2 == 0 && (i % 2 == 0)) {
rectangle.setFill(Color.BEIGE);
}
else if(!((j + 2) % 2 == 0) && !((i + 2) % 2 == 0)) {
rectangle.setFill(Color.BEIGE);
}
else {
rectangle.setFill(Color.GRAY);
}
group.add(rectangle,i,j);
}
}
//FIGURES
//Black
//Pawns
final blackPawn BlackP_1 = new blackPawn(0,1,64,65);
group.add(BlackP_1.IMG,BlackP_1.x,BlackP_1.y);
BlackP_1.IMG.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
group.getChildren().remove(64,65);
group.add(BlackP_1.IMGglow,0,1);
}
});
BlackP_1.IMGglow.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
group.getChildren().remove(64,65);
group.add(BlackP_1.IMG,BlackP_1.x,BlackP_1.y);
}
});
blackPawn BlackP_2 = new blackPawn(1,1);
group.add(BlackP_2.IMG,BlackP_2.x,BlackP_2.y);
blackPawn BlackP_3 = new blackPawn(2,1);
group.add(BlackP_3.IMG,BlackP_3.x,BlackP_3.y);
blackPawn BlackP_4 = new blackPawn(3,1);
group.add(BlackP_4.IMG,BlackP_4.x,BlackP_4.y);
blackPawn BlackP_5 = new blackPawn(4,1);
group.add(BlackP_5.IMG,BlackP_5.x,BlackP_5.y);
blackPawn BlackP_6 = new blackPawn(5,1);
group.add(BlackP_6.IMG,BlackP_6.x,BlackP_6.y);
blackPawn BlackP_7 = new blackPawn(6,1);
group.add(BlackP_7.IMG,BlackP_7.x,BlackP_7.y);
blackPawn BlackP_8 = new blackPawn(7,1);
group.add(BlackP_8.IMG,BlackP_8.x,BlackP_8.y);
//Rooks
blackRook BlackR_1 = new blackRook();
group.add(BlackR_1.IMG,7,0);
blackRook BlackR_2 = new blackRook();
group.add(BlackR_2.IMG,0,0);
//Knights
blackKnight BlackK_1 = new blackKnight();
group.add(BlackK_1.IMG,1,0);
blackKnight BlackK_2 = new blackKnight();
group.add(BlackK_2.IMG,6,0);
//Bishop
blackBishop BlackB_1 = new blackBishop();
group.add(BlackE_1.IMG,2,0);
blackBishop BlackB_2 = new blackBishop();
group.add(BlackE_2.IMG,5,0);
//Queen
blackQueen blackQueen= new blackQueen();
group.add(blackQueen.IMG,3,0);
//King
blackKing blackking = new blackKing();
group.add(blackking.IMG,4,0);
//WHITE
//Pawns
final whitePawn WhiteP_1 = new whitePawn();
group.add(WhiteP_1.IMG,0,6);
whitePawn WhiteP_2 = new whitePawn();
group.add(WhiteP_2.IMG,1,6);
whitePawn WhiteP_3 = new whitePawn();
group.add(WhiteP_3.IMG,2,6);
whitePawn WhiteP_4 = new whitePawn();
group.add(WhiteP_4.IMG,3,6);
whitePawn WhiteP_5 = new whitePawn();
group.add(WhiteP_5.IMG,4,6);
whitePawn WhiteP_6 = new whitePawn();
group.add(WhiteP_6.IMG,5,6);
whitePawn WhiteP_7 = new whitePawn();
group.add(WhiteP_7.IMG,6,6);
whitePawn WhiteP_8 = new whitePawn();
group.add(WhiteP_8.IMG,7,6);
//Rooks
whiteRook WhiteR_1 = new whiteRook();
group.add(WhiteR_1.IMG,0,7);
whiteRook WhiteR_2 = new whiteRook();
group.add(WhiteR_2.IMG,7,7);
//Knights
whiteKnight WhiteK_1 = new whiteKnight();
group.add(WhiteK_1.IMG,1,7);
whiteKnight WhiteK_2 = new whiteKnight();
group.add(WhiteK_2.IMG,6,7);
//Bishop
whiteBishop WhiteB_1 = new whiteBishop();
group.add(WhiteB_1.IMG,2,7);
whiteBishop WhiteB_2 = new whiteBishop();
group.add(WhiteB_2.IMG,5,7);
//Queen
whiteQueen whitequeen = new whiteQueen();
group.add(whitequeen.IMG,3,7);
//King
whiteKing whiteking = new whiteKing();
group.add(whiteking.IMG,4,7);
root.getChildren().add(group);
root.setStyle("-fx-background-color: #C1D1E8;");
Scene scene = new Scene(root, 450, 440);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Black Pawn Class
package sample.Figures;
import javafx.scene.image.ImageView;
public class blackPawn {
public int x;
public int y;
public int start;
public int end;
public ImageView IMG = new ImageView("sample/Sprites/blackPawn.png");
public ImageView IMGglow = new ImageView("sample/Sprites/blackPawnStroke.png");
public blackPawn(int x,int y)
{
this.x = x;
this.y = y;
}
public blackPawn(int x,int y,int start,int end)
{
this.x = x;
this.y = y;
this.start = start;
this.end = end;
}
}
It's quite easy to change the Image of an ImageView just by calling the setImage(). There are two ways to make the transition from one state to another. The first approach is programmatically through setOnMouseEntered() and setOnMouseExited() here is an example :
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class HoverableImage extends Application {
#Override
public void start(Stage stage) throws Exception {
ImageView imageView = createChestImage();
FlowPane pane = new FlowPane();
pane.setAlignment(Pos.CENTER);
pane.getChildren().add(imageView);
stage.setScene(new Scene(pane, 100, 100));
stage.show();
}
private ImageView createChestImage() {
ImageView iv = new ImageView(new Image("https://i.stack.imgur.com/rd71Q.png"));
iv.setOnMouseEntered(e->{
iv.setImage(new Image("https://i.stack.imgur.com/7JU7r.png"));
});
iv.setOnMouseExited(e->{
iv.setImage(new Image("https://i.stack.imgur.com/rd71Q.png"));
});
return iv;
}
public static void main(String[] args) {
launch(args);
}
}
The second approach would be to do that using CSS, you can set each chest piece an ID (for example : iv.setID("SoldierPiece"); ) and then apply those CSS rules on it :
#SoldierPiece{
-fx-image: url("https://i.stack.imgur.com/rd71Q.png");
}
#SoldierPiece:hover{
-fx-image: url("https://i.stack.imgur.com/7JU7r.png");
}
Related
So I'm trying to create a very basic photo editor program in Java, using JavaFX. I got a brush and eraser working pretty well so far the following way:
package application;
import java.io.File;
import javax.imageio.ImageIO;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.canvas.*;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
public class EditorController {
private boolean eraser = false;
#FXML
private Canvas canvas;
#FXML
private ColorPicker colorPicker;
#FXML
private TextField brushSize;
#FXML
private TextField selectedTool;
private Point2D last = null;
public void initialize() {
GraphicsContext gc = canvas.getGraphicsContext2D();
canvas.setOnMouseReleased(e -> {last = null;});
canvas.setOnMouseClicked(e -> {
if (!eraser) {
double size = Double.parseDouble(brushSize.getText());
float mouseX = (float) e.getX();
float mouseY = (float) e.getY();
gc.fillOval(mouseX-(size/2), mouseY-(size/2), size, size);
}
});
canvas.setOnMouseDragged(e -> {
System.out.println(eraser);
double size = Double.parseDouble(brushSize.getText());
gc.setLineCap(StrokeLineCap.ROUND);
gc.setLineWidth(size);
float mouseX = (float) e.getX();
float mouseY = (float) e.getY();
if (last != null && !eraser) {
gc.strokeLine(last.getX(), last.getY(), mouseX, mouseY);
} else if (eraser) {
gc.clearRect(mouseX, mouseY, size, size);
}
last = new Point2D(mouseX, mouseY);
});
}
public void onSave() {
try {
Image snapshot = canvas.snapshot(null, null);
ImageIO.write(SwingFXUtils.fromFXImage(snapshot, null), "png", new File("paint.png"));
} catch (Exception e) {
System.out.println("Failed to save image: " + e);
}
}
public void onLoad() {
// not implemented yet
}
// not implemented yet
public void onUndo() { }
public void onRedo() { }
public void onSmaller() { }
public void onBigger() { }
public void onResetView() { }
public void onFitView() { }
public void onFillView() { }
public void onNewLayer() { }
public void onDeleteLayer() { }
public void onDuplicateLayer() { }
public void onGroupLayers() { }
public void onMergeLayers() { }
public void onAddMask() { }
public void onBrush() { eraser = false; selectedTool.setText("Brush"); }
public void onEraser() { eraser = true; selectedTool.setText("Eraser"); }
public void onExit() {
Platform.exit();
}
}
Now I want to have a feather/hardness value for the brush (like in photoshop) where I can draw a softer-looking line, but I'm not sure how to achieve it with JavaFX? Are there any tools within it for things like this?
So with a visual example: the brush on the left would be a feathered brush, the one on the right isn't (and that's what I have currently)
Simple drawing app.
It uses a radial gradient rendered to an image that is drawn on the canvas, but you could just draw the gradient directly onto the canvas. A gradient is a paint so you can set it directly as an argument to setFill on a graphics context.
The solution in my example probably won't exactly give you the solution you are looking for, but perhaps you could tweak it for what you need.
It was a quick app I put together for demo purposes, it could be structured better if a more functional drawing app was required.
The code which creates the "feathered brush" is based on a gradient:
private RadialGradient createSoftBrushGradient(Color primaryColor) {
return new RadialGradient(
0, 0,
.5, .5,
.5,
true,
CycleMethod.NO_CYCLE,
new Stop(0, primaryColor),
new Stop(1, Color.TRANSPARENT)
);
}
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.*;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class SprayPaint extends Application {
private final IntegerProperty brushDiameter = new SimpleIntegerProperty();
private final ObjectProperty<Image> brushImage = new SimpleObjectProperty<>();
private final ToggleGroup brushHardnessSelection = new ToggleGroup();
private final RadioButton hardBrushSelection = new RadioButton();
private final RadioButton softBrushSelection = new RadioButton();
private final Circle hardBrush = new Circle();
private final Circle softBrush = new Circle();
private final SnapshotParameters snapshotParams = new SnapshotParameters();
private final Canvas canvas = new Canvas(600, 450);
#Override
public void start(Stage stage) {
snapshotParams.setFill(Color.TRANSPARENT);
Pane controls = createControls();
StackPane canvasHolder = new StackPane(canvas);
canvasHolder.setStyle("-fx-border-color: gray;");
canvasHolder.setMaxSize(Pane.USE_PREF_SIZE, Pane.USE_PREF_SIZE);
VBox layout = new VBox(
10,
controls,
canvasHolder
);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
enableDrawing(canvas);
}
private void enableDrawing(Canvas canvas) {
EventHandler<MouseEvent> drawHandler = event -> {
Image brush = snapshotBrushImage();
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(
brush,
event.getX() - brushDiameter.doubleValue() / 2,
event.getY() - brushDiameter.doubleValue() / 2
);
};
canvas.setOnMousePressed(drawHandler);
canvas.setOnMouseDragged(drawHandler);
}
private Image snapshotBrushImage() {
if (brushImage.get() == null) {
if (hardBrushSelection == brushHardnessSelection.getSelectedToggle()) {
brushImage.set(snapshot(hardBrush));
} else { // soft brush selected
brushImage.set(snapshot(softBrush));
}
}
return brushImage.get();
}
private Image snapshot(Circle brushNode) {
return brushNode.snapshot(snapshotParams, null);
}
private Pane createControls() {
hardBrush.radiusProperty().bind(
brushDiameter.divide(2.0)
);
softBrush.radiusProperty().bind(
brushDiameter.divide(2.0)
);
hardBrushSelection.getStyleClass().addAll("toggle-button", "left-pill");
hardBrushSelection.getStyleClass().remove( "radio-button");
StackPane hardBrushGraphic = new StackPane(hardBrush);
hardBrushGraphic.setMinSize(40, 40);
hardBrushSelection.setGraphic(hardBrushGraphic);
hardBrushSelection.setToggleGroup(brushHardnessSelection);
softBrushSelection.getStyleClass().addAll( "toggle-button", "right-pill");
softBrushSelection.getStyleClass().remove( "radio-button");
StackPane softBrushGraphic = new StackPane(softBrush);
softBrushGraphic.setMinSize(40, 40);
softBrushSelection.setGraphic(softBrushGraphic);
softBrushSelection.setToggleGroup(brushHardnessSelection);
hardBrushSelection.setSelected(true);
HBox brushSelectionPanel = new HBox(hardBrushSelection, softBrushSelection);
Slider brushDiameterSlider = new Slider(8, 40, 20);
brushDiameterSlider.setMajorTickUnit(4);
brushDiameterSlider.setMinorTickCount(0);
brushDiameterSlider.setShowTickMarks(true);
brushDiameter.setValue((int) Math.round(brushDiameterSlider.getValue()));
brushDiameterSlider.valueProperty().addListener((observable, oldValue, newValue) ->
brushDiameter.setValue((int) Math.round(newValue.doubleValue()))
);
Label diameterLabel = new Label();
diameterLabel.textProperty().bind(
brushDiameter.asString()
);
ColorPicker colorPicker = new ColorPicker();
hardBrush.fillProperty().bind(
colorPicker.valueProperty()
);
colorPicker.valueProperty().addListener((observable, oldColor, newColor) ->
softBrush.setFill(
createSoftBrushGradient(newColor)
)
);
colorPicker.setValue(Color.NAVY);
brushDiameter.addListener((observable, oldValue, newValue) ->
brushImage.set(null)
);
colorPicker.valueProperty().addListener((observable, oldValue, newValue) ->
brushImage.set(null)
);
brushHardnessSelection.selectedToggleProperty().addListener((observable, oldValue, newValue) ->
brushImage.set(null)
);
Button clear = new Button("Clear");
clear.setOnAction(e ->
canvas.getGraphicsContext2D().clearRect(
0, 0, canvas.getWidth(), canvas.getHeight()
)
);
HBox controlPanel = new HBox(
10,
colorPicker,
brushSelectionPanel,
new Label("Diameter: "),
brushDiameterSlider,
diameterLabel,
clear
);
controlPanel.setMinWidth(450);
controlPanel.setMinHeight(Pane.USE_PREF_SIZE);
return controlPanel;
}
private RadialGradient createSoftBrushGradient(Color primaryColor) {
return new RadialGradient(
0, 0,
.5, .5,
.5,
true,
CycleMethod.NO_CYCLE,
new Stop(0, primaryColor),
new Stop(1, Color.TRANSPARENT)
);
}
}
I have an image. At the beginning I want the image to be displayed with only the first frame. On the keyboard with 'u' key pressed, drink water and load the second frame. If I understand correctly the whole image should be loaded at the beginning. And then I need to set new y.
How to complete this task? What is the right way to display this image?
My code in:
package testDesktopUi;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class DesktopUi extends Application {
private static int y = 0;
private static BufferedImage bufferedImage;
private static final ImageView imageView = new ImageView();
private static final HBox root = new HBox();
#Override
public void start(Stage primaryStage) throws IOException {
String path = "Bottle.png";
bufferedImage = ImageIO.read(new File(path)).getSubimage(0, 0, 32, 32);
Image image = SwingFXUtils.toFXImage(bufferedImage, null);
imageView.setImage(image);
root.getChildren().add(imageView);
Scene scene = new Scene(root);
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.U) {
System.out.println("u pressed");
updateImage(bufferedImage);
System.out.println(y);
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private static void updateImage(BufferedImage bufferedImage) {
int maxHeight = 352;
if (y + 32 >= maxHeight) {
y = 0;
} else {
y += 32;
}
//?? bufferedImage.getSubimage(0, y, 32, 32);
}
}
If you're using JavaFX, stick just to the JavaFX image API: there is no need to first load an AWT BufferedImage and convert it to a JavaFX image.
To display portions of an image, you can create an ImageView from the image and set the ImageView's viewport.
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class DesktopUi extends Application {
private int y = 0;
private final ImageView imageView = new ImageView();
private final HBox root = new HBox();
#Override
public void start(Stage primaryStage) {
String path = "Bottle.png";
// Assumes Bottle.png is in the same package as the current class:
Image image = new Image(getClass().getResource("Bottle.png").toExternalForm());
imageView.setImage(image);
// display only a portion of the image:
imageView.setViewport(new Rectangle2D(0, y, 32, 32));
root.getChildren().add(imageView);
Scene scene = new Scene(root);
scene.setOnKeyPressed(key -> {
if (key.getCode() == KeyCode.U) {
System.out.println("u pressed");
System.out.println(y);
updateImage();
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void updateImage() {
// update y
int maxHeight = 352;
if (y + 32 >= maxHeight) {
y = 0;
} else {
y += 32;
}
// update portion of image displayed
imageView.setViewport(new Rectangle2D(0, y, 32, 32));
}
public static void main(String[] args) {
Application.launch(args);
}
}
Note this also lends itself nicely to animations:
#Override
public void start(Stage primaryStage) {
int numSprites = 11 ;
Image image = new Image(getClass().getResource("Bottle.png").toExternalForm());
imageView.setImage(image);
IntegerProperty spriteIndex = new SimpleIntegerProperty();
spriteIndex.addListener((obs, oldIndex, newIndex) -> System.out.println(newIndex));
imageView.viewportProperty().bind(Bindings.createObjectBinding(
() -> new Rectangle2D(0, spriteIndex.get() * 32 , 32, 32),
spriteIndex
));
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(5),
new KeyValue(spriteIndex, numSprites - 1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
root.getChildren().add(imageView);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
I am building a Simon Says game in JavaFX. I have gotten most of it working, my only issue now is when you run the game it runs a for loop to generate the colours depending on which level you are on.
It seems to display one colour from the loop but it doesn't wait for the KeyFrame to finish before it flies through the rest of the loop and stores the values. How can I make the loop wait for the KeyFrame to complete so it displays all of the colour changes?
package assign3;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import javafx.animation.FillTransition;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Question2 extends Application
{
public static final int RED = 1;
public static final int GREEN = 2;
public static final int BLUE = 3;
public static final int ORANGE = 4;
private int thisGameScore = 0;
private int level = 1;
private BorderPane obBorder;
private HBox obPane;
private HBox obStart;
private Timeline tlRed;
private Timeline tlBlue;
private Timeline tlGreen;
private Timeline tlOrange;
private SequentialTransition stList = new SequentialTransition();
private Button btStart;
private ArrayList<Integer> colours;
private ArrayList<Integer> guesses;
#Override
public void start( Stage obPrimeStage ) throws Exception
{
boolean runGame = true;
int guessIndex = 0;
obBorder = new BorderPane();
obPane = new HBox();
obStart = new HBox();
Button btRed = new Button("Red");
Button btGreen = new Button("Green");
Button btBlue = new Button("Blue");
Button btOrange = new Button("Orange");
btStart = new Button("Start");
class RedTimeLine
{
Timeline tlRed;
RedTimeLine()
{
tlRed = new Timeline();
tlRed.getKeyFrames().add(new KeyFrame(Duration.ZERO,
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)))));
tlRed.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
}
}
tlBlue = new Timeline();
tlBlue.getKeyFrames().add(new KeyFrame(Duration.ZERO,
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)))));
tlBlue.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
tlGreen = new Timeline();
tlGreen.getKeyFrames().add(new KeyFrame(Duration.ZERO,
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY)))));
tlGreen.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
tlOrange = new Timeline();
tlOrange.getKeyFrames().add(new KeyFrame(Duration.ZERO,
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.ORANGE, CornerRadii.EMPTY, Insets.EMPTY)))));
tlOrange.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
new KeyValue(obBorder.backgroundProperty(),
new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
obStart.getChildren().add(btStart);
obPane.getChildren().addAll(btRed, btGreen, btBlue, btOrange);
obBorder.setCenter(obPane);
obBorder.setBottom(obStart);
obPane.setAlignment(Pos.CENTER);
obStart.setAlignment(Pos.CENTER);
Scene obScene = new Scene(obBorder, 400, 400);
obPrimeStage.setTitle("Simon Says");
obPrimeStage.setScene(obScene);
obPrimeStage.show();
btStart.setOnAction((ActionEvent start) -> {
colours = new ArrayList<>();
guesses = new ArrayList<>();
obChange.handle(start);
stList.play();
System.out.println("Started new game");
});
btRed.setOnAction((ActionEvent e) ->
{
guesses.add(RED);
if(guesses.get(guessIndex) != colours.get(guessIndex) )
{
obStart.getChildren().add(btStart);
level = 1;
}
else
{
if(guesses.size() == colours.size())
{
level += 1;
colours = new ArrayList<>();
guesses = new ArrayList<>();
for(int i = 0; i < level; i++)
{
obChange.handle(e);
}
stList.play();
}
}
});
btGreen.setOnAction((ActionEvent e) ->
{
guesses.add(GREEN);
if(guesses.get(guessIndex) != colours.get(guessIndex) )
{
obStart.getChildren().add(btStart);
level = 1;
}
else
{
if(guesses.size() == colours.size())
{
level += 1;
colours = new ArrayList<>();
guesses = new ArrayList<>();
for(int i = 0; i < level; i++)
{
obChange.handle(e);
}
stList.play();
}
}
});
btBlue.setOnAction((ActionEvent e) ->
{
guesses.add(BLUE);
if(guesses.get(guessIndex) != colours.get(guessIndex) )
{
obStart.getChildren().add(btStart);
level = 1;
}
else
{
if(guesses.size() == colours.size())
{
level += 1;
colours = new ArrayList<>();
guesses = new ArrayList<>();
for(int i = 0; i < level; i++)
{
obChange.handle(e);
}
stList.play();
}
}
});
btOrange.setOnAction((ActionEvent e) ->
{
guesses.add(ORANGE);
if(guesses.get(guessIndex) != colours.get(guessIndex) )
{
obStart.getChildren().add(btStart);
level = 1;
}
else
{
if(guesses.size() == colours.size())
{
level += 1;
guesses = new ArrayList<>();
for(int i = 0; i < level; i++)
{
obChange.handle(e);
}
stList.play();
}
}
});
}
class ChangeColour implements EventHandler<ActionEvent>
{
#Override
public void handle( ActionEvent arg0 )
{
thisGameScore = 0;
int randomColour = (int)((Math.random() * 4) + 1);
if(randomColour == RED)
{
colours.add(RED);
stList.getChildren().add(new RedTimeLine());
}
else if(randomColour == BLUE)
{
colours.add(BLUE);
stList.getChildren().add(tlBlue);
}
else if(randomColour == GREEN)
{
colours.add(GREEN);
stList.getChildren().add(tlGreen);
}
else if(randomColour == ORANGE)
{
colours.add(ORANGE);
stList.getChildren().add(tlOrange);
}
obStart.getChildren().remove(btStart);
}
}
ChangeColour obChange = new ChangeColour();
public static void main( String[] args )
{
Application.launch(args);
}
}
I guess I would do something like this:
public void playSequence(int sequenceLength, double speed) {
Timeline timeline = new Timeline();
for (int i = 0; i < sequenceLength; i++) {
Color color = colors[random.nextInt(colors.length)];
Segment segment = segmentMap.get(color);
timeline.getKeyFrames().addAll(
new KeyFrame(
Duration.seconds(i), new KeyValue(segment.litProperty(), true)
),
new KeyFrame(
Duration.seconds(i + 0.9), new KeyValue(segment.litProperty(), false)
)
);
isPlaying.set(true);
timeline.setOnFinished(event -> isPlaying.set(false));
timeline.setRate(speed);
timeline.play();
}
}
The above example uses a Timeline, with the start time at which each segment is lit varying to light each segment in sequence.
Full sample
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.Button;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import static javafx.scene.paint.Color.*;
public class SimpleSimon extends Application {
private int sequenceLength = 1;
private int speed = 1;
#Override
public void start(Stage stage) throws Exception {
Simon simon = new Simon();
Button play = new Button("Play");
play.setStyle("-fx-font-size: 20px;");
play.disableProperty().bind(simon.isPlayingProperty());
play.setOnAction(event -> {
simon.playSequence(sequenceLength, speed);
sequenceLength++;
speed *= 1.05;
});
VBox layout = new VBox(10, simon, play);
layout.setPadding(new Insets(10));
layout.setAlignment(Pos.CENTER);
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Simon extends Group {
private static final Random random = new Random(42);
private final Color[] colors = {
RED, GREEN, BLUE, ORANGE
};
private Map<Color, Segment> segmentMap = new HashMap<>();
private ReadOnlyBooleanWrapper isPlaying = new ReadOnlyBooleanWrapper();
public Simon() {
for (int i = 0; i < colors.length; i++) {
Segment segment = new Segment(colors[i], i * 90);
getChildren().add(segment);
segmentMap.put(colors[i], segment);
}
}
public void playSequence(int sequenceLength, double speed) {
Timeline timeline = new Timeline();
for (int i = 0; i < sequenceLength; i++) {
Color color = colors[random.nextInt(colors.length)];
Segment segment = segmentMap.get(color);
timeline.getKeyFrames().addAll(
new KeyFrame(
Duration.seconds(i), new KeyValue(segment.litProperty(), true)
),
new KeyFrame(
Duration.seconds(i + 0.9), new KeyValue(segment.litProperty(), false)
)
);
}
isPlaying.set(true);
timeline.setOnFinished(event -> isPlaying.set(false));
timeline.setRate(speed);
timeline.play();
}
public boolean isPlaying() {
return isPlaying.get();
}
public ReadOnlyBooleanWrapper isPlayingProperty() {
return isPlaying;
}
}
class Segment extends Arc {
private BooleanProperty lit = new SimpleBooleanProperty();
private static final double RADIUS = 100;
private static final ColorAdjust litEffect = new ColorAdjust(0, 0, 0.5, 0);
private static final ColorAdjust unlitEffect = new ColorAdjust(0, 0, 0, 0);
public Segment(Color color, double angleOffset) {
super(RADIUS, RADIUS, RADIUS, RADIUS, angleOffset, 90);
setFill(color);
setType(ArcType.ROUND);
setEffect(unlitEffect);
lit.addListener((observable, oldValue, newValue) ->
setEffect(lit.get() ? litEffect : unlitEffect)
);
}
public void setLit(boolean lit) {
this.lit.set(lit);
}
public boolean isLit() {
return lit.get();
}
public BooleanProperty litProperty() {
return lit;
}
}
A similar effect could be achieved via a SequentialTransition.
I am trying to do a neural network training visualization with JavaFX 8. The network cells are shown as dots changing their color depending on the output value. The calculations and the drawing are done in a thread that can be started or stopped by clicking a button. For a while everything works fine but after a number of iterations the display is no longer updated.
What needs to be done to reliably update the display?
I am using JRE version 1.8.0_45.
Here's a simplified version of my code:
import javafx.application.*;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.*;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
public class TestView extends Application {
public static final int SCENE_WIDTH = 1000;
public static final int SCENE_HEIGHT = 800;
public static final int BUTTON_PANEL_HEIGHT = 80;
private Canvas canvas;
private GraphicsContext gc;
private Task<Void> task = null;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("MLP");
BorderPane borderPane = new BorderPane();
canvas = new Canvas( SCENE_WIDTH, 3*SCENE_HEIGHT-BUTTON_PANEL_HEIGHT );
gc = canvas.getGraphicsContext2D();
borderPane.setCenter(new ScrollPane(canvas));
GridPane buttonPanel = new GridPane();
Button buttonTrain = new Button("Train");
buttonTrain.setMinWidth(SCENE_WIDTH/2);
buttonPanel.setPadding(new Insets(0, 0, 0, 0));
buttonPanel.add(buttonTrain, 1, 0);
borderPane.setBottom(buttonPanel);
buttonTrain.setOnMouseClicked( e -> {
if (task != null) {
task.cancel();
task = null;
}
else {
task = new Task<Void>() {
#Override
protected Void call() throws Exception {
for (int i = 1; i <= 10000000; i++) {
if (isCancelled()) {
break;
}
// dummy calculation
doSomeStuff();
// dummy graphics update
gc.setFill(Color.GREEN);
gc.fillOval(50, 50, 20, 20);
gc.clearRect(200, 10, 200, 100);
gc.setFill(Color.BLACK);
gc.fillText("" + i, 200, 50);
}
return null;
}
};
new Thread(task).start();
}
});
Scene scene = new Scene( borderPane, SCENE_WIDTH, SCENE_HEIGHT );
primaryStage.setScene(scene);
primaryStage.show();
}
private double doSomeStuff() {
double r = 0.5;
for ( int i = 0; i < 10000; i++ ) {
r = Math.sin(r);
}
return r;
}
}
I am trying to use two for loops to automatically add ImageView nodes to each location. When using the for loops I receive an error. When I comment the for loop code out with only one statement to add an ImageView node the code seems to work can you use for loops to populate GridPane? If so what am I doing wrong? If not what could be used as a solution?
My Class:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class GridCreation extends Application {
#Override
public void start(Stage gameStage) throws Exception {
GridPane grid = new GridPane();
Image backOfCardsImg = new Image("images/naruto_shipuden_logo.png");
ImageView backOfCards = new ImageView(backOfCardsImg);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
grid.add(backOfCards, i, j);
}
}
//grid.add(backOfCards, 1,1);
Scene scene = new Scene(grid);
gameStage.setTitle("MemoryGame");
gameStage.setScene(scene);
gameStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Edit: for the code:
grid.add(backOfCards, i, j);
I changed the line of code to
grid.add(new ImageView(backOfCardImg), i, j);
this seemed to solve the problem but can anyone explain to me why the first option wouldnt work?
This might be a usable start for a memory game in fx. It uses an own extension of ImageView to do the turn and focus animations and to deal with a common backside image. Its only graphics, no game logic.
public class MemoryGame extends Application {
final int rows = 4;
final int columns = 4;
CardView views[][] = new CardView[rows][];
public static class CardView extends ImageView {
static final double scale = 0.95;
static DropShadow shadowhoover = new DropShadow(5, 4, 4, Color.rgb(50, 60, 50));
static DropShadow shadowdown = new DropShadow(2, 2, 2, Color.rgb(50, 60, 50));
static Image backside = null;
public static void setbackside(Image image) { backside = image; }
public CardView(Image image) {
super(backside);
setRotationAxis(new Point3D(0, 200,0));
setScaleX(scale);
setScaleY(scale);
setEffect(shadowdown);
setOnMouseEntered(m -> {
setEffect(shadowhoover);
setScaleX(scale*1.01);
setScaleY(scale*1.01);
});
setOnMouseExited(m -> {
setEffect(shadowdown);
setScaleX(scale);
setScaleY(scale);
});
setOnMouseClicked(m -> {
RotateTransition r1 = new RotateTransition(Duration.millis(300), this);
r1.setByAngle(90);
r1.setOnFinished(e -> setImage(image));
RotateTransition r2 = new RotateTransition(Duration.millis(300), this);
r2.setByAngle(-90);
RotateTransition r3 = new RotateTransition(Duration.millis(300), this);
r3.setByAngle(90);
r3.setOnFinished(e -> setImage(backside));
RotateTransition r4 = new RotateTransition(Duration.millis(300), this);
r4.setByAngle(-90);
new SequentialTransition(r1, r2, new PauseTransition(Duration.millis(1000)), r3, r4).play();
});
}
}
#Override
public void start(Stage gameStage) throws Exception {
GridPane grid = new GridPane();
grid.setBackground(new Background(new BackgroundFill(Color.rgb(140, 200, 140), new CornerRadii(0), new Insets(0))));
grid.setHgap(5);
grid.setVgap(5);
Image back = new Image(MemoryGame.class.getResource("card-back.png").toExternalForm(), 140, 200, true, true);
Image front = new Image(MemoryGame.class.getResource("card-1.png").toExternalForm(), 140, 200, true, true);
CardView.setbackside(back);
for (int r = 0; r < rows; r++) {
views[r] = new CardView[columns];
for (int c = 0; c < columns; c++) {
CardView view = new CardView(front); // different front images of course...
views[r][c] = view;
HBox box = new HBox(5);
box.getChildren().add(views[r][c]);
grid.add(box, c, r);
}
}
//grid.add(backOfCards, 1,1);
Scene scene = new Scene(grid);
gameStage.setTitle("MemoryGame");
gameStage.setScene(scene);
gameStage.show();
}
public static void main(String[] args) {
launch(args);
}
}