TeoCB
TeoCB

Reputation: 23

javafx shape resize dynamically

i need to have an AnchorPane with a stroke around it that resizes when the stage is being resized, let me put some images to explain myself better:

enter image description here

i achieved this by using a Rectangle with fill color White and Alpha = 0 (its transparent), this is my fxml file:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="671.0" prefWidth="644.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
  <children>
  <Rectangle fill="#ffffff00" height="671.0" layoutX="91.0" layoutY="69.0" stroke="RED" strokeType="INSIDE" strokeWidth="10.0" width="644.0"  AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>

when i make the stage bigger i want the rectangle to resize and always fit exactly the size of the AnchorPane

but it doesn't work like that, instead i end up with this:

enter image description here

there is a way to bind the area of the rectangle to the area of the AnchorPane in which the rectangle is? or i am doing it wrong by using a shape for this and there is a more efficient way of achieving what i need?

One last thing! i need to be able to change the color of that stroke around the AnchorPane! Thanks so much, if you need any more information about my code or if my explanation it's too poor let me know and i will improve my question!

Upvotes: 2

Views: 6599

Answers (1)

James_D
James_D

Reputation: 209330

To achieve what you want the way you describe doing it, you can use a controller class and bind the size of the rectangle to the size of the pane:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="671.0" prefWidth="644.0" fx:controller="com.mycompany.myproject.Controller" fx:id="root" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
  <children>
      <Rectangle fx:id="border" fill="#ffffff00" height="671.0" layoutX="91.0" layoutY="69.0" stroke="RED" strokeType="INSIDE" strokeWidth="10.0" width="644.0"  AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
  </children>
</AnchorPane>

and then

package com.mycompany.myproject ;

import javafx.fxml.FXML ;
import javafx.scene.shape.Rectangle ;
import javafx.scene.layout.AnchorPane ;

public class Controller {

    @FXML
    private AnchorPane root ;
    @FXML
    private Rectangle border ;

    public void initialize() {
        border.widthProperty().bind(root.widthProperty());
        border.heightProperty().bind(border.heightProperty());
    }

}

You can change the color of the rectangle in the controller simply by calling border.setStroke(...);.


Using a Rectangle may not be the best way. You can omit the rectangle entirely, and use CSS to style the anchor pane itself. The CSS you need is

-fx-background-color: red, -fx-color ;
-fx-background-insets: 0, 10 ;

You could set this directly on the anchor pane:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="671.0" prefWidth="644.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"
    style="-fx-background-color: red, -fx-color ; -fx-background-insets: 0, 10 ;">

</AnchorPane>

but it's probably better to put it in an external style sheet:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="671.0" prefWidth="644.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">

</AnchorPane>

and then in your main class:

Parent root = FXMLLoader.load(getClass().getResource("path/to/fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add("my-stylesheet.css");
// ...

with my-stylesheet.css containing:

.root {
    -fx-background-color: red, -fx-color ;
    -fx-background-insets: 0, 10 ;
}

Finally, if you use a stylesheet like this, you can change the border color dynamically by using a looked-up color. Modify the stylesheet to:

.root {
    my-border-color: red ;
    -fx-background-color: my-border-color, -fx-color ;
    -fx-background-insets: 0, 10 ;
}

and then you can change the border at any time by calling

root.setStyle("my-border-color: green;")

where root is a reference to the anchor pane.

SSCCE

Here is a complete example using the last technique:

DynamicBorderColor.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.Button?>

<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller" fx:id="root" minWidth="600" minHeight="600">
    <Button text="Change Color" onAction="#changeColor" AnchorPane.topAnchor="20" AnchorPane.leftAnchor="20"/>
</AnchorPane>

Controller.java:

import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane;

public class Controller {

    private int colorIndex ;
    private String[] colors = {"red", "orange", "yellow", "green", "blue", "indigo", "violet"} ;

    @FXML
    private AnchorPane root ;

    @FXML
    private void changeColor() {
        colorIndex = (colorIndex + 1) % colors.length ;
        root.setStyle("border-color: "+colors[colorIndex]+";");
    }
}

DynamicBorderColor.java (main app class):

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class DynamicBorderColor extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        Scene scene = new Scene(FXMLLoader.load(getClass().getResource("DynamicBorderColor.fxml")));
        scene.getStylesheets().add("my-stylesheet.css");

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

my-stylesheet.css:

.root {
    border-color: red ;
    -fx-background-color: border-color, -fx-base ;
    -fx-background-insets: 0, 10 ;
}

Start:

enter image description here

Resize:

enter image description here

Press button a few times:

enter image description here

Upvotes: 3

Related Questions