Thursday, June 30, 2016

93. Writing Pixels

Unlike the Image class, we can use WritableImage class to create an image which can be written to.


We can get a PixelWriter using getPixelWriter() method to write a byte array, for example. We fill the byte array using our getPixels() method in which we create a rainbow image. Finally the byte array is written to the WritableImage object using setPixels() method on the PixelWriter. We view the WritableImage using an ImageView.


In Java, a byte is signed (-128 to +127, 256 different numbers). A color component is from 0 to 255. This is logic to convert a color to byte: colors 0 to 127, unchanged, colors 128 to 255 (negative numbers, -128 to -1), that is color 255 is actually -1. This is the reason for the negative numbers in rainbow(). The function of rainbow() is to set colors. Even though the return type is void, it sets three global variables (r, g, b) which happen to be color components.


package ex93;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Ex93 extends Application {
    
    byte r, g, b;
    int w = 300, h = 280;
    
    public static void main(String[] args) {
        Application.launch(args);
    }
    
    @Override
    public void start(Stage stage) {
        WritableImage rainbowImage = new WritableImage(w, h);

        byte[] pixels = getPixels();

        PixelWriter pixelWriter = rainbowImage.getPixelWriter();

        pixelWriter.setPixels(0, 0,
                    w, h,
                    PixelFormat.getByteRgbInstance(),
                    pixels, 0,
                    w*3);

        ImageView newImageView = new ImageView(rainbowImage);

        HBox root = new HBox(newImageView);
        root.setAlignment(Pos.CENTER);
        root.setStyle("-fx-background-color: gray");
        
        Scene scene = new Scene(root,2*w,2*h);
        stage.setScene(scene);
        stage.setTitle("Example 93. Writing Pixels");
        stage.show();
    }

    private byte[] getPixels() {
        int d = h/7;
        byte[] px = new byte[w * h * 3];
        for (int y = 0; y < h; y++) {
            rainbow(y/d);
            for (int x = 0; x < w; x++) {
                int i = 3*y*w+x*3;
                px[i] = r; px[i+1] = g; px[i+2] = b;
            }
        }
        return px;
    }
    
    private void rainbow(int v) {
        switch (v) {
            case 0:
                r = -1; g = 0; b = 0; break;
            case 1:
                r = -1; g = 127; b = 0; break;
            case 2:
                r = -1; g = -1; b = 0; break;
            case 3:
                r = 0; g = -1; b = 0; break;
            case 4:
                r = 0; g = 0; b = -1; break;
            case 5:
                r = 75; g = 0; b = -126; break;
            case 6:
                r = -113; g = 0; b = -1; break;
        }
    }
}

This is the output:


92. Reading Pixel

A picture of President Obama was downloaded from whitehouse.org, and put in the src folder besides the ex92 folder. But of course this could be any image.


The Image object is used to get a PixelReader by using its getPixelReader() method. Using the PixelReader we can read a pixel, as we do in the handler for the mouse click.


The mouse click reads a color using the getArgb() method. This returns a 32 bit int. The first 8 bits are alpha, next 8 bits are red, next 8 bits are green, and last 8 bits are blue. All these four components are numbers from 0 to 255. For example to get Alpha we have to bit shift left 24 times (>> 24) and then logical and (&) with 255. The logical and serves to mask the first 24 bits so they will be zero. The three non-alpha color components are listed in label, and a Rectangle is filled with the color.


package ex92;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex92 extends Application {
    
    PixelReader pixelReader;
    int width, height;
    Label label;
    Rectangle rect;
    
    public static void main(String[] args) {
        Application.launch(args);
    }
    
    @Override
    public void start(Stage stage) {
        String imageFile = "president_official_portrait_lores.jpg";
        Image image = new Image(imageFile, 420, 524, false, true);
        ImageView imageView = new ImageView(image);
        imageView.setOnMouseClicked(this::handleClick);
        
        label = new Label("Click on picture");
        label.setFont(Font.font("Georgia", 24));
        
        rect = new Rectangle(420,100);
        rect.setFill(Color.WHITE);
        
        pixelReader = image.getPixelReader();
        width = (int)image.getWidth();
        height = (int)image.getHeight();
        
        VBox root = new VBox(50, imageView, label, rect);
        root.setPadding(new Insets(50));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Example 92. Reading Pixel");
        stage.show();
    }
    
    private void handleClick(MouseEvent e) {
        int color = pixelReader.getArgb((int) e.getX(), (int) e.getY());
        int red = (color >> 16) & 0xff;
        int green = (color >> 8) & 0xff;
        int blue = color & 0xff;
        label.setText("Red: " + red + ", Green: " + green
                + ", Blue: " + blue);
        rect.setFill(Color.rgb(red, green, blue));
    }
}

This is the output when a reddish pixel (on the flag) was selected:


Wednesday, June 29, 2016

91. TabPane

We create 10 TabPanes, for poly-3 to poly-12.


Each tab has a node content. Instead of having the Polygon as the content, we put the Polygon inside a VBox and then set the content as that VBox. This way we have greater control of layout parameters, in this case we can center the Polygon, rather than touching the tab labels on top.


package ex91;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex91 extends Application {

    final int RADIUS = 100;
    
    @Override
    public void start(Stage stage) {
        
        Label label = new Label("Polygon Shapes");
        label.setFont(Font.font("Georgia", 20));

        VBox vbox = new VBox(label);
        vbox.setAlignment(Pos.CENTER);
        
        int N = 12;
        Tab[] tabPaneArray = new Tab[N-2];
        for (int i = 3; i<=N; i++) {
            tabPaneArray[i-3] = makeTab(i);
        }
        
        TabPane tabPane = new TabPane();
        tabPane.getTabs().addAll(tabPaneArray);
        
        HBox hbox = new HBox(40, vbox, tabPane);
        hbox.setPadding(new Insets(20));
        hbox.setAlignment(Pos.CENTER);
        hbox.setStyle("-fx-background-color: lime");

        Scene scene = new Scene(hbox, 800, 500);
        stage.setTitle("Example 91. TabPane");
        
        stage.setScene(scene);
        stage.show();
    }
    
    private Tab makeTab(int num) {
        Tab tab = new Tab(num + "-poly");
        Polygon poly = new Polygon(getDouble(num));
        poly.setFill(Color.RED);
        VBox vTabBox = new VBox(poly);
        vTabBox.setAlignment(Pos.CENTER);
        tab.setContent(vTabBox);
        tab.setClosable(false);
        return tab;
    }
    
    private double[] getDouble (int n) {
        double[] array = new double[2*n];
        for (int i = 0; i<n; i++){
            array[2*i] = RADIUS*Math.cos(2*Math.PI/n*i);
            array[2*i+1]=RADIUS*Math.sin(2*Math.PI/n*i);
        }
        return array;
    }

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

This is the output when 10-poly is selected:


90. Translate + Rotate

A node can undergo multiple transformations. Here we first translate and then rotate.


The three rectangles of different colors are at the same location and with the same size. The green one is moved right and then rotated by 45. The blue one is moved down and then rotated by 45.


package ex90;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class Ex90 extends Application {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        Rectangle rect1 = new Rectangle(50, 50, 100, 50);
        rect1.setFill(Color.rgb(255, 0, 0));

        Rectangle rect2 = new Rectangle(50, 50, 100, 50);
        rect2.setFill(Color.rgb(0, 255, 0));
        
        Rectangle rect3 = new Rectangle(50, 50, 100, 50);
        rect3.setFill(Color.rgb(0, 0, 255));
        
        Translate translateX = new Translate(150,0);
        Translate translateY = new Translate(0,150);
        Rotate rotate = new Rotate(45, 50, 75);
        
        rect2.getTransforms().addAll(translateX, rotate);
        rect3.getTransforms().addAll(translateY, rotate);
        
        Group root = new Group(rect1, rect2, rect3);
        Scene scene = new Scene(root, 350, 400, Color.GAINSBORO);
        
        stage.setScene(scene);
        stage.setTitle("Example 90. Translate + Rotate");
        stage.show();
    }
}

