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="Hello, World!"/>
<Double fx:value="1.0"/>
<Boolean fx:value="false"/>

fx:factory-對於使用靜態工廠方法的
<FXCollections fx:factory="observableArrayList">
    <String fx:value="A"/>
    <String fx:value="B"/>
    <String fx:value="C"/>
</FXCollections>

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
null A 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>





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章