December 16, 2013

Day 10 Bind (Part 1)

Bind


Java FX ရဲ့ ထူးခြားချက်များတွင် UI Component များကြီးသာမဟုတ်။ လုပ်ဆောင်မှု့ Architecture အပိုင်းမှာလည်း ထူးခြားမှု့များပါလာပါသည်။ ၎င်းမှာ Bind Function ဖြစ်၏။ Bind Function သည် Property အချင်းချင်းအား အလိုအလျှောက် Synchronize လုပ်စေနိုင်သော ဖန်ရှင်ဖြစ်ပါသည်။ ထို့အတွက် Bind အကြောင်း မဖော်ပြခင် Property အား ပြီးခဲ့သော ဘလောဂ်ဖြင့် ဖော်ပြခဲ့ပါသည်။
public class Test {

    public static void main(String[] args) {
        IntegerProperty x = new SimpleIntegerProperty();
        IntegerProperty y = new SimpleIntegerProperty(0);
        
        x.bind(y);
        System.out.println(x.get()); // out value is 0

        y.set(10);
        System.out.println(x.get()); // out value is 10
        
        y.set(20);
        System.out.println(x.get()); // out value is 20
    }
}

အထက်ပါ ကုဒ်၏ စာကြောင်းနံပါတ် ၇ တွင် x variable အား y နှင့် bind လုပ်စေပါသည်။ ဤနည်းအားဖြင့် y တန်ဖိုးအားပြောင်းလည်းသည်နှင့် x တန်ဖိုးတွင်လည်း ပြောင်းလည်းသွားမည် ဖြစ်ပါသည်။

သို့သော်လည်း လက်တွေ့မှာမှု့  x ၏ တန်ဖိုးပြောင်းလည်းမှု့မှာ y နှင့် အချိန်တူမဟုတ်ပါ။ အနည်းငယ် နောက်ကျ၍ ပြောင်းလည်းမည် ဖြစ်ပါသည်။ x ၏ တန်ဖိုးအား ခေါ်ယူသည့်အခါတွင် x ၏ တန်ဖိုးအား ပြောင်းပေးမည် ဖြစ်ပါသည်။

အထက်ပါ ကုဒ်များ၏ စာကြောင်း ၁၀တွင် y ၏ တန်ဖိုးအား ၁၀ ဟုပြောင်းလည်းပါသည်။ သို့သော်လည်း x ၏ တန်ဖိုးသည် ဤနေရာတွင် ပြောင်းလည်းသွားသေးသည် မဟုတ်။ စာကြောင်း ၁၁အရောက် x ၏ တန်ဖိုးအား ခေါ်ဆိုသည့်အခါတွင် တန်ဖိုးပြောင်းလည်းသွားခြင်းပင် ဖြစ်၏။



IvalidationListener


ဤကဲ့သို့ Bind လုပ်ထားသော Variable ၏ တန်ဖိုးအား သိရှိစေနိုင်သည်မှာ javafx.beans.InvalidationListener Interface ပင် ဖြစ်၏။
public class Test {

    public static void main(String[] args) {
        IntegerProperty x = new SimpleIntegerProperty();
        IntegerProperty y = new SimpleIntegerProperty(0);
        
        x.bind(y);
        x.addListener(new InvalidationListener() {
            
            @Override
            public void invalidated(Observable o) {
                System.out.println("Invalidated : " + o);
            }
        });
        System.out.println(x.get()); 

        y.set(10);
        y.set(20);
        System.out.println(x.get()); 
    }
}
အထက် ပါ ကုဒ်များတွင် စာကြောင်းနံပါတ် ၈ တွင် x ၏ တန်ဖိုးပြောင်းလည်းပါက အလုပ်လုပ်နိုင်သည့် InvalidateListener အား ဖြည့်စွက် ရေးသားထားပါသည်။ ဤနည်းအားဖြင့် x ၏ တန်ဖိုး ပြောင်းလည်း သွားချိန်တွင် invalidate method အား ခေါ်ဆိုမည် ဖြစ်ပါသည်။

