I have some code, in javafx, that has a pane that works like a paint canvas. I need to be able to fill the background color of the pane from a color picker.
Currently I have a Color variable that gets the color chosen from the color picker and I try to set it to my Pane (named canvas) as below:
Color newColour = backgroundColourPicker.getValue();
canvas.setStyle("-fx-background-color: " + newColour + ";");
However I get this output:
June 11, 2022 7:47:57 PM javafx.css.CssParser term
WARNING: CSS Error parsing '*{-fx-background-color: 0x00ffffff;}: Unexpected token '0x' at [1,24]
How do I either swap my Color value to a String to be able to remove the leading 0x and make it work or how do I get my Pane to accept the color value as a Color?
I have found this code worked for me if anyone needs it in the future:
Color newColour = backgroundColourPicker.getValue();
Double red = newColour.getRed()*100;
int rInt = red.intValue();
Double green = newColour.getGreen()*100;
int gInt = green.intValue();
Double blue = newColour.getBlue()*100;
int bInt = blue.intValue();
String hex = String.format("#%02X%02X%02X", rInt, gInt, bInt);
canvas.setStyle("-fx-background-color: " + hex + ";");
If you don't require all the features of the region's background—image, fills, etc.— and a solid color will suffice, also consider binding the color picker's value property to the fill color of a suitable Shape that fills the region. Based on the examples seen here, the variation below illustrates a ColorPane that renders a Rectangle whose size is bound to the enclosing Pane and whose color is bound to an ObjectProperty<Color> holding the rectangle's color. A similar arrangement is made for the foreground Circle. One benefit is that a custom color updates live as the the controls are adjusted. Several related examples are collected here.
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
* #see https://stackoverflow.com/q/72583321/230513
* #see https://stackoverflow.com/a/70312046/230513
*/
public class ColorTest extends Application {
private final class ColorPane extends Pane {
public static final Color bgColor = Color.BLUE;
public static final Color fgColor = Color.CYAN;
private final Rectangle r = new Rectangle();
private final Circle c = new Circle(8, fgColor);
private final ObjectProperty<Color> bg = new SimpleObjectProperty<>(bgColor);
private final ObjectProperty<Color> fg = new SimpleObjectProperty<>(fgColor);
private final InvalidationListener listener = (o) -> update();
public ColorPane() {
this.setPrefSize(256, 256);
r.widthProperty().bind(this.widthProperty());
r.heightProperty().bind(this.heightProperty());
r.setFill(bgColor);
this.getChildren().add(r);
c.centerXProperty().bind(widthProperty().divide(2));
c.centerYProperty().bind(heightProperty().divide(2));
NumberBinding diameter = Bindings.min(widthProperty(), heightProperty());
c.radiusProperty().bind(diameter.divide(2).subtract(diameter.divide(10)));
this.getChildren().add(c);
bg.addListener(listener);
fg.addListener(listener);
}
private void update() {
r.setFill(bg.get());
c.setFill(fg.get());
}
public ObjectProperty<Color> bgProperty() {
return bg;
}
public ObjectProperty<Color> fgProperty() {
return fg;
}
}
private Pane createControlPane(ColorPane view) {
ColorPicker bgPicker = new ColorPicker(view.bgProperty().get());
bgPicker.setTooltip(new Tooltip("Background color."));
view.bgProperty().bindBidirectional(bgPicker.valueProperty());
ColorPicker fgPicker = new ColorPicker(view.fgProperty().get());
fgPicker.setTooltip(new Tooltip("Foreground color."));
view.fgProperty().bindBidirectional(fgPicker.valueProperty());
return new VBox(16, bgPicker, fgPicker);
}
#Override
public void start(Stage stage) {
var root = new BorderPane();
ColorPane colorPane = new ColorPane();
root.setCenter(colorPane);
root.setLeft(createControlPane(colorPane));
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you do require features of the region's background, the following example illustrates dynamically replacing the background of a GradientPane with one that contains a LinearGradient based on the chosen color properties. The approach has the same benefit of live custom color updates as the the controls are adjusted, illustrated above.
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
/**
* #see https://stackoverflow.com/q/72583321/230513
* #see https://stackoverflow.com/a/70312046/230513
*/
public class ColorTest extends Application {
private final class GradientPane extends Pane {
public static final Color c1Color = Color.BLUE;
public static final Color c2Color = Color.CYAN;
private final Circle c = new Circle(8, c2Color);
private final ObjectProperty<Color> c1 = new SimpleObjectProperty<>(c1Color);
private final ObjectProperty<Color> c2 = new SimpleObjectProperty<>(c2Color);
private final InvalidationListener listener = (o) -> update();
public GradientPane() {
this.setPrefSize(256, 256);
c.centerXProperty().bind(widthProperty().divide(2));
c.centerYProperty().bind(heightProperty().divide(2));
NumberBinding diameter = Bindings.min(widthProperty(), heightProperty());
c.radiusProperty().bind(diameter.divide(2).subtract(diameter.divide(10)));
this.getChildren().add(c);
c1.addListener(listener);
c2.addListener(listener);
update();
}
private void update() {
Stop[] stops = new Stop[]{new Stop(0, c1.get()), new Stop(1, c2.get())};
LinearGradient lg = new LinearGradient(0.5, 0, 0.5, 1, true, CycleMethod.NO_CYCLE, stops);
this.setBackground(new Background(new BackgroundFill(lg, CornerRadii.EMPTY, Insets.EMPTY)));
stops = new Stop[]{new Stop(0, c2.get()), new Stop(1, c1.get())};
lg = new LinearGradient(0.5, 0, 0.5, 1, true, CycleMethod.NO_CYCLE, stops);
c.setFill(lg);
}
public ObjectProperty<Color> c1Property() {
return c1;
}
public ObjectProperty<Color> c2Property() {
return c2;
}
}
private Pane createControlPane(GradientPane view) {
ColorPicker bgPicker = new ColorPicker(view.c1Property().get());
bgPicker.setTooltip(new Tooltip("Color stop one."));
view.c1Property().bindBidirectional(bgPicker.valueProperty());
ColorPicker fgPicker = new ColorPicker(view.c2Property().get());
fgPicker.setTooltip(new Tooltip("Color stop two."));
view.c2Property().bindBidirectional(fgPicker.valueProperty());
VBox vBox = new VBox(10, bgPicker, fgPicker);
vBox.setPadding(new Insets(10));
return vBox;
}
#Override
public void start(Stage stage) {
var root = new BorderPane();
GradientPane colorPane = new GradientPane();
root.setCenter(colorPane);
root.setLeft(createControlPane(colorPane));
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
i was searching for answer and trying so many options. Finally i found way to pass my own javaxf object to GridPane. But I still think there is a better way to this than I am doing.
So here is my code:
Main:
package sample;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.layout.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import static java.lang.String.valueOf;
public class Main extends Application {
private My_Rectangle selectedShelf;
Stage window;
GridPane grid;
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
BackgroundFill background_fill = new BackgroundFill(Color.PINK,
CornerRadii.EMPTY, Insets.EMPTY);
Background background = new Background(background_fill);
grid = new GridPane();
grid.setBackground(background);
grid.setPadding(new Insets(10,10,10,10));
grid.setVgap(10);
grid.setHgap(10);
grid.setAlignment(Pos.CENTER);
for (int i = 0; i<10;i++){
for(int y = 0; y<10;y++){
My_Rectangle rect = new My_Rectangle(grid,i,y,new Text( valueOf(i+y)) );
}
}
Scene scene = new Scene(grid, 400, 400);
window.setScene(scene);
window.show();
}
public static void main(String[] args) {
launch(args);
}
}
package sample;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
public class My_Rectangle {
private float wide;
private float height;
private final Rectangle rect;
private boolean selected;
public My_Rectangle( GridPane cheff, int x, int y, Text text) {
wide = 20;
height = 30;
selected = false;
rect = new Rectangle(wide,height);
rect.setFill(Color.GREEN);
text.setTextAlignment(TextAlignment.CENTER);
EventHandler<MouseEvent> clickedHandler = ev -> {
selected = !selected;
this.selected();
ev.consume();
};
rect.setOnMouseClicked(clickedHandler);
cheff.add(rect, x ,y );
cheff.add(text, x ,y );
}
public void selected() {
if (selected) {
rect.setFill(Color.GREEN);
ShelfShowUp.display("KOKOS", 7);
} else {
rect.setFill(Color.HOTPINK);
}
}
}
By better way I mean, that there might be other way than passing GridPane and int x, int y indexes. I still wanna use GridPane.
Thank you for any Help
I am new to this
As #JimD already commented, embedding a reference to the parent of a Node into a node is bad practice. There's nothing special about the Rectangles other than the event handler which toggles the colour. Assuming that you don't want to access the "selected" state of the Rectangles, you can ditch the custom class altogether.
The following code does everything that your sample does, except the call to the [not included] "ShelfShowUp.display("KOKOS", 7)" :
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import static java.lang.String.valueOf;
public class GridPaneCustom extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
GridPane grid = new GridPane();
grid.setBackground(new Background(new BackgroundFill(Color.PINK, CornerRadii.EMPTY, Insets.EMPTY)));
grid.setPadding(new Insets(10));
grid.setVgap(10);
grid.setHgap(10);
grid.setAlignment(Pos.CENTER);
for (int column = 0; column < 10; column++) {
for (int row = 0; row < 10; row++) {
Rectangle rectangle = new Rectangle(20, 30, Color.HOTPINK);
rectangle.setOnMouseClicked(ev -> rectangle.setFill(
rectangle.getFill().equals(Color.HOTPINK) ? Color.GREEN : Color.HOTPINK));
grid.add(rectangle, column, row);
grid.add(new Text(valueOf(column + row)), column, row);
}
}
primaryStage.setScene(new Scene(grid, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In the application I need to create, I have a series of points which are connected by lines. I need to only see the line part of the graph and hide the points. However, I need to mark certain points by clicking on the appropriate places in the graph. In the code I have written I am either able to hide the points and not able to mark or I am able to mark but not hide the rest of the points. What do I do to hide the points and mark the required points?
package application;
import java.awt.Dimension;
import java.awt.Toolkit;
//import java.beans.EventHandler;
import java.util.ArrayList;
import javafx.event.EventHandler;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.Scene;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Main extends Application {
public XYChart.Data<Integer, Integer> k = new XYChart.Data();
public XYChart.Series series;
String pth;
public ObservableList<XYChart.Data<Integer, Integer>> dat = FXCollections.<XYChart.Data<Integer, Integer>>observableArrayList();
public int c = 0;
ArrayList<Integer> myListx = new ArrayList<Integer>();
public void start(Stage stage) {
stage.setTitle("Line Chart Sample");
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Samples");
yAxis.setLabel("Data");
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setCreateSymbols(false);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) screenSize.getWidth();
int height = (int) screenSize.getHeight();
StackPane spLineChart = new StackPane();
spLineChart.getChildren().add(lineChart);
while (c < 20) {
k = new XYChart.Data<Integer, Integer>(c++, c * 6);
dat.add(k);
k.setNode(new Node(c));
}
series = new XYChart.Series("IMU Data", dat);
lineChart.getData().addAll(series);
xAxis.setVisible(true);
yAxis.setVisible(true);
spLineChart.setVisible(true);
StackPane spButton = new StackPane();
StackPane sp = new StackPane();
VBox vbox = new VBox();
VBox.setVgrow(spLineChart, Priority.ALWAYS);
vbox.getChildren().addAll(sp, spLineChart, spButton);
Scene scene = new Scene(vbox, width, height - 500);
stage.setScene(scene);
stage.show();
}
class Node extends StackPane {
Node(int priorValue) {
final Circle circle = createData();
setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
getChildren().setAll(circle);
myListx.add(priorValue);
} else if (mouseEvent.getButton().equals(MouseButton.SECONDARY)) {
getChildren().clear();
myListx.remove(new Integer(priorValue));
}
}
;
});
}
private Circle createData() {
Circle circle = new Circle();
circle.setFill(Color.BLACK);
circle.setStroke(Color.BLACK);
circle.setRadius(4);
return circle;
}
}
public static void main(String[] args) {
launch(args);
}
}
Use this modified Node class. Where on-mouse click event, it toggles the effect as per the existence of its children.
class Node extends StackPane {
Node(int priorValue) {
setOnMouseClicked(event -> {
if (getChildren().isEmpty()) {
final Circle circle = createData();
getChildren().setAll(circle);
} else {
getChildren().clear();
}
myListx.add(priorValue);
});
}
private Circle createData() {
Circle circle = new Circle();
circle.setFill(Color.BLACK);
circle.setStroke(Color.BLACK);
circle.setRadius(4);
return circle;
}
}
Note: You may consider renaming your class Node as it clashes with Node.
I have two circles that I want to turn them around a pivot clockwise if the right key is pressed and counter clockwise if the left key is pressed but my code does not work.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.*;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Font;
import javafx.scene.transform.Rotate;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.util.Duration;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
public class Main extends Application {
public static final double CIRCLES_CENTER_X = 600;
public static final double CIRCLES_CENTER_Y = 450;
public static final double CIRCLES_RADIUS = 15;
public static final double CIRCLES_DISTANCE = 300;
public static final double GAME_HEIGHT = 700;
public static final double GAME_WIDTH = 1200;
private Stage primaryStage;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
primaryStage.setMinWidth(GAME_WIDTH);
primaryStage.setMinHeight(GAME_HEIGHT);
final Scene scene;
BorderPane root = new BorderPane();
scene = new Scene(root, Main.GAME_WIDTH, Main.GAME_HEIGHT);
Circle orangeCircle = new Circle(Main.CIRCLES_CENTER_X + Main.CIRCLES_DISTANCE / 2 * cos(0),
Main.CIRCLES_CENTER_Y + Main.CIRCLES_DISTANCE / 2 * sin(0),
Main.CIRCLES_RADIUS, Color.ORANGE);
Circle yellowCircle = new Circle(Main.CIRCLES_CENTER_X - Main.CIRCLES_DISTANCE / 2 * cos(0),
Main.CIRCLES_CENTER_Y - Main.CIRCLES_DISTANCE / 2 * sin(0),
Main.CIRCLES_RADIUS, Color.YELLOW);
Pane game = new Pane(orangeCircle, yellowCircle);
root.setCenter(game);
SimpleIntegerProperty angle = new SimpleIntegerProperty(0);
root.setOnKeyPressed(ke -> {
if (ke.getCode().toString().equals("RIGHT")) {
angle.set(360);
}
if (ke.getCode().toString().equals("LEFT")) {
angle.set(-360);
}
});
root.setOnKeyReleased(ke -> {
if (ke.getCode().toString().equals("RIGHT")) {
angle.set(0);
}
if (ke.getCode().toString().equals("LEFT")) {
angle.set(0);
}
});
Rotate orangeCircleRotation = new Rotate(0, Main.CIRCLES_CENTER_X, Main.CIRCLES_CENTER_Y);
orangeCircle.getTransforms().add(orangeCircleRotation);
Rotate yellowCircleRotation = new Rotate(0, Main.CIRCLES_CENTER_X, Main.CIRCLES_CENTER_Y);
yellowCircle.getTransforms().add(yellowCircleRotation);
Timeline rotationAnimation = new Timeline();
rotationAnimation.setCycleCount(Timeline.INDEFINITE);
angle.addListener((ov, old_val, new_val) -> {
System.out.println("fk");
rotationAnimation.stop();
while (rotationAnimation.getKeyFrames().size() > 0) {
rotationAnimation.getKeyFrames().remove(0);
}
rotationAnimation.getKeyFrames().add(
new KeyFrame(Duration.millis(2000),
new KeyValue(orangeCircleRotation.angleProperty(), angle.getValue())));
rotationAnimation.getKeyFrames().add(
new KeyFrame(Duration.millis(2000),
new KeyValue(yellowCircleRotation.angleProperty(), angle.getValue())));
rotationAnimation.play();
}
);
primaryStage.setScene(scene);
primaryStage.show();
}
public Stage getPrimaryStage() {
return primaryStage;
}
}
It works almost fine but when i press a key and release it the circles does not stop. they just start turning backward until the last rotation change point and keep repeating that so also when i press the key again it jumps sometimes.(Because the backward turn has reached its end and starts from the beginning)(Hard to explain!you have to see it for yourself!)
Does anyone know how to fix or achieve this?
I wouldn't try to manipulate the key frames while the animation is in progress. Instead you can just pause/play the animation and change the rate. The only "gotcha" here is that it seems the animation ignores the change in rate if it is paused, so you need to call play() before setRate(...).
Here's the modified SSCCE:
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
public class RotatingCircles extends Application {
public static final double CIRCLES_CENTER_X = 600;
public static final double CIRCLES_CENTER_Y = 450;
public static final double CIRCLES_RADIUS = 15;
public static final double CIRCLES_DISTANCE = 300;
public static final double GAME_HEIGHT = 700;
public static final double GAME_WIDTH = 1200;
private Stage primaryStage;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
primaryStage.setMinWidth(GAME_WIDTH);
primaryStage.setMinHeight(GAME_HEIGHT);
final Scene scene;
BorderPane root = new BorderPane();
scene = new Scene(root, GAME_WIDTH, GAME_HEIGHT);
Circle orangeCircle = new Circle(CIRCLES_CENTER_X + CIRCLES_DISTANCE / 2 * cos(0),
CIRCLES_CENTER_Y + CIRCLES_DISTANCE / 2 * sin(0),
CIRCLES_RADIUS, Color.ORANGE);
Circle yellowCircle = new Circle(CIRCLES_CENTER_X - CIRCLES_DISTANCE / 2 * cos(0),
CIRCLES_CENTER_Y - CIRCLES_DISTANCE / 2 * sin(0),
CIRCLES_RADIUS, Color.YELLOW);
Pane game = new Pane(orangeCircle, yellowCircle);
root.setCenter(game);
Rotate orangeCircleRotation = new Rotate(0, CIRCLES_CENTER_X, CIRCLES_CENTER_Y);
orangeCircle.getTransforms().add(orangeCircleRotation);
Rotate yellowCircleRotation = new Rotate(0, CIRCLES_CENTER_X, CIRCLES_CENTER_Y);
yellowCircle.getTransforms().add(yellowCircleRotation);
Timeline rotationAnimation = new Timeline();
rotationAnimation.setCycleCount(Timeline.INDEFINITE);
rotationAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(2), new KeyValue(orangeCircleRotation.angleProperty(), 360)));
rotationAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(2), new KeyValue(yellowCircleRotation.angleProperty(), 360)));
root.setOnKeyPressed(ke -> {
if (ke.getCode() == KeyCode.RIGHT) {
rotationAnimation.play();
rotationAnimation.setRate(1);
} else if (ke.getCode() == KeyCode.LEFT) {
rotationAnimation.play();
rotationAnimation.setRate(-1);
}
});
root.setOnKeyReleased(ke -> {
rotationAnimation.pause();
});
primaryStage.setScene(scene);
primaryStage.show();
root.requestFocus();
}
public Stage getPrimaryStage() {
return primaryStage;
}
}
BTW In this code you really don't need two separate rotations, since they are identical. Just create a single rotation and add it to both circles' transforms lists. It may be different in your real code, of course...
This is my first project in Java and JavaFX. I have most of the work done but I need a button that does something. I used things found in different tutorials but my button still doesn't work. Nothing happens when I click it. I will be VERY thankful for any tips. Please find a picture of my application attached so that you can understand better what the code draws. Here is my code (button is called b1):
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package po_javafx;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import static javafx.scene.paint.Color.CORNSILK;
import static javafx.scene.paint.Color.DARKGOLDENROD;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineBuilder;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PO_JavaFX extends Application {
public static World world = new World("Game");
static protected int width;
static protected int height;
static protected int civilOffsetX;
static protected int civilOffsetY;
static protected int bossOffsetX;
static protected int bossOffsetY;
static protected int heroOffsetX;
static protected int heroOffsetY;
/**
* #return the civilOffsetX
*/
public static int getCivilOffsetX() {
return civilOffsetX;
}
/**
* #param aCivilOffsetX the civilOffsetX to set
*/
public static void setCivilOffsetX(int aCivilOffsetX) {
civilOffsetX = aCivilOffsetX;
}
/**
* #return the civilOffsetY
*/
public static int getCivilOffsetY() {
return civilOffsetY;
}
/**
* #param aCivilOffsetY the civilOffsetY to set
*/
public static void setCivilOffsetY(int aCivilOffsetY) {
civilOffsetY = aCivilOffsetY;
}
/**
* #return the bossOffsetX
*/
public static int getBossOffsetX() {
return bossOffsetX;
}
/**
* #param aBossOffsetX the bossOffsetX to set
*/
public static void setBossOffsetX(int aBossOffsetX) {
bossOffsetX = aBossOffsetX;
}
/**
* #return the bossOffsetY
*/
public static int getBossOffsetY() {
return bossOffsetY;
}
/**
* #param aBossOffsetY the bossOffsetY to set
*/
public static void setBossOffsetY(int aBossOffsetY) {
bossOffsetY = aBossOffsetY;
}
/**
* #return the heroOffsetX
*/
public static int getHeroOffsetX() {
return heroOffsetX;
}
/**
* #param aHeroOffsetX the heroOffsetX to set
*/
public static void setHeroOffsetX(int aHeroOffsetX) {
heroOffsetX = aHeroOffsetX;
}
/**
* #return the heroOffsetY
*/
public static int getHeroOffsetY() {
return heroOffsetY;
}
/**
* #param aHeroOffsetY the heroOffsetY to set
*/
public static void setHeroOffsetY(int aHeroOffsetY) {
heroOffsetY = aHeroOffsetY;
}
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
setWidth(1400);
setHeight(1000);
Canvas background = new Canvas(getWidth(), getHeight());
final GraphicsContext context = background.getGraphicsContext2D();
File f = new File("background.png");
final Image image = new Image(new FileInputStream(f));
root.getChildren().add(background);
Button b1 = new Button("Spawn Civilian");
b1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
root.getChildren().add(b1);
b1.setLayoutX(1300);
b1.setLayoutY(10);
Canvas animation = new Canvas(getWidth(), getHeight());
Canvas animation2 = new Canvas(getWidth(), getHeight());
final GraphicsContext context2 = animation.getGraphicsContext2D();
final GraphicsContext context3 = animation2.getGraphicsContext2D();
File overlay100 = new File("close.png");
final Image but1;
but1 = new Image(new FileInputStream(overlay100));
File overlay = new File("cywil.png");
final Image cywil;
cywil = new Image(new FileInputStream(overlay));
File overlay2 = new File("city.png");
final Image miasto;
miasto = new Image(new FileInputStream(overlay2));
File overlay3 = new File("cross.png");
final Image skrzyzowanie;
skrzyzowanie = new Image(new FileInputStream(overlay3));
File overlay6 = new File("koksu.png");
final Image koksu = new Image(new FileInputStream(overlay6));
File overlay9 = new File("najman.png");
final Image najman = new Image(new FileInputStream(overlay9));
root.getChildren().add(animation);
root.getChildren().add(animation2);
Scene scene = new Scene(root, getWidth(), getHeight());
stage.setTitle("Old Gotham");
stage.setScene(scene);
stage.show();
final Duration oneFrameAmt = Duration.millis(1000 / 60);
final KeyFrame oneFrame = new KeyFrame(oneFrameAmt,
new EventHandler() {
#Override
public void handle(Event event) {
context2.drawImage(image, 0, 0);
//context2.drawImage(but1, 1250, 100, 100, 100);
int offset = 700;
context2.setLineWidth(5.0);
context2.setStroke(DARKGOLDENROD);
for (Road road : World.roads) {
if (road.getOrientation().equals("horizontal")) {
context2.strokeLine(road.getX(), road.getY(), road.getX2(), road.getY2());
} else if (road.getOrientation().equals("vertical")) {
context2.strokeLine(road.getX(), road.getY(), road.getX2(), road.getY2());
}
}
for (City city : World.cities) {
context3.drawImage(miasto, city.getX() - offset / 2, city.getY() - offset / 2, offset, offset);
}
int crossroadOffsetX = 150;
int crossroadOffsetY = 100;
for (Crossroad crossroad : World.crossroads) {
context2.drawImage(skrzyzowanie, crossroad.getX() - crossroadOffsetX / 2, crossroad.getY() - crossroadOffsetY / 2 + 20, crossroadOffsetX, crossroadOffsetY);
}
setCivilOffsetX(70);
setCivilOffsetY(40);
for (Civilian civilian : World.civilians) {
context2.drawImage(cywil, civilian.getX() - getCivilOffsetX() / 2, civilian.getY() - getCivilOffsetY() / 2, getCivilOffsetX(), getCivilOffsetY());
}
setBossOffsetX(70);
setBossOffsetY(40);
for (Boss boss : World.bosses) {
context2.drawImage(najman, boss.getX() - getBossOffsetX() / 2, boss.getY() - getBossOffsetY() / 2, getBossOffsetX(), getBossOffsetY());
}
setHeroOffsetX(70);
setHeroOffsetY(40);
for (SuperHero hero : World.superheroes) {
context2.drawImage(koksu, hero.getX() - getHeroOffsetX() / 2, hero.getY() - getHeroOffsetY() / 2, getHeroOffsetX(), getHeroOffsetY());
}
}
});
final Timeline tl = new Timeline(oneFrame);
tl.setCycleCount(Animation.INDEFINITE);
tl.play();
}
public static void main(String[] args) {
launch(args);
}
/**
* #return the width
*/
public static int getWidth() {
return width;
}
/**
* #param width the width to set
*/
public void setWidth(int width) {
this.width = width;
}
/**
* #return the height
*/
public static int getHeight() {
return height;
}
/**
* #param height the height to set
*/
public void setHeight(int height) {
this.height = height;
}
}
The Canvas instances you are adding to the root Pane after you add the button (animation and animation2) have the size of the scene, and these are covering everything below them, including the button, so you can't click on the button.
As a first simple solution, you can make these canvases transparent:
animation.setMouseTransparent(true);
animation2.setMouseTransparent(true);
But you can benefit from using different layouts, so you can have the graphic area in one pane and the controls in other. For instance, you could use a BorderPane. Something like this:
BorderPane root = new BorderPane();
Pane paneCenter= new Pane();
Canvas background= new Canvas(1200,1000);
Canvas animation = new Canvas(1200,1000);
Canvas animation2 = new Canvas(1200,1000);
paneCenter.getChildren().addAll(background, animation, animation2);
root.setCenter(paneCenter);
VBox paneRight = new VBox();
paneRight.setPrefSize(200, 1000);
paneRight.setPadding(new Insets(20));
paneRight.setAlignment(Pos.TOP_CENTER);
Button b1 = new Button("Spawn Civilian");
paneRight.getChildren().add(b1);
root.setRight(paneRight);
Scene scene = new Scene(root, 1400, 1000);
What I want to do is scale an image on a cylinder in Java3D. The code I have so far is shown below. I have no clue how to make the image not stretch over the whole cylinder.
package javafxapplication2;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.paint.Material;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class EarthCylinder extends Application {
double anchorX, anchorY;
private double anchorAngleX = 0;
private double anchorAngleY = 0;
private final DoubleProperty angleX = new SimpleDoubleProperty(0);
private final DoubleProperty angleY = new SimpleDoubleProperty(0);
PerspectiveCamera scenePerspectiveCamera = new PerspectiveCamera(false);
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// Remove this line once dirtyopts bug is fixed for 3D primitive
System.setProperty("prism.dirtyopts", "false");
launch(args);
}
#Override
public void start(Stage primaryStage) {
Image diffuseMap
= new Image(EarthCylinder.class
.getResource("download.jpg")
.toExternalForm());
PhongMaterial material = new PhongMaterial();
material.setDiffuseMap(diffuseMap);
final Cylinder cylinder = new Cylinder(200, 400);
cylinder.setMaterial(material);
final Group parent = new Group(cylinder);
parent.setTranslateX(450);
parent.setTranslateY(450);
parent.setTranslateZ(0);
Rotate xRotate;
Rotate yRotate;
parent.getTransforms().setAll(
xRotate = new Rotate(0, Rotate.X_AXIS),
yRotate = new Rotate(0, Rotate.Y_AXIS));
xRotate.angleProperty().bind(angleX);
yRotate.angleProperty().bind(angleY);
final Group root = new Group();
root.getChildren().add(parent);
final Scene scene = new Scene(root, 900, 900, true);
scene.setFill(Color.BLACK);
scene.setOnMousePressed(event -> {
anchorX = event.getSceneX();
anchorY = event.getSceneY();
anchorAngleX = angleX.get();
anchorAngleY = angleY.get();
});
scene.setOnMouseDragged(event -> {
angleX.set(anchorAngleX - (anchorY - event.getSceneY()));
angleY.set(anchorAngleY + anchorX - event.getSceneX());
});
PointLight pointLight = new PointLight(Color.WHITE);
pointLight.setTranslateX(400);
pointLight.setTranslateY(400);
pointLight.setTranslateZ(-3000);
scene.setCamera(scenePerspectiveCamera);
root.getChildren().addAll(pointLight, scenePerspectiveCamera);
primaryStage.setScene(scene);
primaryStage.show();
}
}
The result of the above code is shown here: