JavaFX 最初是由 Oracle 推出的一个用于开发富客户端应用程序的框架,它提供了丰富的用户界面控件、布局容器、3D图形绘制、媒体播放和动画等功能,旨在取代较旧的 Swing 框架。JavaFX 于 2007 年推出,2011 年 10 月发布了2.0 版本。JavaFX 2.0 的一个优点是适用于跨平台,而且可以完全用 Java 语言编写代码。
2014年发布的JDK 8.0就包含了JavaFx 2.0 版本。然而,随着时间的发展和技术的变迁,JavaFx 2.0并未达到预期目标,而且在与其他的技术标准竟争中处于下风。从 JDK 11 开始,Oracle 决定不再将 JavaFX 包含在 JDK 中,如有需要JavaFX必须单独下载和使用。
尽管如此,JavaFX 仍然是一个强大的开发工具,开发者可用它来设计、编写、测试、调试和部署富客户端程序,支持跨平台使用。
我们先来看一个简单的“欢迎使用JavaFX”例程,其源代码如下:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class 欢迎使用JavaFX extends Application {
@Override public void start(Stage stage) {
Text text = new Text(10, 40, "欢迎使用 JavaFX !");
text.setFont(new Font(40));
Scene scene = new Scene(new Group(text), 400, 100);
stage.setTitle("欢迎使用JavaFX");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
程序演示结果:
下面再来看一个“3D图像演示”例程,其源代码如下:
/***3D图像演示例程***/
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class Shapes3DViewer extends Application {
@Override public void start(Stage stage) {
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.LIGHTGRAY);
material.setSpecularColor(Color.rgb(30, 30, 30));
Shape3D[] meshView = new Shape3D[] {
new Box(200, 200, 200),
new Sphere(100),
new Cylinder(100, 200),
};
for (int i=0; i!=3; ++i) {
meshView[i].setMaterial(material);
meshView[i].setTranslateX((i + 1) * 220);
meshView[i].setTranslateY(200);
meshView[i].setTranslateZ(20);
meshView[i].setDrawMode(DrawMode.FILL);
meshView[i].setCullFace(CullFace.BACK);
};
PointLight pointLight = new PointLight(Color.ANTIQUEWHITE);
pointLight.setTranslateX(800);
pointLight.setTranslateY(-100);
pointLight.setTranslateZ(-1000);
Group root = new Group(meshView);
root.getChildren().add(pointLight);
Scene scene = new Scene(root, 800, 400, true);
scene.setFill(Color.rgb(10, 10, 40));
scene.setCamera(new PerspectiveCamera(false));
stage.setTitle("3D图像演示");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
3D图像演示效果图:
JavaFX提供了丰富的控件来构造所需要的程序界面。JavaFX提供了一种容器控件,即面板Pane来简化解决这个问题,不同类型的面板采用不同的布局策略。我们可以根据实际的需要来选择不同的面板,从而构造出我们所需要的界面。下面就介绍几种常用的面板。
(一) FlowPane面板
它采用的布局管理器实际上就是AWT的FlowLayout:按照控件的添加次序按个摆放,按照从上到下、从左到右的次序摆放。当面板的大小发生变化后,舞台的大小也自动跟着变化,场景的大小也自动跟着调整,并且会重新计算各个控件的位置,重新摆放各个控件的位置。
FlowPane测试例程:
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.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class PaneTest extends Application {
public static Pane FlowPaneTest() {
FlowPane pane = new FlowPane();
pane.setPadding(new Insets(11, 12, 13, 14));
//设置控件之间的垂直间隔距离
pane.setHgap(5);
//设置控件之间的水平间隔距离
pane.setVgap(5);
Label lbName = new Label("姓名:");
TextField tfName = new TextField();
Label lbPassword = new Label("密码:");
TextField tfPassword = new TextField();
Button okbtn = new Button("递交");
pane.getChildren().addAll(lbName,tfName,lbPassword,tfPassword,okbtn);
return pane;
}
@Override
public void start(Stage stage) {
Pane pane = FlowPaneTest();
// 创建场景
Scene scene = new Scene(pane, 600, 150);
// 设置舞台
stage.setScene(scene);
stage.setTitle("JavaFX面板演示");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
例程演示结果图一:
当程序主窗口宽度变小时,例程演示结果图二:
(二) GridPane面板
它采用的布局管理器实际上就是AWT中的GridLayout:将整个面板划分为若干个格子,每个格子的大小是一样的,每个格子中可以放置一个控件,类似于网格的形式。
GridPane测试例程:
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.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class PaneTest extends Application {
public static Pane FlowPaneTest() {
FlowPane pane = new FlowPane();
pane.setPadding(new Insets(11, 12, 13, 14));
//设置控件之间的垂直间隔距离
pane.setHgap(5);
//设置控件之间的水平间隔距离
pane.setVgap(5);
Label lbName = new Label("姓名:");
TextField tfName = new TextField();
Label lbPassword = new Label("密码:");
TextField tfPassword = new TextField();
Button okbtn = new Button("递交");
pane.getChildren().addAll(lbName,tfName,lbPassword,tfPassword,okbtn);
return pane;
}
public Pane GridPaneTest() {
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);
pane.add(new Button("按钮A"), 0, 0);
pane.add(new Button("按钮B"), 1, 0);
pane.add(new Button("按钮C"), 0, 1);
pane.add(new Button("按钮D"), 1, 1);
pane.add(new Button("按钮E"), 0, 2);
pane.add(new Button("按钮F"), 1, 2);
return pane;
}
public void BorderPaneTest() {
}
public void HBoxTest() {
}
public void VBoxTest() {
}
@Override
public void start(Stage stage) {
//Pane pane = FlowPaneTest();
Pane pane = GridPaneTest();
// 创建场景
Scene scene = new Scene(pane, 320, 150);
// 设置舞台
stage.setScene(scene);
stage.setTitle("JavaFX面板演示");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
测试演示结果页面:
(三) BorderPane面板
它采用的布局管理器实际上就是AWT中的BorderLayout:将整个面板划分五个区域,分别是上、下、左、右、中,每个区域可以放置一个控件。
在此我们提供一个综合性的演示例程,它还组合使用了后续将要介绍的“HBox面板”和“VBox面板”,请看源代码:
/***BorderPane演示例程***/
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.Separator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class BorderPaneExample extends Application {
private BorderPane root;
@Override
public void start(Stage primaryStage) throws Exception
{
root = new BorderPane();
root.setTop(getMenu());
root.setRight(getRightHBox());
root.setBottom(getFooter());
root.setLeft(getLeftHBox());
root.setCenter(getCenterPane());
Scene scene = new Scene(root, 900, 500);
primaryStage.setTitle("BorderPane演示");
primaryStage.setScene(scene);
primaryStage.show();
}
private MenuBar getMenu()
{
MenuBar menuBar = new MenuBar();
Menu menuFile = new Menu("文件");
Menu menuEdit = new Menu("编辑");
Menu menuHelp = new Menu("帮助");
menuBar.getMenus().addAll(menuFile, menuEdit, menuHelp);
return menuBar;
}
private HBox getRightHBox()
{
HBox hbox = new HBox();
VBox vbox = new VBox(50);
vbox.setPadding(new Insets(0, 20, 0, 20));
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(new Text("其他提示信息A"),
new Text("其他提示信息B"), new Text("其他提示信息C"));
hbox.getChildren().addAll(new Separator(Orientation.VERTICAL), vbox);
return hbox;
}
private HBox getLeftHBox()
{
HBox hbox = new HBox();
VBox vbox = new VBox(10);
vbox.setPadding(new Insets(10));
Text text = new Text("导航");
text.setFont(Font.font("Helvetica", FontWeight.BOLD, 20));
VBox vboxText = new VBox(10);
for (int i = 1; i <= 10; i++)
{
vboxText.getChildren().add(new Text("目录 " + i));
}
Text text2 = new Text("结束位");
text2.setFont(Font.font("Helvetica", FontWeight.BOLD, 20));
vbox.getChildren().addAll(text, vboxText, text2);
hbox.getChildren().addAll(vbox, new Separator(Orientation.VERTICAL));
return hbox;
}
private VBox getFooter()
{
VBox vbox = new VBox();
HBox hbox = new HBox(20);
hbox.setPadding(new Insets(5));
hbox.setAlignment(Pos.CENTER);
hbox.getChildren().addAll(new Text("状态信息01")
, new Text("状态信息02"), new Text("状态信息03"));
vbox.getChildren().addAll(new Separator(), hbox);
return vbox;
}
private StackPane getCenterPane()
{
StackPane stackPane = new StackPane();
stackPane.setAlignment(Pos.CENTER);
Rectangle rec = new Rectangle(200, 200);
rec.setFill(Color.DODGERBLUE);
rec.widthProperty().bind(stackPane.widthProperty().subtract(50));
rec.heightProperty().bind(stackPane.heightProperty().subtract(50));
stackPane.getChildren().addAll(rec);
return stackPane;
}
public static void main(String[] args)
{
Application.launch(args);
}
}
例程的演示页面:
(四) HBox面板
HBox采用的布局管理器,我称其为行式布局管理器,这种布局管理器是对AWT的FlowLayout做了一些限制,它将所有的控件放在同一行,各控件横向布置,无论有多少个控件都是放在同一行,不允许换行。而AWT的FlowLayout布局管理器当一行放不下时是允许换行的。
HBox面板测试例程:
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.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class PaneTest extends Application {
public static Pane FlowPaneTest() {
FlowPane pane = new FlowPane();
pane.setPadding(new Insets(11, 12, 13, 14));
//设置控件之间的垂直间隔距离
pane.setHgap(5);
//设置控件之间的水平间隔距离
pane.setVgap(5);
Label lbName = new Label("姓名:");
TextField tfName = new TextField();
Label lbPassword = new Label("密码:");
TextField tfPassword = new TextField();
Button okbtn = new Button("递交");
pane.getChildren().addAll(lbName,tfName,lbPassword,tfPassword,okbtn);
return pane;
}
public Pane GridPaneTest() {
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);
pane.add(new Button("按钮A"), 0, 0);
pane.add(new Button("按钮B"), 1, 0);
pane.add(new Button("按钮C"), 0, 1);
pane.add(new Button("按钮D"), 1, 1);
pane.add(new Button("按钮E"), 0, 2);
pane.add(new Button("按钮F"), 1, 2);
return pane;
}
public Pane HBoxTest() {
HBox pane = new HBox(15);
pane.setPadding(new Insets(15, 15, 15, 15));
pane.setStyle("-fx-background-color: blue");
pane.getChildren().add(new Button("按钮A"));
pane.getChildren().add(new Button("按钮B"));
pane.getChildren().add(new Button("按钮C"));
pane.getChildren().add(new Button("按钮D"));
pane.getChildren().add(new Button("按钮E"));
pane.getChildren().add(new Button("按钮F"));
return pane;
}
@Override
public void start(Stage stage) {
//Pane pane = FlowPaneTest();
//Pane pane = GridPaneTest();
Pane pane = HBoxTest();
// 创建场景
Scene scene = new Scene(pane, 320, 150);
// 设置舞台
stage.setScene(scene);
stage.setTitle("JavaFX面板演示");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
例程测试效果图:
当框架窗口足够宽时,显示效果如下 :
当框架窗口宽度不足以显示所有组件时,绝不换行显示,超出窗体部分不可见。其显示效果如下 :
(五) VBox面板
VBox的布局策略与HBox有些类似,不过VBox是将所有的控件放在同一列,各控件纵向布置。
不同面板的布局策略各有特点,在应用开发中,可以根据实际需求选取合适的面板进行布局。很多情形可能需要将多种不同类型的面板组合起来使用,才能符合需求效果。
JavaFx 2.0 还可用Java编程实现音频和视频播放器,下一篇博客:
【多媒体】Java实现MP4和MP3音视频播放器【JavaFX】【音视频播放】