This is the output:


89. Shear

With shear, we can change angle between the x and y axis. All the sides maintain their length.


The pivot point is 50, 75, and which is center of left side, and which does not move during the transformation.


package ex89;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Shear;
import javafx.stage.Stage;

public class Ex89 extends Application {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        Rectangle rect1 = new Rectangle(50, 50, 100, 50);
        rect1.setFill(Color.rgb(255, 0, 0, 0.5));

        Rectangle rect2 = new Rectangle(50, 50, 100, 50);
        rect2.setFill(Color.rgb(0, 255, 0, 0.5));
        
        Shear shear = new Shear(0.5, 0.5, 50, 75);
        rect2.getTransforms().add(shear);
        
        Group root = new Group(rect1, rect2);
        Scene scene = new Scene(root,300,200);
        
        stage.setScene(scene);
        stage.setTitle("Example 89. Shear");
        stage.show();
    }
}

This is the output:


88. Scale

We have two rectangle, red and green, at same location and with same size. However the green is scaled down 50% in both x and y directions.


The pivot point corresponds to center left of the rectangles (50, 75). This point will not change position during the scaling.


package ex88;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;

public class Ex88 extends Application {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        Rectangle rect1 = new Rectangle(50, 50, 100, 50);
        rect1.setFill(Color.rgb(255, 0, 0, 0.5));

        Rectangle rect2 = new Rectangle(50, 50, 100, 50);
        rect2.setFill(Color.rgb(0, 255, 0, 0.5));
        
        Scale scale = new Scale(0.5, 0.5, 50, 75);
        rect2.getTransforms().add(scale);
        
        Group root = new Group(rect1, rect2);
        Scene scene = new Scene(root,300,200);
        
        stage.setScene(scene);
        stage.setTitle("Example 88. Scale");
        stage.show();
    }
}

This is the output:


87. Rotate

We create a red and green rectangle at same location and with same size. However the green one is rotated by 45 degrees.


The pivot point (50,75 in this example) is the center of rotation, and the point which not change position during rotation. This point corresponds to center of left side.


package ex87;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class Ex87 extends Application {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        Rectangle rect1 = new Rectangle(50, 50, 100, 50);
        rect1.setFill(Color.rgb(255, 0, 0, 0.5));

        Rectangle rect2 = new Rectangle(50, 50, 100, 50);
        rect2.setFill(Color.rgb(0, 255, 0, 0.5));
        
        Rotate rotate = new Rotate(45, 50, 75);
        rect2.getTransforms().add(rotate);
        
        Group root = new Group(rect1, rect2);
        Scene scene = new Scene(root,300,200);
        
        stage.setScene(scene);
        stage.setTitle("Example 87. Rotate");
        stage.show();
    }
}

This is the output:


Tuesday, June 28, 2016

86. Translate

With Translate, we can move a node in x or y (for 2D).


We create 3 Rectangles and place them at same location. The red rectangle is not moved, the green rectangle is moved 80 to right and 10 downwards. Lastly, the blue rectangle is moved 80 to left, and 10 downwards. The colors are only half opaque, so we can see the outlines for all three rectangles.


package ex86;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class Ex86 extends Application {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) {
        Rectangle rect1 = new Rectangle(100, 0, 100, 50);
        rect1.setFill(Color.rgb(255, 0, 0, 0.5));

        Rectangle rect2 = new Rectangle(100, 0, 100, 50);
        rect2.setFill(Color.rgb(0, 255, 0, 0.5));
        
        Rectangle rect3 = new Rectangle(100, 0, 100, 50);
        rect3.setFill(Color.rgb(0, 0, 255, 0.5));

        Translate translate1 = new Translate(80, 10);
        rect2.getTransforms().addAll(translate1);
        
        Translate translate2 = new Translate(-80, 10);
        rect3.getTransforms().add(translate2);

        Group root = new Group(rect1, rect2, rect3);
        Scene scene = new Scene(root,300,100);
        
        stage.setScene(scene);
        stage.setTitle("Example 86. Translate");
        stage.show();
    }
}

This is the output:


85. StackedBarChart

The StackedBarChart is very similar to the BarChart except now the all heights are on one bar.


Thus we only have one bar for a category, no matter how many series. Since we have 3 categories here, there are only 3 bars.


package ex85;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class Ex85 extends Application {
 
    ObservableList<XYChart.Series> obList 
            = FXCollections.observableArrayList();
    
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
        CategoryAxis xAxis = new CategoryAxis();
        NumberAxis yAxis = new NumberAxis();
        initData();
        StackedBarChart stackedBarChart = 
                new StackedBarChart(xAxis, yAxis, obList);
        stackedBarChart.setTitle("A StackedBar plot");
        
        StackPane root = new StackPane();
        root.getChildren().add(stackedBarChart);
        
        primaryStage.setTitle("Example 85. StackedBarChart");
        primaryStage.setScene(new Scene(root, 400, 250));
        primaryStage.show();
    }
 
    private void initData() {
        Series series1 = new Series<>();
        Series series2 = new Series<>();
        series1.getData().addAll(
                new XYChart.Data("0", 5),
                new XYChart.Data("1", 3),
                new XYChart.Data("2", 2)
                );
        series1.setName("series 1");
        series2.getData().addAll(
                new XYChart.Data("0", 2),
                new XYChart.Data("1", 4),
                new XYChart.Data("2", 7)
                );
        series2.setName("series 2");
        obList.addAll(series1, series2);
    }
}

