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: