首页 > 代码库 > javafx之FXML初探

javafx之FXML初探

FXML作为XML-based,UI构造器。其相关的规则值得我们去理解。

FXML元素分类:

  • A class instance
  • A property of a class instance
  • A "static" property
  • A "define" block
  • A block of script code
FXML应该在根元素定义prefix : xmlns:fx=http://javafx.com/xml

Class instance 元素

实例声明
<?import javafx.scene.control.Label?>
<Label text="Hello, World!"/>
Maps
<HashMap foo="123" bar="456"/>

fx:value-对于没有默认构造器的类如String,Double等但是有valueOf方法的
<String fx:value=http://www.mamicode.com/"Hello, World!"/>>
fx:factory-对于使用静态工厂方法的
<FXCollections fx:factory="observableArrayList">
    <String fx:value=http://www.mamicode.com/"A"/>>
Builders使用构造器模式的类:如Color
<Color red="1.0" green="0.0" blue="0.0"/>
<Color>
    <red>1.0</red>
    <green>0.0</green>
    <blue>0.0</blue>
</Color>

fx:include-包含另一个fxml文件或者国际化资源文件resource bundle
<fx:include source="filename"/>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox xmlns:fx="http://javafx.com/fxml">
    <children>
        <fx:include source="my_button.fxml"/>
    </children>
</VBox>
my_button.fxml
<?import javafx.scene.control.*?>
<Button text="My Button"/>
包含国际化资源文件
<fx:include source="filename" resources="resource_file" charset="utf-8"/>

fx:constant
<Button>
    <minHeight><Double fx:constant="NEGATIVE_INFINITY"/></minHeight>
</Button>

fx:reference-通过fx:id进行引用
<ImageView>
    <image>
        <fx:reference source="myImage"/> //用于替代ImageView的image属性
    </image>
</ImageView>
<ArrayList>
    <fx:reference source="element1"/>
    <fx:reference source="element2"/>
    <fx:reference source="element3"/>
</ArrayList>

fx:copy-暂时别用,以后也许会改变

fx:root-指向root元素

Property元素

property元素支持强制类型转换。
分为:
  • A property setter
  • A read-only list property
  • A read-only map property
Property Setters
<?import javafx.scene.control.Label?>
<Label>
    <text>Hello, World!</text>
</Label>
<?import javafx.scene.control.Label?>
<Label text="Hello, World!"/>

ReadOnly List Property
<Group xmlns:fx="http://javafx.com/fxml">
    <children>
        <Rectangle fx:id="rectangle" x="10" y="10" width="320" height="240"
            fill="#ff0000"/>
        ...
    </children>
</Group>

ReadOnly Map Property
<?import javafx.scene.control.*?>
<Button>
    <properties foo="123" bar="456"/>
</Button>

Default Property
<?import javafx.scene.*?>
<?import javafx.scene.shape.*?>
<VBox xmlns:fx="http://javafx.com/fxml">
    <Button text="Click Me!"/>
    ...
</VBox>

Static Property
<GridPane>
    <children>
        <Label text="My Label">
            <GridPane.rowIndex>0</GridPane.rowIndex>
       <GridPane.columnIndex>0</GridPane.columnIndex>
        </Label>
    </children>
</TabPane>

定义Blocks----fx:define
fx:define定义的内容不会被添加到Scene Graph,最典型的应用就是单选按钮组中ToggleGroup的fx:define
引用它之前需要添加符号$
<VBox>
    <fx:define>
        <ToggleGroup fx:id="myToggleGroup"/>
    </fx:define>
    <children>
        <RadioButton text="A" toggleGroup="$myToggleGroup"/>
        <RadioButton text="B" toggleGroup="$myToggleGroup"/>
        <RadioButton text="C" toggleGroup="$myToggleGroup"/>
    </children>
</VBox>



Attributes:

分类:
  • A property of a class instance
  • A "static" property
  • An event handler
Property Attribute与Property Element是有区别:
1.property attribute只有当元素关闭时才会生效
2.property attribute还支持解析操作(resolution operators):
  • Location resolution位置解析
  • Resource resolution国际化资源解析
  • Variable resolution变量解析

Location resolution

@代表与当前fxml文件在同一目录
<ImageView>
    <image>
        <Image url="@my_image.png"/>
    </image>
</ImageView>
注意@路径解析后面接的必须是已经被URL编码的字符。如My Image.jpg应该写成这样
<Image url="@My%20Image.png"/>

Resource resolution

%代表该字符变量应该用国际化资源解析
<Label text="%myText"/>

Variable resolution

$代表需要进行变量解析,一般与fx:define配合使用
<fx:define>
    <ToggleGroup fx:id="myToggleGroup"/>
</fx:define>
...
<RadioButton text="A" toggleGroup="$myToggleGroup"/>
<RadioButton text="B" toggleGroup="$myToggleGroup"/>

转义处理:

<Label text="\$10.00"/>


表达式绑定:

${expr}
<TextField fx:id="textField"/>
<Label text="${textField.text}"/>

支持的其他操作:
"string"
‘string‘
A string constant
true
false
A boolean constant
nullA constant representing the null value
50.0
3e5
42
A numerical constant

(unary operator)
Unary minus operator, applied on a number