အဆိုပါ ပရိုဂရမ်အား Run ကြည့်သောအခါ အောက်ပါအတိုင်း အဖြေရရှိပါသည်။
0
Invalidated : IntegerProperty [bound, invalid]
20
ကုဒ်ထဲတွင် စာကြောင်း ၁၇ နှင့် ၁၈တို့တွင် y ၏ တန်ဖိုးအား ၂ကြိမ် ပြောင်းလည်းခဲ့သော်လည်း လက်တွေ့မှာမူ invalidate အား တစ်ကြိမ်သာ ခေါ်ဆိုသည်ကို တွေ့ရပါသည်။ စာကြောင်း ၁၉ အရောက်တွင် x.get အား ခေါ်ဆိုသည့်အခါတွင် invalidate အား တစ်ကြိမ်သာ ခေါ်ဆိုသောကြောင့် ဖြစ်ပါသည်။



Bind With UI Component


ကျွှန်တော်တို့  Bind Function အား UI Component များနှင့် တွဲပြီး နောက်ထပ်နမှုနာလေးတစ်ခု ရေးကြည့်ပါဦးမည်။

ပထမဦးဆုံး ScenBuilder အား အသုံးပြု၍ အောက်ပါ အတိုင်း Controller.fxml အား ရေးသားပါမည်။
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.*?>

<AnchorPane prefHeight="481.0" prefWidth="656.0"
    xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2"
    fx:controller="com.dtc.bind.Controller">
    <children>
        <Label layoutX="21.0" layoutY="24.0" text="Bind Tutorial"
            textOverrun="CENTER_ELLIPSIS">
            <effect>
                <DropShadow height="5.059523809523809" offsetX="2.0"
                    offsetY="4.0" radius="3.2946428571428568" spread="0.19841269841269843"
                    width="10.119047619047619" />
            </effect>
            <font>
                <Font name="Bleucher" size="30.0" />
            </font>
        </Label>
        <PieChart id="PieChart" fx:id="chart" labelsVisible="false"
            layoutX="21.0" layoutY="60.0" prefHeight="369.0" prefWidth="457.0"
            visible="true" />
        <Slider fx:id="slideB" layoutX="574.0" layoutY="66.0"
            orientation="VERTICAL" prefHeight="356.0" showTickLabels="true"
            showTickMarks="true" />
        <Slider fx:id="slideA" layoutX="508.0" layoutY="66.0"
            orientation="VERTICAL" prefHeight="356.0" showTickLabels="true"
            showTickMarks="true" />
        <Label layoutX="502.0" layoutY="434.0" text="Data A" />
        <Label layoutX="560.0" layoutY="434.0" text="Data B" />
    </children>
</AnchorPane>

အတွင်းတွင် ခေါင်းစဉ် Label ၃ခု၊ PieChart တစ်ခု နှင့် VerticalSlideBar နှစ်ခု အား ရေးသားထားပါသည်။ ပြီးပါက Controller.java အား ဆက်၍ရေသားပါမည်။
package com.dtc.bind;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Slider;
import javafx.stage.Stage;

public class Controller extends Application implements Initializable {

    @FXML
    private Slider slideA;
    @FXML
    private Slider slideB;
    @FXML
    private PieChart chart;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        
        chart.getData().addAll(new PieChart.Data("Data A", 0),
                new PieChart.Data("Data B", 0),
                new PieChart.Data("Data C", 20));
        
        slideA.valueProperty().set(30);
        slideB.valueProperty().set(10);;
        
