Objective

In this example we are going to create a RoundedRectangle shape with two sliders as per the image below:

002-drawingshapes

By moving the slider inside the shape, we will change the curvature on the corners of the shape:

003-drawingshapes

By moving the slider underneath the shape, we will move the shape (and the slider within it) up and down the page:

004-drawingshapes

 

The Code

Create the class examples001.DrawingShapes.java as follows:

DrawingShapes

package examples001;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeLineCap;
import javafx.stage.Stage;

/**
 *
 * @author johndunning
 */
public class DrawingShapes extends Application
{

    @Override
    public void start(Stage primaryStage)
    {
        primaryStage.setTitle("Drawing Shapes");

        //

        Group root = new Group();
        Scene scene = new Scene(root, 500, 260);

        //

        Rectangle roundRect = new Rectangle(50,50,400,130);

        roundRect.setArcWidth(30);
        roundRect.setArcHeight(60);

        roundRect.setFill(null);
        roundRect.setStroke(Color.DARKORANGE);
        roundRect.setStrokeWidth(2);
        roundRect.setStrokeLineCap(StrokeLineCap.BUTT);

        root.getChildren().add(roundRect);

        //

        Slider slider = new Slider(30,150,30);
        slider.setLayoutX(250-slider.getWidth()/2);
        slider.setLayoutY(115-slider.getHeight()/2);

        slider.widthProperty().addListener(
                (ov, curVal, newVal) -> { slider.setLayoutX(250-slider.getWidth()/2); }
        );

        slider.heightProperty().addListener(
                (ov, curVal, newVal) -> slider.setLayoutY(115-slider.getHeight()/2)
        );

        //

        roundRect.arcWidthProperty().bind(slider.valueProperty());

        root.getChildren().add(slider);

        //

        Slider slider2 = new Slider(10,120,50);
        slider2.setLayoutX(50);
        slider2.setLayoutY(230);

        slider2.widthProperty().addListener(
                (ov, curVal, newVal) -> { slider2.setLayoutX(250-slider2.getWidth()/2); }
        );

        roundRect.yProperty().bind(slider2.valueProperty());
        root.getChildren().add(slider2);

        slider2.valueProperty().addListener(
                (ov, curVal, newVal) -> slider.setLayoutY(slider.getLayoutY()+newVal.doubleValue()-curVal.doubleValue())
        );

        //

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

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}

Run the code by right clicking on the file and selecting Run File.

Reviewing the Code

Setting the Scene

First we create a Stage, set the Scene and initialise the Scene with a Group to which we will add our Nodes as children.

The Group is called root and we add our Nodes (in this class a Rectangle) to it by calling root.getChildren().add() with our Node.

Once the scene is set on the Stage, we show the Stage

Adding the roundRect Rectangle

The shape we are going to draw is a simple Rectangle object which we define and then add to root.getChildren().

Rectangle roundRect = new Rectangle(50,50,400,130);

roundRect.setArcWidth(30);
roundRect.setArcHeight(60);

roundRect.setFill(null);
roundRect.setStroke(Color.DARKORANGE);
roundRect.setStrokeWidth(2);
roundRect.setStrokeLineCap(StrokeLineCap.BUTT);

root.getChildren().add(roundRect);

In the code above we first define a Rectangle with a width of 400, height of 130 which starts at position (50,50).  Note that in JavaFX (0,0) is in the top left with x increasing across the page and y increasing down the page.

The ArcWidth is the width of the curve on the corners, and teh ArcHeight is the height of the curve on the corners.

We setFill to null meaning there is no fill and then we set the border of the shape by calling setStroke and setStrokeWidth.

Finally, a StrokeLineCap of StrokeLineCap.BUTT with draw our line with a flat square end, while a round (StrokeLineCap.ROUND) style will appear with a rounded end.

Adding the centre Slider

Next we add the slider to the Centre of the image

Slider slider = new Slider(30,150,30);
slider.setLayoutX(250-slider.getWidth()/2);
slider.setLayoutY(115-slider.getHeight()/2);

In the code above we create a slider with values that range between 30 and 150 and an initial value of 30.

Next we set the x and y coordinates of the slider to centre the slider in the middle of the shape.

This will not work properly, because the Application does not know the width and height of the slider until it has been rendered.  In fact the width and height will both be -1.

In order to get round this problem we add a Listener to the widthProperty that will set the x position of the slider when the width is set, and we do the same for the heightProperty.

The addListener method is expecting a ChangeListener to be passed to it which is an Interface declared as follows:

public interface ChangeListener<T extends Object>
{
    public void changed(ObservableValue<? extends T> ov, T t, T t1);
}

To call this using a lambda expression we would write:

slider.widthProperty().addListener(
                (ObservableValue<? extends Number> ov, Number curVal, Number newVal) -> { slider.setLayoutX(250-slider.getWidth()/2); }
        );

but because we know the argument types to the lambda expression can be reduced to:

slider.widthProperty().addListener(
                (ov, curVal, newVal) -> { slider.setLayoutX(250-slider.getWidth()/2); }
        );

Finally, we bind the arcWidthProperty of our Rectangle object to the valueProperty of the slider so that when the slider value changes, the arcWidth of the rectangle changes with it.

This is done using the following code:

roundRect.arcWidthProperty().bind(slider.valueProperty());

Adding the bottom Slider

Next we add the slider to the bottom of the page, centred underneath the shape:

Slider slider2 = new Slider(10,120,50);
slider2.setLayoutX(50);
slider2.setLayoutY(230);

Once again, we need to add a listener to the width property of the slider to change the x co-ordinate once the width of the slider has been set in order to centre it.

slider2.widthProperty().addListener(
    (ov, curVal, newVal) -> { slider2.setLayoutX(250-slider2.getWidth()/2); }
);

Next we bind the the y coordinate of our Rectangle to the bottom slider value

roundRect.yProperty().bind(slider2.valueProperty());

Finally, we add a listener to our bottom Slider to move the Centre slider up and down as we slide the bottom slider.

slider2.valueProperty().addListener(
    (ov, curVal, newVal) -> slider.setLayoutY(slider.getLayoutY()+newVal.doubleValue()-curVal.doubleValue())
);

Source Code

The source code for this example can be found on GitHub at https://github.com/johndunning/JavaFX8Examples

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s