HelloWorld创世纪
完成好JavaFX的环境搭建之后,我们开始正式地编写JavaFX的代码。在Eclipse中File->New Project->JavaFx->JavaFX Application,完成项目创建。
我们看到的是这样的默认代码
/*Main.java*/
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
来看看代码结构中几个关键的点:
Ⅰ. JavaFX应用中的核心类Main是继承自
javafx.application.Application的子类,Application的一个实例化对象在整个生命周期会经历以下几个过程:
- 构建一个指定Application类的实例化对象。
- 调用init()方法进行初始化工作
- 调用start(javafx.stage.Stage)方法
- 等待Application结束,即以下两种情况之一:1)调用Platform.exit()方法时 2)所有的window都被关闭,并且Platform的implicitExit参数为true。
- 调用stop()方法
Ⅱ.
JavaFX Application通过stage和scene来定义UI容器,其中Stage是最顶层的JavaFX容器,Scene是所有部件的容器。下图描述了一个简单的样例:
Ⅲ.
在JavaFX中,scene的部件被表示成拥有层次关系的节点。在上面例子中,根节点是StackPane root对象,Button btn则是root的子节点。
Ⅳ.
main()方法在JavaFX Application中不是必须的(在一些集成了JavaFX启动器的IDE中,会自动调用start()方法来启动JavaFX Application),但是考虑到某些情况下JavaFX启动器可能未被集成到IDE当中,或者有的时候我们是通过集成了JavaFX代码的Swing Application来启动JavaFX,所以把main()方法写出来还是很有必要的!
创建JavaFX表单
比较简单,直接上代码吧
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
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.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Login extends Application {
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("My Form");
GridPane grid = new GridPane(); //创建一个GridPane来布局
grid.setAlignment(Pos.CENTER); //GridPane在父容器中的位置
//以下代码设置grid的样式
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
Scene scene = new Scene(grid, 300, 275); //创建scene并把grid设为root节点
primaryStage.setScene(scene); //把scene渲染到primaryStage。
/**
* 注意一个Stage同一时间只能有一个scene,一个scene也只能被渲染到一个Stage。
* 如果同一个scene被渲染到两个Stage,则在新的Stage接受此scene之前会把旧Stage中对scene的引用销毁。
* 可以在任何时候对Stage中的scene进行调整,但是只能发生在JavaFX Application Thread中,
* 如果不是,则会扔出一个IllegalStateException
*/
Text scenetitle = new Text("Welcome"); //新建一个Text
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
grid.add(scenetitle, 0, 0, 2, 1); //在grid中添加scenetitle作为标题
//后四个参数分别表示行列的起始Index和跨度
//以下代码原理相同
Label userName = new Label("User Name:");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
grid.add(userTextField, 1, 1);
Label pw = new Label("Password:");
grid.add(pw, 0, 2);
PasswordField pwBox = new PasswordField();
grid.add(pwBox, 1, 2);
Button btn = new Button("Sign in");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 1, 4);
final Text actiontarget = new Text();
actiontarget.setText("Error");
actiontarget.setVisible(false);
actiontarget.setFill(Color.GOLD);
HBox acHBox = new HBox(10);
acHBox.setAlignment(Pos.BASELINE_CENTER);
acHBox.getChildren().add(actiontarget);
grid.add(acHBox, 0, 6, 2, 1);
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
actiontarget.setText(pwBox.getText());
actiontarget.setVisible(true);
}
});
//grid.setGridLinesVisible(true); //可以把GridLinesVisible设为true显示grid的行列线
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
代码运行效果:
使用CSS装饰
把业务逻辑跟样式代码分开,可以利用CSS。这里我们仍然使用上述Form中的代码来做修改
正式开始之前先把把原本.java代码中关于样式的语句删除
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
//删除//...
actiontarget.setFill(Color.GOLD);
//删除
OK,首先新建一个.css文件并在.java中关联它
scene.getStylesheets().add
(Login.class.getResource("Login.css").toExternalForm());
然后为需要使用CSS修饰的部件添加ID
scenetitle.setId("welcome-text");
actiontarget.setId("actiontarget");
接着开始编辑.css文件
@CHARSET "UTF-8";
.root {
-fx-background-image: url("background.jpg");/*设置背景图片*/
}
.label { /*利用类选择器为label类添加样式*/
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-text-fill: #333333;
-fx-effect: dropshadow(gaussian, rgba(255, 255, 255, 0.5), 0, 0, 0, 1);
}
#welcome-text { /*利用id选择器为id="welcome-text"的部件添加样式*/
-fx-font-size: 30px;
-fx-font-family: "Arial Black";
-fx-fill: #818181;
-fx-effect: innershadow(three-pass-box, rgba(0, 0, 0, 0.7), 6, 0.0, 0, 2);
}
#actiontarget { /*利用id选择器为id="actiongtarget"的部件添加样式*/
-fx-fill: FIREBRICK;
-fx-font-weight: bold;
-fx-effect: dropshadow(gaussian, rgba(255, 255, 255, 0.5), 0, 0, 0, 1);
}
运行效果如下:
更多关于javafx-css的信息请访问:
Skinning JavaFX Applications with CSS,
Styling FX Buttons with CSS,
JavaFX CSS Reference Guide
使用FXML来创建UI
JavaFX还支持使用一种FXML的语言来构建UI,以达到把UI和业务逻辑分开的目的。
下面来创建这个FXML项目。
首先,我们的项目包含以下三个文件:
作为整个Application的入口,FXMLExample.java中需载入fxml资源。
所以我们在代码中是通过javafx.fxml.FXMLLoader类来创建Parent节点的。
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("example.fxml"));
//载入example.fxml文件
Scene scene = new Scene(root,300,375);
primaryStage.setTitle("Hello FXML");
primaryStage.setScene(scene);
primaryStage.show();
}
简单完成这一步之后就可以对example.fxml进行编辑了,完整代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<GridPane fx:controller="javaFX_FXML.FXMLExampleController"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<padding>
<Insets top="25" right="25" bottom="10" left="25" />
</padding>
<!-- <gridLinesVisible>true</gridLinesVisible> -->
<Text text="Welcome" GridPane.columnIndex="0" GridPane.rowIndex="0"
GridPane.columnSpan="2" />
<Label text="User Name:" GridPane.columnIndex="0"
GridPane.rowIndex="1" />
<TextField GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Password:" GridPane.columnIndex="0"
GridPane.rowIndex="2" />
<PasswordField fx:id="passwordField"
GridPane.columnIndex="1" GridPane.rowIndex="2" />
<HBox spacing="10" alignment="bottom_right" GridPane.columnIndex="1"
GridPane.rowIndex="4">
<Button text="Sign In" onAction="#handleSubmitButtonAction" />
</HBox>
<Text fx:id="actiontarget" GridPane.columnIndex="0"
GridPane.columnSpan="2" GridPane.halignment="RIGHT" GridPane.rowIndex="6" />
</GridPane>
来看看整个fxml的结构,首行是对版本及字符编码的定义。
然后就把需要用到的包import进来(由于默认Eclipse环境不会自动导入需要的包,暂时还不知道有没有比较方便的途径可以导入需要用到的包)。接下来是一个<GridPane>
</GridPane>布局
组件,布局内部放入了需要用到的子组件,参数都是见名知意的。就不再添加注释了。
完成了在fxml中对UI的定义之后就要编辑Controller了,在FXMLExampleController.java中:
package javaFX_FXML;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.text.Text;
public class FXMLExampleController {
@FXML private Text actiontarget;
@FXML protected void handleSubmitButtonAction(ActionEvent event) {
actiontarget.setText("Sign in button pressed");
}
}
@FXML注释用来标记非public的FXML成员字段以及方法。其中字段名跟fx:id属性相关,方法则跟onAction属性相关。
当然,也可以在FXML中引用CSS。通过以下方法:
<stylesheets>
<URL value="@Login.css" />
</stylesheets>
</GridPane>
然后在需要引用CSS类的组件中添加styleClass属性,例如在GridPane中添加css的root类。
<GridPane fx:controller="fxmlexample.FXMLExampleController"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10"
styleClass="root">
也可以利用CSS的ID选择器来使用指定ID的样式:
<Text id="welcome-text" text="Welcome"
GridPane.columnIndex="0" GridPane.rowIndex="0"
GridPane.columnSpan="2"/>
更多相关文档:
Introduction to FXML