(unary operator)
Unary negation of a boolean
+ - 
* / %
Numerical binary operators
&& ||Boolean binary operators
> >= 
< <= 
== !=
Binary operators of comparison.
Both arguments must be of type Comparable

Static Properties与Instance Properties类似

static properties attribute与element有点区别:
  <Label text="My Label" GridPane.rowIndex="0" GridPane.columnIndex="0"/>

EventHandlers

适用于setOnEvent类的方法(如setOnAction)

脚本化处理方式:

使用javascript声明与脚本
<?language javascript?>
...

<VBox>
    <children>
        <Button text="Click Me!"
            onAction="java.lang.System.out.println(‘You clicked me!‘);"/>
    </children>
</VBox>

控制器类Controller方法处理方式:

注意#号,与@FXML注解
<VBox fx:controller="com.foo.MyController"
    xmlns:fx="http://javafx.com/fxml">
    <children>
        <Button text="Click Me!" onAction="#handleButtonAction"/>
    </children>
</VBox>
public class MyController {
   @FXML public void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
    }
}
下面这种方式也是有效的
public class MyController {
    public void handleButtonAction() {
        System.out.println("You clicked me!");
    }
}

对于Collections与properties的特殊的处理

 ObservableListObservableMap orObservableSet uses a special onChange attribute that points to a handler method with aListChangeListner.ChangeMapChangeListener.Change or SetChangeListener.Changeparameter respectively.
<VBox fx:controller="com.foo.MyController"
    xmlns:fx="http://javafx.com/fxml">
    <children onChange="#handleChildrenChange"/>
</VBox>
public class MyController {
    public void handleChildrenChange(ListChangeListener.Change c) {
        System.out.println("Children changed!");
    }
}

对于parent property的处理:
public class MyController {
    public void handleParentChange(ObservableValue value, Parent oldValue, Parent newValue) {
        System.out.println("Parent changed!");
    }
}
<VBox fx:controller="com.foo.MyController"
    xmlns:fx="http://javafx.com/fxml" onParentChange="#handleParentChange"/>


Scripting脚本化

<?language javascript?>
<fx:script>
<?language javascript?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml">
    <fx:script>

    function handleButtonAction(event) {
       java.lang.System.out.println(‘You clicked me!‘);
    }
    </fx:script>

    <children>
        <Button text="Click Me!" onAction="handleButtonAction(event);"/>
    </children>
</VBox>

从外部文件读取脚本。
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml">
    <fx:script source="example.js" charset="cp1252"/>

    <children>
        <Button text="Click Me!" onAction="handleButtonAction(event);"/>
    </children>
</VBox>
example.js:
function handleButtonAction(event) {
   java.lang.System.out.println(‘You clicked me!‘);
}
<fx:script>
var myText = "This is the text of my label.";
</fx:script>

...

<Label text="$myText"/>

Controllers

fx:controller
<VBox fx:controller="com.foo.MyController"
    xmlns:fx="http://javafx.com/fxml">
    <children>
        <Button text="Click Me!" onAction="#handleButtonAction"/>
    </children>
</VBox>
public class MyController {
    public void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
    }
}
当然Controllers类还可以实现Initializable接口,以便在被加载时可以调用初始化方法initialize()
<VBox fx:controller="com.foo.MyController"
    xmlns:fx="http://javafx.com/fxml">
    <children>
        <Button fx:id="button" text="Click Me!"/>
    </children>
</VBox>
package com.foo;

public class MyController implements Initializable {
    public Button button;

    @Override
    public void initialize(URL location, Resources resources)
        button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                System.out.println("You clicked me!");
            }
前面介绍的都是通过public修饰field与方法,但是这破坏了封装性原则。
由于controller是对FXML Loader可见的,所以没必要对外部开放访问权限。
这样我们就必须通过@FXML注解进行修饰。
public class MyController {
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
    }
}
public class MyController implements Initializable {
    @FXML private Button button;

    @FXML
    protected void initialize()
        button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                System.out.println("You clicked me!");
            }

Nested Controllers嵌套的控制器访问。

FXMLLoader

URL location = getClass().getResource("example.fxml");
ResourceBundle resources = ResourceBundle.getBundle("com.foo.example");
FXMLLoader fxmlLoader = new FXMLLoader(location, resources);

Pane root = (Pane)fxmlLoader.load();
MyController controller = (MyController)fxmlLoader.getController();

使用FXML结合FXMLLoader自定义UI组件

通过使用<fx:root>元素指定root元素的类型:
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<fx:root type="javafx.scene.layout.VBox" xmlns:fx="http://javafx.com/fxml">
    <TextField fx:id="textField"/>
    <Button text="Click Me" onAction="#doSomething"/>
</fx:root>
自定义的UI组件:
package fxml;

import java.io.IOException;

import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

public class CustomControl extends VBox {
    @FXML private TextField textField;

    public CustomControl() {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    public String getText() {
        return textProperty().get();
    }

    public void setText(String value) {
        textProperty().set(value);
    }

    public StringProperty textProperty() {
        return textField.textProperty();
    }

    @FXML
    protected void doSomething() {
        System.out.println("The button was clicked!");
    }
}

使用自定义的UI组件:
HBox hbox = new HBox();
CustomControl customControl = new CustomControl();
customControl.setText("Hello World!");
hbox.getChildren().add(customControl);

<HBox>
    <CustomControl text="Hello World!"/>
</HBox>





javafx之FXML初探