This is the output:


84. BarChart

In a BarChart, the x-axis has to be categorical (and a String).


The relative heights of each category is plotted for all series. We make class changes and a few name changes.


package ex84;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class Ex84 extends Application {
 
    ObservableList<XYChart.Series<String, Double>> obList 
            = FXCollections.observableArrayList();
    
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
        CategoryAxis xAxis = new CategoryAxis();
        NumberAxis yAxis = new NumberAxis();
        initData();
        BarChart barChart = new BarChart(xAxis, yAxis, obList);
        barChart.setTitle("A bar plot");
        
        StackPane root = new StackPane();
        root.getChildren().add(barChart);
        
        primaryStage.setTitle("Example 84. BarChart");
        primaryStage.setScene(new Scene(root, 400, 250));
        primaryStage.show();
    }
 
    private void initData() {
        Series series1 = new Series<>();
        Series series2 = new Series<>();
        series1.getData().addAll(
                new XYChart.Data("0", 5),
                new XYChart.Data("1", 3),
                new XYChart.Data("2", 2)
                );
        series1.setName("series 1");
        series2.getData().addAll(
                new XYChart.Data("0", 2),
                new XYChart.Data("1", 4),
                new XYChart.Data("2", 7)
                );
        series2.setName("series 2");
        obList.addAll(series1, series2);
    }
}

This is the output:


Monday, June 27, 2016

83. LineChart

LineChart is very similar to the ScatterChart except each series is connected with lines.


The only thing changed here, from example 82, is that we use the LineChart class instead of ScatterChart class, and rename the resulting object to lineChart.


package ex83;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class Ex83 extends Application {
 
    ObservableList<XYChart.Series<Integer, Double>> obList 
            = FXCollections.observableArrayList();
    
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
        NumberAxis xAxis = new NumberAxis();
        xAxis.setAutoRanging(false);
        xAxis.setLowerBound(-1);
        xAxis.setUpperBound(3);
        xAxis.setTickUnit(1);
        NumberAxis yAxis = new NumberAxis();
        initData();
        LineChart lineChart = new LineChart(xAxis, yAxis, obList);
        lineChart.setVerticalZeroLineVisible(false);
        lineChart.setTitle("A line plot");
        
        StackPane root = new StackPane();
        root.getChildren().add(lineChart);
        
        primaryStage.setTitle("Example 83. LineChart");
        primaryStage.setScene(new Scene(root, 400, 250));
        primaryStage.show();
    }
 
    private void initData() {
        Series series1 = new Series<>();
        Series series2 = new Series<>();
        series1.getData().addAll(
                new XYChart.Data(0, 5),
                new XYChart.Data(1, 3),
                new XYChart.Data(2, 2)
                );
        series1.setName("series 1");
        series2.getData().addAll(
                new XYChart.Data(0, 2),
                new XYChart.Data(1, 4),
                new XYChart.Data(2, 7)
                );
        series2.setName("series 2");
        obList.addAll(series1, series2);
    }
}

This is the output:


82. ScatterChart

A Scatter graph, like all XY graphs, needs xAxis and yAxis. We can have any number of series to plot. Here we use two series.


We define three points (for each of the two series), set a title and remove the vertical zero line. You can comment out the setVerticalZeroLineVisible to see what it does, or set it to true.


package ex82;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class Ex82 extends Application {
 
    ObservableList<XYChart.Series<Integer, Double>> obList 
            = FXCollections.observableArrayList();
    
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
        NumberAxis xAxis = new NumberAxis();
        xAxis.setAutoRanging(false);
        xAxis.setLowerBound(-1);
        xAxis.setUpperBound(3);
        xAxis.setTickUnit(1);
        NumberAxis yAxis = new NumberAxis();
        initData();
        ScatterChart scatterChart=new ScatterChart(xAxis,yAxis,obList);
        scatterChart.setVerticalZeroLineVisible(false);
        scatterChart.setTitle("A scatter plot");
        
        StackPane root = new StackPane();
        root.getChildren().add(scatterChart);
        
        primaryStage.setTitle("Example 82. ScatterChart");
        primaryStage.setScene(new Scene(root, 400, 250));
        primaryStage.show();
    }
 
    private void initData() {
        Series series1 = new Series<>();
        Series series2 = new Series<>();
        series1.getData().addAll(
                new XYChart.Data(0, 5),
                new XYChart.Data(1, 3),
                new XYChart.Data(2, 2)
                );
        series1.setName("series 1");
        series2.getData().addAll(
                new XYChart.Data(0, 2),
                new XYChart.Data(1, 4),
                new XYChart.Data(2, 7)
                );
        series2.setName("series 2");
        obList.addAll(series1, series2);
    }
}

This is the output:


81. PieChart

The style class, below, defines the colors in the PieChart (for the four slices), rather than using the default colors.


The name of the file is pieColors.css and is in the same directory as the main java file, folder ex81 of src.


.default-color0.chart-pie { -fx-pie-color: blue; }
.default-color1.chart-pie { -fx-pie-color: red; }
.default-color2.chart-pie { -fx-pie-color: peru; }
.default-color3.chart-pie { -fx-pie-color: green; }

The data for the PieChart is an ObjervableList of type PieChart.Data. It is four numbers from a recent poll


The title is printed using setTitle and put at bottom using setTitleSide. Also it is rotated from original ordering. You can comment out the setStartAngle line to see the original ordering.


package ex81;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Side;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class Ex81 extends Application {
 
    ObservableList obList = 
                FXCollections.observableArrayList();
    
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage primaryStage) {
        initData();
        PieChart pieChart = new PieChart(obList);
        pieChart.setTitle("\nABC News/Washington Post\n\t6/20-6/23");
        pieChart.setTitleSide(Side.BOTTOM);
        pieChart.setStartAngle(180);
        
        StackPane root = new StackPane();
        root.getChildren().add(pieChart);
        
        primaryStage.setTitle("Example 81. PieChart");
        
        Scene scene = new Scene(root, 300, 400);
        scene.getStylesheets().add("ex81/pieColors.css");
    
        primaryStage.setScene(scene);
        primaryStage.show();
    }
 
    private void initData() {
        obList.addAll(
                new PieChart.Data("CLINTON", 47),
                new PieChart.Data("trump", 37),
                new PieChart.Data("Johnson", 7),
                new PieChart.Data("Stein", 3));
    }
}

This is the output:


80. Accordion