        chart.getData().get(0).pieValueProperty().bind(slideA.valueProperty());
        chart.getData().get(1).pieValueProperty().bind(slideB.valueProperty());
    }

    @Override
    public void start(Stage stage) throws IOException {
        stage.setScene(new Scene((Parent) FXMLLoader.load(getClass()
                .getResource(getClass().getSimpleName() + ".fxml"))));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

အထက်ပါ ပရိုဂရမ်အတွင်းတွင် စာကြောင်း ၂၉ မှ ၃၁ အထိ PieChart ၏ Data များကို ဖြည့်စွက်နေပါသည်။ PieChart တွင် အသုံးပြုသော Data မှာ ObservableList ဖြစ်ပြီး ၎င်းအတွင်းတွင် PieChart.Data အား အသုံးပြုပြီး၊ Type Parameter အနေနှင့် String နှင့် Number အား အသုံးပြုပါသည်။ ထို့ကြောင့် စာကြောင်း ၂၉ တွင် PieChart#getData ဖြင့် ObservableList အား ခေါ်ယူ၍ ၎င်း၏ addAll function ဖြင့် အသုံးပြုမည့် Data များအား ဖြည့်စွက်နေပါသည်။ ဤနေရာသည် PieChart အတွက် Data များကို ပြင်ဆင်နေသည်သာ ဖြစ်၏။

Bind လုပ်နေသည်မှာ စာကြောင်း ၃၆ နှင့် ၃၇ ဖြစ်ပါသည်။ PieChart၏ Data အတွင်းမှ ပထမဦးဆုံး တန်ဖိုးအား Slider A ၏ တန်ဖိုးနှင့် Bind လုပ်ပြီး၊ ဒုတီယမြောက် Data ၏ တန်ဖိုးအား Slider B ၏ တန်ဖိုးနှင့် Bind လုပ်ထားပါသည်။ ဤနည်းအားဖြင့် Slider A ၏ တန်ဖိုး ပြောင်းလည်းသွားပါက၊ PieChart ၏ ပထမ တန်ဖိုးလည်း ပြောင်းလည်းမည်ဖြစ်ပြီး၊ Slider B ၏ တန်ဖိုးပြောင်းလည်းပါက PieChart ၏ ဒုတိယ တန်ဖိုးလည်း ပြောင်းလည်းမည် ဖြစ်ပါသည်။ လက်တွေ့ စမ်းကြည့်ပါမည်။


အထက်ဖော်ပြပါအတိုင်း Slider အား ရွှေ့ကြည့်သည်နှင့် PieChart အတွင်းရှိ တန်ဖိုးများလည်း ပြောင်းလည်းသွားသည်ကို တွေ့ရပါသည်။

ယခင်တစ်ခေါက် Property အား လေ့လာခဲ့စဉ်က User Input အပြင် Data ပြောင်းသွားတာကို သိနိုင်တဲ့ ထူးခြားချက်က ရှိခဲ့ပေမယ့်၊ Event ကို Catch လုပ်ပြီး ရေးနေရတဲ့အတွက် သိပ်ပြီး ထူးခြားတယ် လို့မထင်ခဲ့မိပါ။ သို့ရာတွင် ယခုတစ်ခေါက် Bind တွင်မှာမူ တကူးတက EventListener ကို ရေးထားစရာမလိုပဲ Bind လုပ်ထားရုံနဲ့ အခြားသော Variable တစ်ခုရဲ့ တန်ဖိုးနဲ့ တွဲပေးနိုင်တဲ့ အချက်ဟာ အတော်လေးကို ကွာခြားပါတယ်။

Ajax မှာတောင် Asynchronous ကို သုံးခဲ့ရင်တောင်မှ၊ အနည်းငယ်နောက်ကျပြီးအလုပ်လုပ်ပေမယ့် Java FX ရဲ့ Bind မှာတော့ အသုံးပြုသူက တစ်ခုခုလုပ်လိုက်တာနဲ့ Application က ချက်ချင်း တုံ့ပြန်နိုင်တာကို တွေ့ရပါတယ်။ Bind ဖန်ရှင်ကိုသုံးပြီး၊ User နဲ့ Interactive ဖြစ်တဲ့ Application တွေကို ရေးသားနိုင်လိမ့်မယ် လို့ မျှော်လင့်ပါတယ်။

ဆက်ပါဦးမည်
မင်းလွင်

No comments:

Post a Comment