引言

  • JavaFX是开发JavaGUI程序的新框架
  • JavaFX API是演示如何应用面向对象原则的优秀范例

JavaFX与Swing以及AWT的比较

  • JavaFX平台取代了Swing和AMT,用于开发富GUI(图形用户界面)应用
  • GUI类使用一个称为抽象窗体工具包(AWT)的库
  • AWT开发简单的图形用户界面尚可,但是不适合开发综合型的GUI项目,且易受特定于平台的错误的影响
  • Swing组件使用Java代码在画布上直接绘制,Swing组件较少依赖目标平台,且使用更少的本地GUI资源,用于开发桌面GUI应用

JavaFX程序的基本结构

  • javafx.application.Application类定义了编写JavaFX程序的基本框架
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

public class MyJavaFX extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a button and place it in the scene
    Button btOK = new Button("OK");
    Scene scene = new Scene(btOK, 200, 250);
    primaryStage.setTitle("MyJavaFX"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
 * The main method is only needed for the IDE with limited
 * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) { 
    launch(args); 
  }
}
  • 程序说明:
  • lanch方法是定义一个在Application类中的静态方法,用于启动一个独立的JavaFX应用
  • main方法不是必需的
  • 一个称为主舞台的Stage对象由JVM自动创建
  • 默认情况下,用户可以改变舞台的大小