An Accordion allows a group of TitledPanes (each TitledPane has a Title and a Node (a Polygon here) .


Here we make 10 TitledPanes, using the makeTitledPane method, for polygons from 3 to 12 sides.


package ex80;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Label;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex80 extends Application {

    final int RADIUS = 100;
    
    @Override
    public void start(Stage stage) {
        
        Label label = new Label("Polygon Shapes");
        label.setFont(Font.font("Georgia", 20));

        VBox vbox = new VBox(label);
        vbox.setAlignment(Pos.CENTER);
        
        int N = 12;
        TitledPane[] titledPaneArray = new TitledPane[N-2];
        for (int i = 3; i<=N; i++) {
            titledPaneArray[i-3] = makeTitledPane(i);
        }
        
        Accordion accordion = new Accordion();
        accordion.getPanes().addAll(titledPaneArray);
        
        HBox hbox = new HBox(40, vbox, accordion);
        hbox.setAlignment(Pos.CENTER);
        hbox.setStyle("-fx-background-color: lime");

        Scene scene = new Scene(hbox, 600, 500);
        stage.setTitle("Example 80. Accordion");
        
        stage.setScene(scene);
        stage.show();
    }
    
    private TitledPane makeTitledPane(int num) {
        Polygon poly = new Polygon(getDouble(num));
        poly.setFill(Color.RED);
        return new TitledPane(num + "-sided Polygon", poly);
    }
    
    private double[] getDouble (int n) {
        double[] array = new double[2*n];
        for (int i = 0; i&t;n; i++){
            array[2*i] = RADIUS*Math.cos(2*Math.PI/n*i);
            array[2*i+1]=RADIUS*Math.sin(2*Math.PI/n*i);
        }
        return array;
    }

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

This is the output with 12-sided polygon selected:


Sunday, June 26, 2016

78. HyperLink

With HyperLink, we can cause an action if a text is clicked. The text will be highlightened when selected.


This is used here to select a group of colors. This is comparable to a set of radio buttons.


package ex78;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Hyperlink;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex78 extends Application {
    
    Rectangle rect;
    Font font;
    
    @Override
    public void start(Stage stage) {

        String[] colors = {"red","green","blue",
            "palegreen","cyan","coral"};
        
        font = Font.font("Georgia",32);
        
        Hyperlink[] hyp = new Hyperlink[colors.length];
        for (int i = 0; i < colors.length; i++) {
            hyp[i] = makeHyp(colors[i]);
        }
        
        VBox vbox = new VBox(50, hyp);
        
        rect = new Rectangle(300,600,Color.WHITE);
        
        HBox root = new HBox(50, vbox, rect);
        root.setPadding(new Insets(50));
        root.setAlignment(Pos.CENTER);
        
        Scene scene = new Scene(root);
        stage.setTitle("Example 78. Hyperlink"); 

        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }

    private Hyperlink makeHyp(String color) {
        Hyperlink hyperlink = new Hyperlink(color);
        hyperlink.setFont(font);
        hyperlink.setOnAction(e -> {
            hyperlink.setVisited(false);
            rect.setStyle("-fx-fill:" + color);
        });
        return hyperlink;
    }
}

This is the output:


77. MediaPlayer

With MediaPlayer, we may stream an audio source.


Since the entire sound is not stored in memory, the MediaPlayer is necessary for large audio files.


package ex77;

import java.net.URL;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;

public class Ex77 extends Application {

    private final String style =
            "-fx-font-family: Georgia; -fx-font-size: 32;"
            +"-fx-text-fill: purple;";

    @Override
    public void start(Stage stage) {

        URL chirpURL = getClass().getResource("/chirp.wav");
        
        Media media = new Media(chirpURL.toString());
        MediaPlayer mediaPlayer = new MediaPlayer(media);
        mediaPlayer.setCycleCount(5);
        
        Button button = new Button("Play");
        button.setStyle(style);
        button.setOnAction(e-> {
            if (button.getText().equals("Play")) {
                mediaPlayer.play();
                button.setText("Exit");
            }
            else Platform.exit();
            
        });
        
        Label label = new Label();
        label.setStyle(style);
        
        label.textProperty().bind(
                new SimpleStringProperty("Current Count: ").
                concat(
                mediaPlayer.currentCountProperty().asString()));
        
        VBox vbox = new VBox(50, button, label);
        vbox.setAlignment(Pos.CENTER);
        vbox.setStyle("-fx-background-color: lime");

        Scene scene = new Scene(vbox, 400, 300);
        stage.setTitle("Example 77. MediaPlayer");

        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output after 2 counts of playing sound. Note the button text has changed form Play to Exit.


76. Chaining Effects

We can apply a number of effects to a Node. There will only be one setEffect call, but there will be setInput for each additional effect.


Here we apply PerspectiveTransorm to button with a DropShadow. This is in contrast to last example, where only PerspectiveTransform was applied.


package ex76;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Ex76 extends Application {
    
    @Override
    public void start(Stage stage) {
        
        Group root = new Group();

        DropShadow dropShadow = new DropShadow();
        dropShadow.setOffsetX(4);
        dropShadow.setOffsetY(6);
        dropShadow.setColor(Color.PURPLE);
        
        PerspectiveTransform perspective = new PerspectiveTransform();
        perspective.setUlx(10);  perspective.setUly(50);
        perspective.setLlx(10);  perspective.setLly(210);
        perspective.setUrx(300);  perspective.setUry(50);
        perspective.setLrx(300);  perspective.setLry(310);
        
        perspective.setInput(dropShadow);
        
        Button button = new Button("Perspective + DropShadow");
        button.setEffect(perspective);
        
        root.getChildren().add(button);
        
        Scene scene = new Scene(root, 350, 350, Color.ROSYBROWN);
        stage.setTitle("Example 76. Chaining");
        stage.setScene(scene);
        stage.show();
    }

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

This is the output:


75. PerspectiveTransform

With PerspectiveTransform, we can set the four corners of a node to give 3D look.


Here, we apply it to a button.


package ex75;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Ex75 extends Application {
    
    @Override
    public void start(Stage stage) {
        
        Group root = new Group();

        PerspectiveTransform perspective = new PerspectiveTransform();
        perspective.setUlx(10);  perspective.setUly(50);
        perspective.setLlx(10);  perspective.setLly(210);
        perspective.setUrx(300);  perspective.setUry(50);
        perspective.setLrx(300);  perspective.setLry(310);
        
        Button button = new Button("Perspective");
        button.setEffect(perspective);
        
        root.getChildren().add(button);
        
        Scene scene = new Scene(root, 350, 350, Color.ROSYBROWN);
        stage.setTitle("Example 75. Perspective");
        stage.setScene(scene);
        stage.show();
    }

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

This is the output:


Friday, June 24, 2016

74. ListView and ObservableList

This program is similar to example 72, except now the ObservableList is connected to a ListView.


We break example 72 into 9 steps, and click on a button 9 times, and the ListView node updates. Clicking a 10th time will exit the program.


package ex74;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
 
public class Ex74 extends Application {
    
    private final String style1 =
           "-fx-font-family: Georgia; -fx-font-size: 24;"
         + "-fx-text-fill: purple; -fx-background-color: greenyellow;";
    private final String style2 =
           "-fx-font-family: Georgia; -fx-font-size: 24;";
    
    ObservableList obsList;
    int step = 1;
    private Button button;
    
    
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        
        button = new Button("Do step 1");
        appendButtonText(1);
        button.setPrefSize(200, 200);
        button.setStyle(style1);
        button.setWrapText(true);
        
        obsList = FXCollections.observableArrayList();
        
        ListView listView = new ListView<>(obsList);
        listView.setPrefSize(200, 400);
        listView.setStyle(style2);
        
        button.setOnAction( e -> {
            doStep(step);
            step++;
            if (step<10) {
                button.setText("Do step " + step);
                appendButtonText(step);
            }
            else button.setText("No more steps. Exit now!");
        });
        
        HBox hbox = new HBox(50, button, listView);
        hbox.setPadding(new Insets(20));
        
        Scene scene = new Scene(hbox);
        primaryStage.setTitle("Example 74. ListView and Observable List");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private void doStep(int stepNumber) {
        switch (stepNumber) {
            case 1:
                List list = Arrays.asList("-1", "-2");
                obsList.addAll(list);
                break;
            case 2:
                obsList.addAll("1","2","3");
                break;
            case 3:
                obsList.add("4");
                break;
            case 4:
                obsList.add(0, "0");
                break;
            case 5:
                obsList.addAll("4", "5");
                break;
            case 6:
                obsList.set(1, "One");
                break;
            case 7:
                obsList.removeAll("3", "4");
                break;
            case 8:
                obsList.remove("1");
                break;
            case 9:
                obsList.clear();
                break;
            default:
                Platform.exit();
        }
    }
    
    private void appendButtonText(int stepNumber) {
        String val;
        switch (stepNumber) {
            case 1:
                val = " : Adding -1 and -2";
                break;
            case 2:
                val = " : Adding 1, 2, 3";
                break;
            case 3:
                val = " : Adding 4";
                break;
            case 4:
                val = " : Adding 0 at location 0";
                break;
            case 5:
                val = " : Adding 4 and 5";
                break;
            case 6:
                val = " : Changing location 1 to One";
                break;
            case 7:
                val = " : Removing 3 and 4";
                break;
            case 8:
                val = " : Removing 1";
                break;
            case 9:
                val = " : Clearing";
                break;
            default:
                val = " : Exit";
        }
        button.setText(button.getText() + val);
    }
}

This is the output after 5 steps and before Step 6 which will put One in location 1 (replacing -1):


73. ColorPicker and DatePicker

The ColorPicker can select a color. We bind it to a label as well as the scene fill color.


The DatePicker can select a date. We bind it to a label.


package ex73;

import java.time.LocalDate;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex73 extends Application {

    @Override
    public void start(Stage stage) {
        
        String date = "2016-06-23";
        
        ObjectProperty str1 =
                new SimpleObjectProperty<>(this,"str1",Color.WHITE);
        StringProperty str2 = 
                new SimpleStringProperty(this,"str2",date);
        
        Font font = Font.font("Georgia", 20);
        
        Label label1 = new Label();
        label1.setFont(font);
        label1.setLayoutX(100); label1.setLayoutY(100);
        Label label2 = new Label();
        label2.setFont(font);
        label2.setLayoutX(100); label2.setLayoutY(200);
        Label label3 = new Label("Color: ");
        label3.setFont(font);
        label3.setLayoutX(50); label3.setLayoutY(350);
        Label label4 = new Label("Date: ");
        label4.setFont(font);
        label4.setLayoutX(50); label4.setLayoutY(450);
        
        ColorPicker colorPicker = new ColorPicker();
        colorPicker.setOnAction(event -> 
                str1.set(colorPicker.getValue()));
        colorPicker.setLayoutX(150); colorPicker.setLayoutY(350);
        
        LocalDate dateLD = LocalDate.parse(date);
        DatePicker datePicker = new DatePicker(dateLD);
        datePicker.setOnAction(event -> {
            LocalDate localDate = datePicker.getValue();
            str2.set(localDate.toString());
        });
        datePicker.setLayoutX(150); datePicker.setLayoutY(450);
        
        Group root = new Group(label1, label2,
                label3, label4, 
                colorPicker, datePicker);
        
        Scene scene = new Scene(root, 400, 550);
        stage.setTitle("Example 73. ColorPicker and DatePicker"); 
        
        label1.textProperty().bind(new SimpleStringProperty("Color: ")
                .concat((str1.asString())));
        label2.textProperty().bind(new SimpleStringProperty("Date: ")
                .concat(str2));
        scene.fillProperty().bind(str1);
        
        stage.setScene(scene);
        stage.show();
    }

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

This is the output after selecting a date and color:


Thursday, June 23, 2016

72. Observable List

Often we need a list of data to connect to a UI element.


The ObservableList class is used to change a list and its listener prints the change, in a TextArea. The TextArea is non-editable, since we only use it to display information.


package ex72;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import static javafx.collections.ListChangeListener.Change;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
 
public class Ex72 extends Application {
    
    private final String style =
           "-fx-font-family: Georgia; -fx-font-size: 24;"
         + "-fx-text-fill: purple; -fx-background-color: greenyellow;";
    private TextArea textArea;
    
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        textArea = new TextArea();
        textArea.setStyle(style);
        textArea.setPadding(new Insets(10));
        textArea.setPrefRowCount(30);
        textArea.setPrefColumnCount(15);
        textArea.setEditable(false);
        
        final List list = Arrays.asList("-1", "-2");
        ObservableList obsList = 
                FXCollections.observableArrayList(list);
        
        appendText("Initial obsList", false);
        appendText(obsList.toString(), true);
 
        obsList.addListener((Change change) -> {
            appendText(change.toString(), false);
            appendText(change.getList().toString(), true);
        });
        
        obsList.addAll("1","2","3");
        obsList.add("4");
        obsList.add(0, "0");
        obsList.addAll("4", "5");
        obsList.set(1, "One");
        obsList.removeAll("3", "4");
        obsList.remove("1");
        obsList.clear();
        
        VBox vbox = new VBox(textArea);
        
        Scene scene = new Scene(vbox);
        primaryStage.setTitle("Example 72. Observable List");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private void appendText(String text, boolean endNewLine) {
        if (endNewLine) textArea.appendText("\n" + text + "\n");
        else textArea.appendText("\n" + text);
    }
}

This is the output:


71. AudioClip

With AudioClip we can load audio into memory. For large files we should use streaming Media API.


In Audacity (audio editor), selecting Generate menu and Chirp... option, we can generate a chirp sound and then export in to a wav file. The default length is 30 second which should be OK. Of course it does not matter what the sound is, as long as it is a small file. We place the file in the src folder.


Rather than using the full path, we can create a URL and then convert it to String in the AudioClip constructor. If the Play button is pressed, we call the play method for the AudioClip object.


package ex71;

import java.net.URL;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.media.AudioClip;
import javafx.stage.Stage;

public class Ex71 extends Application {

    private final String style =
            "-fx-font-family: Georgia; -fx-font-size: 32;"
            +"-fx-text-fill: purple;";

    @Override
    public void start(Stage stage) {

        URL chirpURL = getClass().getResource("/chirp.wav");
        AudioClip chirp = new AudioClip(chirpURL.toString());
        
        Button button = new Button("Play");
        button.setStyle(style);
        button.setOnAction(e->chirp.play());
        
        VBox vbox = new VBox(button);
        vbox.setAlignment(Pos.CENTER);
        vbox.setStyle("-fx-background-color: lime");

        Scene scene = new Scene(vbox, 400, 300);
        stage.setTitle("Example 71. AudioClip");

        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output:


70. ToolBar

Three buttons, with graphics for red, green, and blue form a ToolBar.


Each graphic is a 40 by 40 png image filled with one color and put in src folder. The text "Red", "Green", or "Blue" is displayed in the label depending on which button is clicked.


package ex70;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToolBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Ex70 extends Application {

    private final String style =
            "-fx-font-family: Georgia; -fx-font-size: 32;"
            +"-fx-text-fill: purple;";

    @Override
    public void start(Stage stage) {

        Label label = new Label("Red");
        label.setStyle(style);
        
        ToolBar toolBar = new ToolBar();
        toolBar.setMaxWidth(220);
        toolBar.setPadding(new Insets(20));
        
        Button button1 = new Button();
        Image image1 = new Image("red.png");
        button1.setGraphic(new ImageView(image1));
        button1.setOnAction(e->label.setText("Red"));
        
        Button button2 = new Button();
        Image image2 = new Image("green.png");
        button2.setGraphic(new ImageView(image2));
        button2.setOnAction(e->label.setText("Green"));
        
        Button button3 = new Button();
        Image image3 = new Image("blue.png");
        button3.setGraphic(new ImageView(image3));
        button3.setOnAction(e->label.setText("Blue"));
        
        toolBar.getItems().addAll(button1, button2, button3);
        
        VBox vbox = new VBox(20, toolBar, label);
        vbox.setAlignment(Pos.CENTER);
        vbox.setPadding(new Insets(30));
        vbox.setStyle("-fx-background-color: lime");

        Scene scene = new Scene(vbox, 400, 300);
        stage.setTitle("Example 70. ToolBar");

        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output:


69. TextArea

Unlike the TextField, we can enter many lines of text in TextArea.


Text is copied from the Wikipedia article on JavaFX and pasted into the TextArea. Because the text can not fit on one screen, vertical scrollbars appear.


package ex69;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex69 extends Application {

    private TextArea textArea;

    @Override
    public void start(Stage stage) {

        Label label = new Label("TextArea");
        label.setFont(Font.font("Georgia", 20));
        
        textArea = new TextArea();
        textArea.setFont(Font.font("Georgia", 20));
        textArea.setWrapText(true);

        VBox root = new VBox(10, label, textArea);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(20));
        
        Scene scene = new Scene(root, 400, 300);
        stage.setTitle("Example 69. TextArea");

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

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

This is the output:


68. ScrollBar

We use a ScrollBar to move a VBox layout.


The VBox holds a rectangle that is wider than the window size. We bind the layout x coordinate to the ScrollBar.


package ex68;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Ex68 extends Application {

    @Override
    public void start(Stage stage) {
        
        final double WIDTH = 800;

        ScrollBar hScroll = new ScrollBar();
        hScroll.setLayoutX(10); hScroll.setLayoutY(150);
        hScroll.setMin(0); hScroll.setMax(WIDTH);
        
        LinearGradient lg = new LinearGradient(
            0, 0.5, 1, 0.5, true, CycleMethod.NO_CYCLE, 
                new Stop(0,Color.RED),
                new Stop(0.5, Color.GREEN),
                new Stop(1,Color.BLUE));
        
        Rectangle rect = new Rectangle(10,10,WIDTH,100);
        rect.setFill(lg);
        
        HBox hbox = new HBox(rect);
        hbox.setPadding(new Insets(20));
  
        Group root = new Group(hbox, hScroll);
        
        Scene scene = new Scene(root, 400, 200, Color.LINEN);
        stage.setTitle("Example 68. ScrollBar"); 
        
        hbox.layoutXProperty().bind(hScroll.valueProperty().negate());
       
        stage.setScene(scene);
        stage.show();
    }

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

This is the output after scrolling to the right end:


67. TextField and PasswordField

With a TextField and PasswordField, we can enter text.


If the submit button is pressed and the password is correct (password), the person is greeted with green OK.


package ex67;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex67 extends Application {

    @Override
    public void start(Stage stage) {
        
        Font font = Font.font("Geogia",20);
        
        GridPane gridPane = new GridPane();
        gridPane.setHgap(10); gridPane.setVgap(10);
        gridPane.setAlignment(Pos.CENTER);
                
        Label nameLab = new Label("Name");
        nameLab.setFont(font);
        gridPane.add(nameLab, 0, 0);
        
        TextField nameTF = new TextField();
        nameTF.setMaxWidth(100);
        gridPane.add(nameTF, 1, 0);
        
        Label passwordLab = new Label("Password");
        passwordLab.setFont(font);
        gridPane.add(passwordLab, 0, 1);
        
        PasswordField passwordField = new PasswordField();
        passwordField.setMaxWidth(200);
        gridPane.add(passwordField, 1, 1);
        
        Button submit = new Button("Submit");
        gridPane.add(submit, 1, 2, 2, 1);
        
        Label messageLab = new Label();
        messageLab.setFont(font);
        messageLab.setPrefWidth(200);
        gridPane.add(messageLab, 1, 3, 2, 1);

        Scene scene = new Scene(gridPane, 500, 200);
        stage.setTitle("Example 67. TextField and PasswordField"); 
        
        submit.setOnAction(e -> {
            String message;
            String password = passwordField.getText();
            if (password.equals("password")) {
                message = "OK";
                messageLab.setTextFill(Color.GREEN);
            } else {
                message = "Wrong";
                messageLab.setTextFill(Color.RED);
            }
            messageLab.setText(message + ", " + nameTF.getText());
        });
        
        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output:


66. CheckBox

Like the previous example, we can select triangle, square or pentagon, by selecting the appropriate CheckBox.


Now we can select more than one choice.


package ex66;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;

public class Ex66 extends Application {

    final int RADIUS = 100;
    
    @Override
    public void start(Stage stage) {
                        
        VBox root = new VBox(20);
        root.setAlignment(Pos.CENTER);
        
        HBox hbox = new HBox(50);
        hbox.setAlignment(Pos.CENTER);
        
        CheckBox triangleCB = new CheckBox("Triangle");
        CheckBox squareCB = new CheckBox("Square  ");
        CheckBox pentagonCB = new CheckBox("Pentagon ");
        hbox.getChildren().setAll(triangleCB, squareCB,
                pentagonCB);
        
        Polygon triangle = new Polygon(getDouble(3));
        triangle.setFill(Color.RED);
        
        Polygon square = new Polygon(getDouble(4));
        square.setFill(Color.BLUE);
        
        Polygon pentagon = new Polygon(getDouble(5));
        pentagon.setFill(Color.GREEN);
        
        triangle.visibleProperty().bind(
                triangleCB.selectedProperty());
        square.visibleProperty().bind(
                squareCB.selectedProperty());
        pentagon.visibleProperty().bind(
                pentagonCB.selectedProperty());
        
        root.getChildren().addAll(hbox,
                triangle, square, pentagon);
        
        Scene scene = new Scene(root, 400, 800, Color.CORNSILK);
        stage.setTitle("Example 66. CheckBox");
        
        stage.setScene(scene);
        stage.show();
    }
    
    private double[] getDouble (int n) {
        double[] array = new double[2*n];
        for (int i = 0; i<n; i++){
            array[2*i] = RADIUS*Math.cos(2*Math.PI/n*i);
            array[2*i+1]=RADIUS*Math.sin(2*Math.PI/n*i);
        }
        return array;
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output after selecting triangle and pentagon:


Wednesday, June 22, 2016

65. RadioButton

A set of 3 RadioButtons, part of a ToggleGroup, can select between triangle, square or pentagon shape.


The visibility of the shape node is dependent on the state of button's selectedProperty through a unidirectional bind. For the Polygon shapes, we construct the double array using getDouble method which requires the number of sides (which is also equal to the number of vertices of points in our array).


package ex65;

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;

public class Ex65 extends Application {

    final int RADIUS = 100;
    final Point2D CENTER = new Point2D(200, 200);
    
    @Override
    public void start(Stage stage) {
                        
        Group root = new Group();
        
        RadioButton triangleButton = new RadioButton("Triangle");
        triangleButton.setLayoutX(10); triangleButton.setLayoutY(10);
        RadioButton squareButton = new RadioButton("Square");
        squareButton.setLayoutX(10); squareButton.setLayoutY(60);
        RadioButton pentagonButton = new RadioButton("Pentagon");
        pentagonButton.setLayoutX(10); pentagonButton.setLayoutY(110);
        
        Polygon triangle = new Polygon(getDouble(3));
        triangle.setFill(Color.RED);
        
        Polygon square = new Polygon(getDouble(4));
        square.setFill(Color.BLUE);
        
        Polygon pentagon = new Polygon(getDouble(5));
        pentagon.setFill(Color.GREEN);
        
        triangle.visibleProperty().bind(
                triangleButton.selectedProperty());
        square.visibleProperty().bind(
                squareButton.selectedProperty());
        pentagon.visibleProperty().bind(
                pentagonButton.selectedProperty());
        
        root.getChildren().addAll(triangleButton,
                squareButton, pentagonButton,
                triangle, square, pentagon);
        
        ToggleGroup toggleGroup = new ToggleGroup();
        toggleGroup.getToggles().addAll(triangleButton,
                squareButton, pentagonButton);
        
        Scene scene = new Scene(root, 400, 400, Color.CORNSILK);
        stage.setTitle("Example 65. RadioButton");
        
        stage.setScene(scene);
        stage.show();
    }
    
    private double[] getDouble (int n) {
        double[] array = new double[2*n];
        for (int i = 0; i<n; i++){
            array[2*i] = RADIUS*Math.cos(2*Math.PI/n*i)+CENTER.getX();
            array[2*i+1]=RADIUS*Math.sin(2*Math.PI/n*i)+CENTER.getY();
        }
        return array;
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output when the pentagon button is selected:


64. RotateTransition

With RotateTransition we can rotate a node.


Here the button is rotated for 20 seconds, from 0 to 45 degree, and another 20 seconds, going back.


package ex64;

import javafx.animation.RotateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Ex64 extends Application {

    @Override
    public void start(Stage stage) {
       
        Group root = new Group();
        
        Button button = new Button("RotateTransition");
        button.setPrefSize(250,250);
        button.setLayoutX(100); button.setLayoutY(100);
        
        RotateTransition rt = new RotateTransition(
                Duration.seconds(20), button);
        rt.setToAngle(45);
        rt.setFromAngle(0);
        rt.setAutoReverse(true);
        rt.setCycleCount(2);
        
        root.getChildren().add(button);
        
        button.setOnAction(e -> rt.play());
        
        Scene scene = new Scene(root, 500, 500, Color.PAPAYAWHIP);
        stage.setTitle("Example 64. RotateTransition");
        stage.setScene(scene);
        stage.show();
    }

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


This is the output during the animation:


63. DisplacementMap

With DisplacementMap effect, we can move pixel in x or y.


Here motion is based on absolute function on the y-axis There is no x-displacement.


package ex63;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.effect.DisplacementMap;
import javafx.scene.effect.FloatMap;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class Ex63 extends Application {

    @Override
    public void start(Stage stage) {
        Group root = new Group();

        FloatMap map = new FloatMap(250, 100);
        for (int i = 0; i < map.getWidth(); i++) {
            double value = -Math.abs(.002*(i-125));
            for (int j = 0; j < map.getHeight(); j++)
                map.setSamples(i, j, 0f, (float)value);
        }
        DisplacementMap displacementMap = new DisplacementMap(map);
        
        Label label = new Label("Displacement");
        label.setFont(Font.font("Georgia", 50));
        label.setPrefHeight(100);
        label.setLayoutX(55); label.setLayoutY(30);
        label.setEffect(displacementMap);
        
        root.getChildren().add(label);

        Scene scene = new Scene(root, 450, 200, Color.LIGHTYELLOW);
        stage.setTitle("Example 63. DisplacementMap");
        stage.setScene(scene);
        stage.show();
    }

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

This is the output:


Tuesday, June 21, 2016

62. TextFlow

A TextFlow layout can be used to align text and other nodes.


We also apply a DropShadow effect.


package ex62;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.DropShadow;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;

public class Ex62 extends Application {

    @Override
    public void start(Stage stage) {

        DropShadow dropShadow = new DropShadow();
        dropShadow.setOffsetX(4);
        dropShadow.setOffsetY(6);
        dropShadow.setColor(Color.PURPLE);
        
        Text text = new Text("A TextFlow Layout ");
        text.setFont(Font.font("Georgia", 64));
        text.setFill(Color.BLUE);
        text.setEffect(dropShadow);
        
        TextFlow root = new TextFlow(text);
        root.setTextAlignment(TextAlignment.CENTER);
        root.setLineSpacing(10);
        
        Scene scene = new Scene(root, 300, 300, Color.LIGHTGREEN);
        stage.setTitle("Example 62. TextFlow");
        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output:


61. AnchorPane

AnchorPane layout can fix nodes to certain distances from the four corners.


Here we set 4 rectangles (squares) and circles near each of the four coners.


package ex61;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Ex61 extends Application {

    @Override
    public void start(Stage stage) {
                
        Rectangle square1 = new Rectangle(25,25,Color.RED);
        AnchorPane.setTopAnchor(square1, 10.0);
        AnchorPane.setLeftAnchor(square1, 10.0);
        Circle circle1 = new Circle(25);
        circle1.setFill(Color.RED);
        AnchorPane.setTopAnchor(circle1, 50.0);
        AnchorPane.setLeftAnchor(circle1, 50.0);
        
        Rectangle square2 = new Rectangle(25,25,Color.BLUE);
        AnchorPane.setBottomAnchor(square2, 10.0);
        AnchorPane.setLeftAnchor(square2, 10.0);
        Circle circle2 = new Circle(25);
        circle2.setFill(Color.BLUE);
        AnchorPane.setBottomAnchor(circle2, 50.0);
        AnchorPane.setLeftAnchor(circle2, 50.0);
        
        Rectangle square3 = new Rectangle(25,25,Color.YELLOW);
        AnchorPane.setTopAnchor(square3, 10.0);
        AnchorPane.setRightAnchor(square3, 10.0);
        Circle circle3 = new Circle(25);
        circle3.setFill(Color.YELLOW);
        AnchorPane.setTopAnchor(circle3, 50.0);
        AnchorPane.setRightAnchor(circle3, 50.0);
        
        Rectangle square4 = new Rectangle(25,25,Color.GREEN);
        AnchorPane.setBottomAnchor(square4, 10.0);
        AnchorPane.setRightAnchor(square4, 10.0);
        Circle circle4 = new Circle(25);
        circle4.setFill(Color.GREEN);
        AnchorPane.setBottomAnchor(circle4, 50.0);
        AnchorPane.setRightAnchor(circle4, 50.0);
        
        AnchorPane anchorPane = new AnchorPane(square1, square2,
                square3, square4,
                circle1, circle2,
                circle3, circle4);
        
        Scene scene = new Scene(anchorPane, 300, 300, Color.LIGHTGREEN);
        stage.setTitle("Example 61. AnchorPane");
        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

This is the output after the window is resized:


60. TilePane

A TilePane organizes nodes in a table kind of view, with the height and width set by the biggest element in a row or column.


Here 12 different sized and colored rectangles are drawn and put in a new slot.


package ex60;

import java.util.ArrayList;
import java.util.Random;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Ex60 extends Application {

    final int NUMCOLORS = 12;
    @Override
    public void start(Stage stage) {
       
        ArrayList<Color> colors = new ArrayList<>();
        
        Random rand = new Random();
        
        int i, r, g, b;
        
        for (i = 0; i<NUMCOLORS; i++) {
            r = rand.nextInt(256);
            b = rand.nextInt(256);
            g = rand.nextInt(256);
            colors.add(Color.rgb(r, g, b));
        }
        
        TilePane tilePane = new TilePane();
        tilePane.setPadding(new Insets(50, 50, 50, 50));
        tilePane.setHgap(25);
        tilePane.setVgap(25);
        
        for (i = 0; i < colors.size(); i++) {
            int w = 50+rand.nextInt(51); // 50 to 100
            int h = 50+rand.nextInt(51); // 50 to 100
            Rectangle rect = new Rectangle(w, h, colors.get(i));
            rect.setArcWidth(25);
            rect.setArcHeight(25);
            tilePane.getChildren().add(rect);
        }

        Scene scene = new Scene(tilePane, Color.GRAY);
        stage.setTitle("Example 60. TilePane");
        stage.setScene(scene);
        stage.show();
    }

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

This is the output:


59. SepiaTone

The SepiaTone effect can be applied to a node, usually an image. Here we chained an ImageInput with the SepiaTone effect.


The SepiaTone effect is used to create image looking older and more monochrome.


package ex59;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.ImageInput;
import javafx.scene.effect.SepiaTone;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class Ex59 extends Application {

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        
        String hillary = "Hillary";
        String clinton = "Clinton";

        SepiaTone sepiaTone = new SepiaTone();
        sepiaTone.setLevel(.5);
        
        String fileName = hillary + clinton + ".png";

        Image image = new Image(fileName);
        ImageInput imageInput = new ImageInput(image);
        sepiaTone.setInput(imageInput);
        root.setEffect(sepiaTone);
 
        Scene scene = new Scene(root);
        stage.setTitle("Example 59. SepiaTone");
        stage.setScene(scene);
        stage.show();
    }

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

This is the output:


58. Reflection

The Reflection effect can be used on a node. The offset will indicate the distance downwards where the reflection starts. Here we only applied to 90% of the height, and had top opacity as .8 and lower as 0.4 (much lighter).


We can see the effect on an ImageView node and a text node.


package ex58;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.Reflection;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Ex58 extends Application {
    
    @Override
    public void start(Stage stage) {
        
        HBox root = new HBox(50);
        
        Reflection reflection = new Reflection();
        reflection.setFraction(.9);
        reflection.setTopOffset(5);
        reflection.setTopOpacity(.8);
        reflection.setBottomOpacity(.4);
        
        String hillary = "Hillary";
        String clinton = "Clinton";
        
        Image image=new Image(hillary+clinton+".png",200,200,true,true);
        ImageView imageView = new ImageView(image);
        imageView.setEffect(reflection);
        
        Text text = new Text(100, 100, hillary + " " + clinton);
        text.setFont(Font.font("Georgia", FontWeight.BOLD, 
                FontPosture.ITALIC, 60));
        text.setFill(Color.BLUE);
        text.setEffect(reflection);
        
        root.getChildren().addAll(imageView, text);
        
        Scene scene = new Scene(root, 700, 400, Color.LIGHTYELLOW);
        stage.setTitle("Example 58. Reflection");
        stage.setScene(scene);
        stage.show();
    }

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

This is the output: