I'm trying to combine 3 features into a single JavaFX class. My first feature displays "WELCOME TO JAVA" around in a circle. The second displays a 10x10 matrix of random 1's and 0's. The third displays a smiley face. They should be displayed one after the other in a single pane. I have the first and third features but the matrix one is throwing me off. Although everything is supposed to be in a single pane to display on the same GUI window (per professor), I don't see how else I could've done the matrix other than creating the gridPane. It displays fine without the size constraints, but then it takes up the entire screen and my other 2 features aren't visible. When I add the constraints, it gets small and the numbers aren't visible. I'm not sure how I can fix this. Can someone please help?
Pane pane = new Pane();
// Create a circle and set its properties
Circle circle = new Circle();
circle.setCenterX(100);
circle.setCenterY(100);
circle.setRadius(50);
circle.setStroke(null);
circle.setFill(null);
pane.getChildren().add(circle); // Add circle to the pane
//Display WELCOME TO JAVA with the text forming a circle
int i = 0;
String phrase = "WELCOME TO JAVA ";
double degree = 360 / phrase.length();
for (double degrees = 0; i < phrase.length(); i++, degrees += degree) {
double pointX = circle.getCenterX() + circle.getRadius() *
Math.cos(Math.toRadians(degrees));
double pointY = circle.getCenterY() + circle.getRadius() *
Math.sin(Math.toRadians(degrees));
Text letter = new Text(pointX, pointY, phrase.charAt(i) + "");
letter.setFill(Color.BLACK);
letter.setFont(Font.font("Times New Roman", FontWeight.BOLD, 20));
letter.setRotate(degrees + 90);
pane.getChildren().add(letter); }
//Create a 10x10 matrix of 1s and 0s
GridPane pane2 = new GridPane();
pane2.setHgap(1);
pane2.setVgap(1);
Button[][] matrix;
int length = 10;
int width = 10;
ArrayList<TextField> textFields = new ArrayList<>();
for (int y = 0; y < length; y++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(10);
pane2.getColumnConstraints().add(colConst);
for (int x = 0; x < width; x++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(10);
pane2.getRowConstraints().add(rowConst);
Random rand = new Random();
int random1 = rand.nextInt(2);
TextField textf = new TextField();
textf.setText("" + random1);
textf.setPrefSize(15, 15);
pane2.setRowIndex(textf, x);
pane2.setColumnIndex(textf, y);
pane2.getChildren().add(textf);
}}
//Create a smiley face
Circle circle2 = new Circle();
circle2.setCenterX(600.0f);
circle2.setCenterY(100.0f);
circle2.setRadius(50.0f);
circle2.setStroke(Color.BLACK);
circle2.setFill(null);
pane.getChildren().add(circle2);
Circle leftInnerEye = new Circle();
leftInnerEye.setCenterX(580.0f);
leftInnerEye.setCenterY(85.0f);
leftInnerEye.setRadius(5);
leftInnerEye.setStroke(Color.BLACK);
pane.getChildren().add(leftInnerEye);
Ellipse leftOutterEye = new Ellipse();
leftOutterEye.setCenterX(580.0f);
leftOutterEye.setCenterY(85.0f);
leftOutterEye.setRadiusX(11.0f);
leftOutterEye.setRadiusY(8.0f);
leftOutterEye.setStroke(Color.BLACK);
leftOutterEye.setFill(null);
pane.getChildren().add(leftOutterEye);
Circle rightEye = new Circle();
rightEye.setCenterX(620.0f);
rightEye.setCenterY(85.0f);
rightEye.setRadius(5);
rightEye.setStroke(Color.BLACK);
pane.getChildren().add(rightEye);
Ellipse rightOutterEye = new Ellipse();
rightOutterEye.setCenterX(620.0f);
rightOutterEye.setCenterY(85.0f);
rightOutterEye.setRadiusX(11.0f);
rightOutterEye.setRadiusY(8.0f);
rightOutterEye.setStroke(Color.BLACK);
rightOutterEye.setFill(null);
pane.getChildren().add(rightOutterEye);
Polygon nose = new Polygon();
nose.getPoints().setAll(
600d, 90d,
588d, 115d,
612d, 115d );
nose.setStroke(Color.BLACK);
nose.setFill(null);
pane.getChildren().add(nose);
Arc mouth = new Arc(600, 115, 30, 16, 180, 180);
mouth.setFill(null);
mouth.setType(ArcType.OPEN);
mouth.setStroke(Color.BLACK);
pane.getChildren().add(mouth);
HBox hbox = new HBox(pane, pane2);
hbox.autosize();
hbox.setAlignment(Pos.BASELINE_LEFT);
hbox.setPadding(new Insets(20));
// Create a scene and place it in the stage
Scene scene = new Scene(hbox, 1000, 500);
primaryStage.setTitle("Laura's Chapter 14"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
Create a pane for each feature and then add the features to either a VBox or HBox, that will root pane of the scene. That way you can have a GridPane for your second feature. There are different layouts available in JavaFX and they behave differently. Take a look at this documentation and its sub documentations.
Related
I have a sample 3D application (built by taking reference from the Javafx sample 3DViewer) which has a table created by laying out Boxes and Panes:
The table is centered wrt (0,0,0) coordinates and camera is at -z position initially.
It has the zoom-in/out based on the camera z position from the object.
On zooming in/out the object's boundsInParent increases/decreases i.e. area of the face increases/decreases. So the idea is to put more text when we have more area (always confining within the face) and lesser text or no text when the face area is too less. I am able to to do that using this node hierarchy:
and resizing the Pane (and managing the vBox and number of texts in it) as per Box on each zoom-in/out.
Now the issue is that table boundsInParent is giving incorrect results (table image showing the boundingBox off at the top) whenever a text is added to the vBox for the first time only. On further zooming-in/out gives correct boundingBox and does not go off.
Below is the UIpane3D class:
public class UIPane3D extends Pane
{
VBox textPane;
ArrayList<String> infoTextKeys = new ArrayList<>();
ArrayList<Text> infoTextValues = new ArrayList<>();
Rectangle bgCanvasRect = null;
final double fontSize = 16.0;
public UIPane3D() {
setMouseTransparent(true);
textPane = new VBox(2.0)
}
public void updateContent() {
textPane.getChildren().clear();
getChildren().clear();
for (Text textNode : infoTextValues) {
textPane.getChildren().add(textNode);
textPane.autosize();
if (textPane.getHeight() > getHeight()) {
textPane.getChildren().remove(textNode);
textPane.autosize();
break;
}
}
textPane.setTranslateY(getHeight() / 2 - textPane.getHeight() / 2.0);
bgCanvasRect = new Rectangle(getWidth(), getHeight());
bgCanvasRect.setFill(Color.web(Color.BURLYWOOD.toString(), 0.10));
bgCanvasRect.setVisible(true);
getChildren().addAll(bgCanvasRect, textPane);
}
public void resetInfoTextMap()
{
if (infoTextKeys != null || infoTextValues != null)
{
try
{
infoTextKeys.clear();
infoTextValues.clear();
} catch (Exception e){e.printStackTrace();}
}
}
public void updateInfoTextMap(String pKey, String pValue)
{
int index = -1;
boolean objectFound = false;
for (String string : infoTextKeys)
{
index++;
if(string.equals(pKey))
{
objectFound = true;
break;
}
}
if(objectFound)
{
infoTextValues.get(index).setText(pValue.toUpperCase());
}
else
{
if (pValue != null)
{
Text textNode = new Text(pValue.toUpperCase());
textNode.setFont(Font.font("Consolas", FontWeight.BLACK, FontPosture.REGULAR, fontSize));
textNode.wrappingWidthProperty().bind(widthProperty());
textNode.setTextAlignment(TextAlignment.CENTER);
infoTextKeys.add(pKey);
infoTextValues.add(textNode);
}
}
}
}
The code which get called at the last after all the manipulations:
public void refreshBoundingBox()
{
if(boundingBox != null)
{
root3D.getChildren().remove(boundingBox);
}
PhongMaterial blueMaterial = new PhongMaterial();
blueMaterial.setDiffuseColor(Color.web(Color.CRIMSON.toString(), 0.25));
Bounds tableBounds = table.getBoundsInParent();
boundingBox = new Box(tableBounds.getWidth(), tableBounds.getHeight(), tableBounds.getDepth());
boundingBox.setMaterial(blueMaterial);
boundingBox.setTranslateX(tableBounds.getMinX() + tableBounds.getWidth()/2.0);
boundingBox.setTranslateY(tableBounds.getMinY() + tableBounds.getHeight()/2.0);
boundingBox.setTranslateZ(tableBounds.getMinZ() + tableBounds.getDepth()/2.0);
boundingBox.setMouseTransparent(true);
root3D.getChildren().add(boundingBox);
}
Two things:
The table3D's boundsInParent is not updated properly when texts are added for the first time.
What would be the right way of putting texts on 3D nodes? I am having to manipulate a whole lot to bring the texts as required.
Sharing code here.
For the first question, about the "jump" that can be noticed just when after scrolling a new text item is laid out:
After digging into the code, I noticed that the UIPane3D has a VBox textPane that contains the different Text nodes. Every time updateContent is called, it tries to add a text node, but it checks that the vbox's height is always lower than the pane's height, or else the node will be removed:
for (Text textNode : infoTextValues) {
textPane.getChildren().add(textNode);
textPane.autosize();
if (textPane.getHeight() > getHeight()) {
textPane.getChildren().remove(textNode);
textPane.autosize();
break;
}
}
While this is basically correct, when you add a node to the scene, you can't get textPane.getHeight() immediately, as it hasn't been laid out yet, and you have to wait until the next pulse. This is why the next time you scroll, the height is correct and the bounding box is well placed.
One way to force the layout and get the correct height of the textNode is by forcing css and a layout pass:
for (Text textNode : infoTextValues) {
textPane.getChildren().add(textNode);
// force css and layout
textPane.applyCss();
textPane.layout();
textPane.autosize();
if (textPane.getHeight() > getHeight()) {
textPane.getChildren().remove(textNode);
textPane.autosize();
break;
}
}
Note that:
This method [applyCss] does not normally need to be invoked directly but may be used in conjunction with Parent.layout() to size a Node before the next pulse, or if the Scene is not in a Stage.
For the second question, about a different solution to add Text to 3D Shape.
Indeed, placing a (2D) text on top of a 3D shape is quite difficult, and requires complex maths (that are done quite nicely in the project, by the way).
There is an alternative avoiding the use of 2D nodes directly.
Precisely in a previous question, I "wrote" into an image, that later on I used as the material diffuse map of a 3D shape.
The built-in 3D Box places the same image into every face, so that wouldn't work. We can implement a 3D prism, or we can make use of the CuboidMesh node from the FXyz3D library.
Replacing the Box in UIPaneBoxGroup:
final CuboidMesh contentShape;
UIPane3D displaypane = null;
PhongMaterial shader = new PhongMaterial();
final Color pColor;
public UIPaneBoxGroup(final double pWidth, final double pHeight, final double pDepth, final Color pColor) {
contentShape = new CuboidMesh(pWidth, pHeight, pDepth);
this.pColor = pColor;
contentShape.setMaterial(shader);
getChildren().add(contentShape);
addInfoUIPane();
}
and adding the generateNet method:
private Image generateNet(String string) {
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
Label label5 = new Label(string);
label5.setFont(Font.font("Consolas", FontWeight.BLACK, FontPosture.REGULAR, 40));
GridPane.setHalignment(label5, HPos.CENTER);
grid.add(label5, 3, 1);
double w = contentShape.getWidth() * 10; // more resolution
double h = contentShape.getHeight() * 10;
double d = contentShape.getDepth() * 10;
final double W = 2 * d + 2 * w;
final double H = 2 * d + h;
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth(d * 100 / W);
ColumnConstraints col2 = new ColumnConstraints();
col2.setPercentWidth(w * 100 / W);
ColumnConstraints col3 = new ColumnConstraints();
col3.setPercentWidth(d * 100 / W);
ColumnConstraints col4 = new ColumnConstraints();
col4.setPercentWidth(w * 100 / W);
grid.getColumnConstraints().addAll(col1, col2, col3, col4);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight(d * 100 / H);
RowConstraints row2 = new RowConstraints();
row2.setPercentHeight(h * 100 / H);
RowConstraints row3 = new RowConstraints();
row3.setPercentHeight(d * 100 / H);
grid.getRowConstraints().addAll(row1, row2, row3);
grid.setPrefSize(W, H);
grid.setBackground(new Background(new BackgroundFill(pColor, CornerRadii.EMPTY, Insets.EMPTY)));
new Scene(grid);
return grid.snapshot(null, null);
}
Now all the 2D related code can be removed (including displaypane), and after a scrolling event get the image:
public void refreshBomUIPane() {
Image net = generateNet(displaypane.getText());
shader.setDiffuseMap(net);
}
where in UIPane3D:
public String getText() {
return infoTextKeys.stream().collect(Collectors.joining("\n"));
}
I've also removed the bounding box to get this picture:
I haven't played around with the number of text nodes that can be added to the VBox, the font size nor with an strategy to avoid generating images on every scroll: only when the text changes this should be done. So with the current approach is quite slow, but it can be improved notably as there are only three possible images for each box.
I posted a question here a couple weeks ago for some help on making a chess game and I got a great response and some code that demonstrates a solution to my problem. I have been trying to dissect the code and study it so I can better understand how it works. While doing this I ran into a question I can not seem to find an answer for. The chess board is made up of a 2d array of Regions and I am trying to add a MouseListener to each Region in the 2d array so that when a Region is pressed it will print out the row and column of the Region that was pressed. Right now nothing is happening when I press on a square in my screen and I can't not figure out why my MouseListener is not working.
public class Main extends Application {
GridPane root = new GridPane();
final int size = 8;
int col = 0;
int row = 0;
#Override
public void start(Stage primaryStage) {
try {
GridPane board = new GridPane();
Region[][] fields = new Region[8][8];
for (int i = 0; i < fields.length; i++) {
Region[] flds = fields[i];
for (int j = 0; j < flds.length; j++) {
Region field = new Region();
flds[j] = field;
field.setBackground(new Background(new BackgroundFill((i + j) % 2 == 0 ? Color.WHITE : Color.LIGHTBLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
board.addRow(i, flds);
}
for (int i = 0; i < fields.length; i++) {
col = i;
for (int j = 0; j < fields[i].length; j++) {
row = j;
fields[i][j].setOnMouseClicked(e->{
System.out.println("Col:" + col + ", Row" + row);
});
}
}
// use 1/8 of the size of the Grid for each field
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setPercentHeight(100d / 8);
ColumnConstraints columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(100d / 8);
for (int i = 0; i < 8; i++) {
board.getColumnConstraints().add(columnConstraints);
board.getRowConstraints().add(rowConstraints);
}
Pane piecePane = new Pane();
StackPane root = new StackPane(board, piecePane);
// NumberBinding boardSize = Bindings.min(root.widthProperty(), root.heightProperty());
NumberBinding boardSize = Bindings.min(root.widthProperty(), root.heightProperty());
// board size should be as large as possible but at most the min of the parent sizes
board.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
// same size for piecePane
piecePane.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
piecePane.maxWidthProperty().bind(boardSize);
piecePane.maxHeightProperty().bind(boardSize);
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Change:
StackPane root = new StackPane(board,piecePane);
to:
StackPane root = new StackPane(piecePane,board);
🐞?
Because the board was behind the piecePane it couldn't receive events.
Before you were using global variables col and row so these variables had always the same value of 7 and 7. Running the loop those variables where changing their value,but at the end they had the values 7 7 , here we need to use local variables col and row , so you need to add this modification:
for (int i = 0; i < fields.length; i++) {
int col = i;
for (int j = 0; j < fields[i].length; j++) {
int row = j;
fields[i][j].setOnMouseClicked(e -> System.out.println("Col:" + col + ", Row" + row));
}
}
I haven't worked much in JavaFX myself, though it is very similar to java swing regarding basic "collision".
There is a rectangle class with the methods contains and intersects. If you use MouseEvent to know the mouse coordinates and when the mouse is clicked. You can do something like this:
if(mouse.isClicked() && rect.contains(mouse.x, mouse.y) { // do stuff }
You need to create rectangle objects for all the squares though. Hope it works out.
EDIT: Noticed Regions also contained the methods contains and intersects - try these beforehand, use rectangles only if you must to skip too much object creation.
I have a chess board and I am trying to add pieces to the board. Every spot on the board is a Rectangle so I thought the best way to add pieces would be to add an ImagePattern to each Rectangle that gets a piece. The problem I encountered was when I added an ImagePattern to a Rectangle it would make the background of that Rectangle white despite what the color was before the ImagePattern was added. So my question is, is there a way for me to preserve the background color of a Rectangle after an ImagePattern is added?
For demo purposes my code only adds one piece to the board.
public class ChessBoard extends Application {
GridPane root = new GridPane();
final int size = 8;
public void start(Stage primaryStage) {
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
Rectangle square = new Rectangle();
Color color;
if ((row + col) % 2 == 0)
color = Color.WHITE;
else
color = Color.BLACK;
square.setFill(color);
root.add(square, col, row);
if(row == 4 && col == 3){
Image p = new Image("Peices/Black/0.png");
ImagePattern pat = new ImagePattern(p);
square.setFill(pat);
}
square.widthProperty().bind(root.widthProperty().divide(size));
square.heightProperty().bind(root.heightProperty().divide(size));
square.setOnMouseClicked(e->{
square.setFill(Color.BLUE);
});
}
}
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I think you are searching for blending which is done with the BlendMode. For example:
Image p = new Image("Peices/Black/0.png");
ImagePattern pat = new ImagePattern(p);
Rectangle r1 = new Rectangle();
r1.setX(50);
r1.setY(50);
r1.setWidth(50);
r1.setHeight(50);
r1.setFill(pat);
Rectangle r = new Rectangle();
r.setX(50);
r.setY(50);
r.setWidth(50);
r.setHeight(50);
r.setFill(Color.BLUE);
r.setBlendMode(BlendMode.ADD);
As far as I know there is no direct way to accomplish this.
Source: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/effect/BlendMode.html
No, you cannot use more than a single fill with a Rectangle. Theoretically you could use a Region with multiple backgrounds, but this is probably a bad idea. Most likely you'll want at least some of the following functionality for the pieces, which will not work, if you do not make pieces their own nodes:
Dragging a piece from one field to another
animating moves
I recommend using a StackPane and put the Board in the background and put a Pane on top of it to place the pieces. Simply use ImageViews for the pieces.
Example:
#Override
public void start(Stage primaryStage) {
GridPane board = new GridPane();
Region[][] fields = new Region[8][8];
for (int i = 0; i < fields.length; i++) {
Region[] flds = fields[i];
for (int j = 0; j < flds.length; j++) {
Region field = new Region();
flds[j] = field;
field.setBackground(new Background(new BackgroundFill((i + j) % 2 == 0 ? Color.WHITE : Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));
}
board.addRow(i, flds);
}
// use 1/8 of the size of the Grid for each field
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setPercentHeight(100d / 8);
ColumnConstraints columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(100d / 8);
for (int i = 0; i < 8; i++) {
board.getColumnConstraints().add(columnConstraints);
board.getRowConstraints().add(rowConstraints);
}
Pane piecePane = new Pane();
StackPane root = new StackPane(board, piecePane);
NumberBinding boardSize = Bindings.min(root.widthProperty(), root.heightProperty());
ImageView queen = new ImageView("https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Chess_qdt45.svg/480px-Chess_qdt45.svg.png");
DropShadow shadow = new DropShadow(BlurType.GAUSSIAN, Color.WHITE, 2, 1, 0, 0);
// drop shadow for black piece on black field
queen.setEffect(shadow);
// trigger move to topleft field on mouse click
queen.setOnMouseClicked(evt -> {
Node source = (Node) evt.getSource();
TranslateTransition animation = new TranslateTransition(Duration.seconds(0.5), source);
Region targetRegion = fields[0][0];
final PositionChangeListener listener = (PositionChangeListener) source.getUserData();
listener.setField(null);
animation.setByX(targetRegion.getLayoutX() - source.getLayoutX());
animation.setByY(targetRegion.getLayoutY() - source.getLayoutY());
animation.setOnFinished(e -> {
source.setTranslateX(0);
source.setTranslateY(0);
listener.setField(targetRegion);
});
animation.play();
});
PositionChangeListener changeListener = new PositionChangeListener(queen);
queen.setUserData(changeListener);
changeListener.setField(fields[4][3]);
// board size should be as large as possible but at most the min of the parent sizes
board.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
board.maxWidthProperty().bind(boardSize);
board.maxHeightProperty().bind(boardSize);
// same size for piecePane
piecePane.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
piecePane.maxWidthProperty().bind(boardSize);
piecePane.maxHeightProperty().bind(boardSize);
// add piece to piecePane
piecePane.getChildren().add(queen);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private static class PositionChangeListener implements ChangeListener<Bounds> {
private final ImageView piece;
public PositionChangeListener(ImageView piece) {
this.piece = piece;
}
private Region currentField;
public void setField(Region newRegion) {
// register/unregister listeners to bounds changes of associated field
if (currentField != null) {
currentField.boundsInParentProperty().removeListener(this);
}
currentField = newRegion;
if (newRegion != null) {
newRegion.boundsInParentProperty().addListener(this);
changed(null, null, newRegion.getBoundsInParent());
}
}
#Override
public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
// align piece with field
piece.setLayoutX(newValue.getMinX());
piece.setLayoutY(newValue.getMinY());
piece.setFitHeight(newValue.getHeight());
piece.setFitWidth(newValue.getWidth());
}
}
I have created circles on a graph in JavaFX, and I want to connect those circles with a polyline. Does anyone know the syntax for doing this? Thanks!
A Polyline may work, but you can do this easier, if you use the Path class, since this allows you to access to the individual elements of the path (PathElements). You can use bindings to bind the position of the line points to the positions of the circles. This way the lines will stay at the appropriate positions, even if you move the circles later.
Example
private static void bindLinePosTo(Circle circle, LineTo lineTo) {
lineTo.xProperty().bind(circle.centerXProperty());
lineTo.yProperty().bind(circle.centerYProperty());
}
private static void animate(Circle circle, Duration duration, double dy) {
Timeline animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(circle.centerYProperty(), circle.getCenterY())),
new KeyFrame(duration, new KeyValue(circle.centerYProperty(), circle.getCenterY()+dy)));
animation.setAutoReverse(true);
animation.setCycleCount(Animation.INDEFINITE);
animation.play();
}
#Override
public void start(Stage primaryStage) {
MoveTo start = new MoveTo();
LineTo line1 = new LineTo();
LineTo line2 = new LineTo();
Circle c1 = new Circle(10, 100, 5);
Circle c2 = new Circle(50, 100, 5);
Circle c3 = new Circle(100, 100, 5);
c1.setFill(Color.RED);
c2.setFill(Color.RED);
c3.setFill(Color.RED);
start.xProperty().bind(c1.centerXProperty());
start.yProperty().bind(c1.centerYProperty());
bindLinePosTo(c2, line1);
bindLinePosTo(c3, line2);
Path path = new Path(start, line1, line2);
Pane root = new Pane(path, c1, c2, c3);
animate(c1, Duration.seconds(1), 100);
animate(c2, Duration.seconds(2), 50);
animate(c3, Duration.seconds(0.5), 150);
Scene scene = new Scene(root, 110, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
Use the Binding API, e. g. like this.
I have to rewrite existing app, with SWT.
I'm adding FXCanvas class with JavaFX components on it.
I noticed that somehow my panes (usually, HBox'es) do not change size when I maximize window, for example.
My code is:
final Display display = parent.getDisplay();
shell = new Shell(display);
Group group = new Group();
scene = new Scene(group, Color.rgb(shell.getBackground().getRed(), shell.getBackground().getGreen(),
shell.getBackground().getBlue()));
fxCanvas = new FXCanvas(shell, SWT.NONE) {
#Override
public Point computeSize(int wHint, int hHint, boolean changed) {
getScene().getWindow().sizeToScene();
int width = (int) getScene().getWidth();
int height = (int) getScene().getHeight();
return new Point(width, height);
}
};
fxCanvas.setScene(scene);
HBox hbox = new HBox();
hbox.setPadding(new Insets(15, 12, 15, 12));
hbox.setSpacing(20); // Gap between nodes
group.getChildren().add(hbox);
Please advise.