面板,组,UI组件以及形状

  • 面板,组,UI组件以及形状是Node的子类型
  • 结点是可视化组件
  • 形状是指文本,直线,圆,椭圆,矩形,多边形,弧,折线等
  • UI组件是指标签,按钮,复选框,单选按钮,文本域,文本输入,区域等
  • 是将结点集合进行分组的容器
  • Scene可以包含Control,Group,或者Pane,但是不能包含Shape或者ImageView
  • Pane和Group可以包含Node的任何子类型
  • Node的每个子类都有一个无参构造方法,用于创建一个默认的结点
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ButtonInPane extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a scene and place a button in the scene
    StackPane pane = new StackPane();
    pane.getChildren().add(new Button("OK"));    
    Scene scene = new Scene(pane, 200, 50);
    primaryStage.setTitle("Button in a pane"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
 * The main method is only needed for the IDE with limited
 * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._JavaFXGUI编程


JavaFXGUI编程 javafx._java_02

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

public class ShowCircle extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a circle and set its properties
    Circle circle = new Circle();
    circle.setCenterX(100);
    circle.setCenterY(100);
    circle.setRadius(50);
    circle.setStroke(Color.BLACK);
    circle.setFill(Color.RED);
    
    // Create a pane to hold the circle 
    Pane pane = new Pane();
    pane.getChildren().add(circle);
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane, 200, 200);
    primaryStage.setTitle("ShowCircle"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._ci_03


JavaFXGUI编程 javafx._JavaFX_04

  • 在Java坐标系中,面板左上角的坐标是(0,0),不同于传统坐标系中(0,0)位于窗体的中央

  • 如图,在Java坐标系中,X坐标从左向右递增,Y坐标从上向下递增
  • JavaFXGUI编程 javafx._css_05

  • 面板置于场景中,然后场景置于舞台中

属性绑定
  • 可以将一个目标对象绑定到源对象中,源对象的修改将自动反映到目标对象中
  • 目标对象称为绑定对象或者绑定属性
  • 源对象称为可绑定对象或者可观察对象
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ShowCircleCentered extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {    
    // Create a pane to hold the circle 
    Pane pane = new Pane();
    
    // Create a circle and set its properties
    Circle circle = new Circle();
    circle.centerXProperty().bind(pane.widthProperty().divide(2));
    circle.centerYProperty().bind(pane.heightProperty().divide(2));
    circle.setRadius(50);
    circle.setStroke(Color.BLACK); 
    circle.setFill(Color.RED);
    pane.getChildren().add(circle); // Add circle to the pane

    // Create a scene and place it in the stage
    Scene scene = new Scene(pane, 200, 200);
    primaryStage.setTitle("ShowCircleCentered"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._JavaFX_06


JavaFXGUI编程 javafx._ci_07

结点的共同属性和方法
  • 节点具有许多通用的属性
  • JavaFX中的样式属性称为JavaFX CSS
  • 样式属性使用前缀-fx-进行定义
  • 每个结点拥有它自己的样式属性
  • 设定样式的语法是 styleName:value
  • 一个结点的多个样式属性可以一起设置,通过分号;进行分隔
  • JavaFXGUI编程 javafx._ci_08


  • 如果使用了一个不正确的JavaFX CSS,程序依然可以编译和运行,但是样式将被忽略
  • rotate属性可以设定一个以度为单位的角度,让结点围绕它的中心旋转该角度 正顺负逆
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.scene.layout.StackPane;

public class NodeStyleRotateDemo extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a scene and place a button in the scene
    StackPane pane = new StackPane();
    Button btOK = new Button("OK");
    btOK.setStyle("-fx-border-color: blue;");
    pane.getChildren().add(btOK);    
    
    pane.setRotate(45);
    pane.setStyle(
      "-fx-border-color: red; -fx-background-color: lightgray;");
    
    Scene scene = new Scene(pane, 200, 250);
    primaryStage.setTitle("NodeStyleRotateDemo"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._ci_09

Color类
  • Color类可以用于创建颜色

  • javafx.scene.paint.Color 子类
  • JavaFXGUI编程 javafx._JavaFX_10

  • 可以通过以下方法构建color实例:

public Color( double r, double g, double b, double opacity)
  • r: 红色 g:绿色 b:蓝色 0.0(最深色) 1.0(最浅色)
  • opacity:透明度 0.0(完全透明) 1.0(完全不透明)
  • Color类是不可修改的
Font类
  • Font类描述字体名称,粗细和大小
  • javafx.scene.text.Font
  • JavaFXGUI编程 javafx._JavaFXGUI编程_11


  • Font实例可以用它的构造方法或者静态方法来构建
  • Font可以用它的名称,粗细,字形和大小来描述
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.*;
import javafx.scene.control.*;
import javafx.stage.Stage;


public class FontDemo extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {    
    // Create a pane to hold the circle 
    Pane pane = new StackPane();
    
    // Create a circle and set its properties
    Circle circle = new Circle();
    circle.setRadius(50);
    circle.setStroke(Color.BLACK); 
    circle.setFill(new Color(0.5, 0.5, 0.5, 0.1));
    pane.getChildren().add(circle); // Add circle to the pane

    // Create a label and set its properties
    Label label = new Label("JavaFX");
    label.setFont(Font.font("Times New Roman", 
      FontWeight.BOLD, FontPosture.ITALIC, 20));
    pane.getChildren().add(label);

    // Create a scene and place it in the stage
    Scene scene = new Scene(pane);
    primaryStage.setTitle("FontDemo"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
 * The main method is only needed for the IDE with limited
 * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._java_12

  • Font对象是不可改变的
Image和ImageView类
  • Image类创建一个图形图像
  • ImageView类可以用于显示一个图像
  • java.scene.image.Image类表示一个图像,用于从一个指定的文件名或者URL载入一个图像
  • java.scene.image.ImageView是一个用于显示图像的结点
  • ImageView可以从一个Image对象创建
  • JavaFXGUI编程 javafx._ci_13


  • JavaFXGUI编程 javafx._JavaFXGUI编程_14


  • JavaFXGUI编程 javafx._JavaFX_15


import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class ShowImage extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a pane to hold the image views
    Pane pane = new HBox(10);
    pane.setPadding(new Insets(5, 5, 5, 5));
    Image image = new Image("image/us.gif");
    pane.getChildren().add(new ImageView(image));
    
    ImageView imageView2 = new ImageView(image);
    imageView2.setFitHeight(100);
    imageView2.setFitWidth(100);
    pane.getChildren().add(imageView2);   

    ImageView imageView3 = new ImageView(image);
    imageView3.setRotate(90);
    pane.getChildren().add(imageView3);     
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane);
    primaryStage.setTitle("ShowImage"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._ci_16

  • Image对象可以被多个结点共享
  • ImageView这样的结点不能共享,不能讲一个ImageView多次放入一个面板或者场景中
  • 注意⚠️:必须将图像文件放在类文件的相同目录中,如下图所示:
  • JavaFXGUI编程 javafx._JavaFXGUI编程_17


布局面板和组
  • JavaFX提供了多种类型的面板,用于自动地将结点以希望的位置和大小进行布局
  • 面板和组是容纳结点的容器
  • Group类常用于将结点组合成组并作为一个组进行转换和缩放
  • 面板和UI组件对象是可改变大小的
  • JavaFXGUI编程 javafx._java_18


FlowPane(流水面板)

  • FlowPane将结点按照加入的顺序,从左到右水平或从上到下垂直组织
  • 水平:Orientation.HORIZONTAL
  • 垂直:Orientation.VERTICAL
  • JavaFXGUI编程 javafx._java_19


import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class ShowFlowPane extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a pane and set its properties
    FlowPane pane = new FlowPane();
    pane.setPadding(new Insets(11, 12, 13, 14));  //Insets对象制定了一个面板边框的大小
    pane.setHgap(5);
    pane.setVgap(5);

    // Place nodes in the pane
    pane.getChildren().addAll(new Label("First Name:"), 
      new TextField(), new Label("MI:"));
    TextField tfMi = new TextField();
    tfMi.setPrefColumnCount(1); //文本域结点
    pane.getChildren().addAll(tfMi, new Label("Last Name:"),
      new TextField());
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane, 200, 250);
    primaryStage.setTitle("ShowFlowPane"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._css_20

  • 将一个结点加入一个面板中多次或者不同面板中将引起运行时错误

GridPane(网络面板)

  • GridPane将结点安排在一个网格(矩阵)结构中
  • 结点放在一个指定下标的列和行中
  • JavaFXGUI编程 javafx._ci_21


import javafx.application.Application;
import javafx.geometry.HPos;
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.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class ShowGridPane extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a pane and set its properties
    GridPane pane = new GridPane();
    pane.setAlignment(Pos.CENTER);  //对齐方式居中
    pane.setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
    pane.setHgap(5.5);
    pane.setVgap(5.5);
    
    // Place nodes in the pane
    pane.add(new Label("First Name:"), 0, 0); //标签
    pane.add(new TextField(), 1, 0); 
    pane.add(new Label("MI:"), 0, 1); 
    pane.add(new TextField(), 1, 1);
    pane.add(new Label("Last Name:"), 0, 2);
    pane.add(new TextField(), 1, 2);
    Button btAdd = new Button("Add Name");
    pane.add(btAdd, 1, 3);
    GridPane.setHalignment(btAdd, HPos.RIGHT); //调用静态的setHalignment方法将按钮在单元格中右对齐
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane);
    primaryStage.setTitle("ShowGridPane"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._JavaFXGUI编程_22

BorderPane(边框面板)

JavaFXGUI编程 javafx._css_23

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ShowBorderPane extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a border pane 
    BorderPane pane = new BorderPane();

    // Place nodes in the pane
    pane.setTop(new CustomPane("Top")); 
    pane.setRight(new CustomPane("Right"));
    pane.setBottom(new CustomPane("Bottom"));
    pane.setLeft(new CustomPane("Left"));
    pane.setCenter(new CustomPane("Center")); 
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane);
    primaryStage.setTitle("ShowBorderPane"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  public static void main(String[] args) {
	    launch(args);
	  }
} 

// Define a custom pane to hold a label in the center of the pane
class CustomPane extends StackPane {
  public CustomPane(String title) {
    getChildren().add(new Label(title));
    setStyle("-fx-border-color: red");
    setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
  }
}

JavaFXGUI编程 javafx._JavaFXGUI编程_24

  • 一个面板是一个结点,所以一个面板可以加入另外一个面板中

HBox和VBox

  • HBox将他的子结点布局在单个水平行中
  • VBox将他的子结点布局在单个垂直列中
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class ShowHBoxVBox extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a border pane 
    BorderPane pane = new BorderPane();

    // Place nodes in the pane
    pane.setTop(getHBox()); 
    pane.setLeft(getVBox());
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane);
    primaryStage.setTitle("ShowHBoxVBox"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  private HBox getHBox() {
    HBox hBox = new HBox(15); 
    hBox.setPadding(new Insets(15, 15, 15, 15));
    hBox.setStyle("-fx-background-color: gold");
    hBox.getChildren().add(new Button("Computer Science"));
    hBox.getChildren().add(new Button("Chemistry"));
    ImageView imageView = new ImageView(new Image("image/us.gif"));
    hBox.getChildren().add(imageView);
    return hBox;
  }
  
  private VBox getVBox() {
    VBox vBox = new VBox(15);
    vBox.setPadding(new Insets(15, 5, 5, 5));
    vBox.getChildren().add(new Label("Courses"));
    
    Label[] courses = {new Label("CSCI 1301"), new Label("CSCI 1302"), 
        new Label("CSCI 2410"), new Label("CSCI 3720")};

    for (Label course: courses) {
      VBox.setMargin(course, new Insets(0, 0, 0, 15));
      vBox.getChildren().add(course);
    }
    
    return vBox;
  }
  
  /**
 * The main method is only needed for the IDE with limited
 * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._JavaFXGUI编程_25

形状
  • Shape类是一个抽象基类,定义了所有形状的共同属性
  • fill属性指定一个填充形状内部区域的颜色
  • Stroke属性指定用于绘制形状轮廓的颜色
  • stroekWidth属性指定形状轮廓的宽度
  • JavaFXGUI编程 javafx._ci_26


Text

  • Text类定义了一个结点,用于在一个起始点(x,y)处显示一个字符串
  • Text对象通常设置在一个面板中
  • JavaFXGUI编程 javafx._ci_27


import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.FontPosture;

public class ShowText extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {
    // Create a pane to hold the texts
    Pane pane = new Pane();
    pane.setPadding(new Insets(5, 5, 5, 5));
    Text text1 = new Text(20, 20, "Programming is fun");
    text1.setFont(Font.font("Courier", FontWeight.BOLD, 
      FontPosture.ITALIC, 15));
    pane.getChildren().add(text1);     

    Text text2 = new Text(60, 60, "Programming is fun\nDisplay text");
    pane.getChildren().add(text2);     

    Text text3 = new Text(10, 100, "Programming is fun\nDisplay text");
    text3.setFill(Color.RED);
    text3.setUnderline(true);
    text3.setStrikethrough(true);    
    pane.getChildren().add(text3); 
    
    // Create a scene and place it in the stage
    Scene scene = new Scene(pane);
    primaryStage.setTitle("ShowText"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage
  }
  
  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);
  }
}

JavaFXGUI编程 javafx._JavaFXGUI编程_28