FXML、カスタムコントロールへのパラメータの渡し方

####　SceneBuilderを使うとカスタムコントロールへパラメータが渡せない。
(JavaFX+FXML+SceneBuilderでの勉強メモ)

JavaFX+FXML+SceneBuilderで名前と値の表示付きSliderを作ったが、SeneBuilderがコンストラクタはパラメータ無しでしか扱ってくれない？？

色々例を探しても見つからなかったので
AccessibleTextを利用してSeneBluiderから初期値を渡す方法を試して見た。

#### AccessibleText
本家のサイトを見ても良く使い方が分からない
VBoxに存在してユーザが使えそうなプロパティがこれ
ただしFXMLLoaderに*.fmxlファイルが読み込まれた時点では値が設定されておらず、start()やInitialize（）の時点でも同じだったためChangeListenerをaddしてパラメータを受けてその値を各コントローラーにセットした。

```java:MySlider.java

package CustomComponent;



import java.io.IOException;

import MyEvent.MyEvent;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;

/*
 *  Custom Slider with NameLabel and ValueLabel
 */


public class MySlider extends VBox  {
	
    @FXML private Label nameLabel;
    @FXML private Label valueLabel;
    @FXML private Slider slider;

	
    public MySlider() {
    	super();
    	FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("my_slider.fxml"));
    	fxmlLoader.setRoot(this);
    	fxmlLoader.setController(this);
        
        try {
            fxmlLoader.load();            
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }  

        /* accessibleTextに値が設定されたらパラメータを読みに行く */
        this.accessibleTextProperty().addListener(accessibleTextListener);

        /* sliderの値が変化した場合 */
        slider.valueProperty().addListener((
        	ObservableValue<? extends Number> ov,Number old_val,
    		Number new_val) ->{
    			sliderChangeValue();
    	}); 	  
        
        
    }
    
    
    /* パラメータの処理     "name,min,max,val"   */
	 ChangeListener<String> accessibleTextListener = new ChangeListener<String>() {
		@Override 
		public void changed(ObservableValue<?extends String>observable,String oldValue,String newValue) {
			String data[] = newValue.split(",");
			System.out.println(data[0]);
		   	nameLabel.setText( data[0]);
		   	int i = data.length;
		   	if((i > 1) && (i <= 4)){
		   		slider.setMin(Double.parseDouble(data[1]));
		   		slider.setMax(Double.parseDouble(data[2]));
		   		Double val = Double.parseDouble(data[3]);
		  		slider.setValue(val);
		   	}
		}	
	};
 

    protected void sliderChangeValue() {
    	int i = 0;

    	i = (int) slider.getValue();
    	valueLabel.setText(i + "");
    	Event myEvent = new MyEvent(MyEvent.CHANGE_VALUE,i);
    	Node node = this;
    	node.fireEvent(myEvent);

    }
 	
    	   
 	public void initialize() {
	    	
    }

        
    public void setLabelName(String name) {
    	nameLabel.setText(name);
    }
    
    public void setValue(Double val) {
    	slider.setValue( val);
    }

    public Double getValue() {
    	return slider.getValue();
    }
}

```
```xml:my_slider.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.VBox?>
<fx:root  type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
         <Label fx:id="nameLabel" contentDisplay="CENTER" layoutY="6.0"  textAlignment="CENTER" />
         <Label fx:id="valueLabel" contentDisplay="CENTER" layoutY="23.0" prefHeight="10.0" prefWidth="31.0" text="0" textAlignment="CENTER" />
         <Slider fx:id="slider" blockIncrement="1.0" layoutX="7.0" layoutY="47.0" max="31.0"  orientation="VERTICAL">
            <cursor>
               <Cursor fx:constant="DEFAULT" />
            </cursor>
         </Slider>
</fx:root>
```

上記のカスタムコントロールをimportしてSceneBuilderで構築したfxmlファイル
AccessibleText="name,val1,val2,val3"のフォーマットでMySliderへの初期値を渡す。

```xml
<?xml version="1.0" encoding="UTF-8"?>

<?import CustomComponent.MySlider?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.TestFXML5Controller">
   <Pane prefHeight="534.0" prefWidth="299.0">
      <children>
          <Label text="CustomSlider Test" />

         <MySlider fx:id="sliderAtk" AccessibleText="Atk,1,15,2" accessibleText="Atk,0,15,0" layoutX="19.0" layoutY="95.0" prefHeight="175.0" prefWidth="30.0" />
         <MySlider fx:id="sliderDec" AccessibleText="Dec,0,50,25" accessibleText="Dec,0,15,0" layoutX="44.0" layoutY="95.0" />
         <MySlider fx:id="sliderSus" AccessibleText="Sus" accessibleText="SR,0,15,0" layoutX="75.0" layoutY="95.0" />
         <Label fx:id="valueLabel" layoutX="19.0" layoutY="51.0" prefHeight="17.0" prefWidth="56.0" text="0" />
         <MySlider fx:id="sliderSl" accessibleText="SL,0,15,0" layoutX="104.0" layoutY="95.0" />
         <MySlider fx:id="sliderRel" accessibleText="Rel,0,15,0" layoutX="134.0" layoutY="95.0" />
         <MySlider fx:id="sliderMul" accessibleText="Mul,0,15,0" layoutX="165.0" layoutY="95.0" />
         <MySlider fx:id="sliderDT" accessibleText="DT,0,7,0" layoutX="196.0" layoutY="95.0" prefHeight="97.0" prefWidth="31.0" />
         <MySlider fx:id="sliderTLV" accessibleText="TLV,0,63,0" layoutX="18.0" layoutY="290.0" />
         <MySlider fx:id="sliderKSL" accessibleText="KSL,0,3,0" layoutX="53.0" layoutY="291.0" prefHeight="97.0" prefWidth="31.0" />
         <MySlider fx:id="sliderDAM" accessibleText="DAM,0,3,0" layoutX="101.0" layoutY="385.0" prefHeight="90.0" prefWidth="38.0" />
         <MySlider fx:id="sliderDVB" accessibleText="DVB,0,3,0" layoutX="148.0" layoutY="385.0" prefHeight="90.0" prefWidth="38.0" />
         <ComboBox layoutX="181.0" layoutY="290.0" prefHeight="32.0" prefWidth="107.0" />
         <RadioButton fx:id="ksrRadioButton" layoutX="14.0" layoutY="475.0" mnemonicParsing="false" onAction="#ksrSelect" text="KSR" />
         <RadioButton layoutX="14.0" layoutY="502.0" mnemonicParsing="false" onAction="#xofSelect" text="XOF" fx:id="xofRadioButton" />
         <RadioButton fx:id="eamRadioButton" layoutX="86.0" layoutY="340.0" mnemonicParsing="false" onAction="#eamSelect" text="EAM" />
         <RadioButton fx:id="evbRadioButton" layoutX="196.0" layoutY="349.0" mnemonicParsing="false" onAction="#evbSelect" text="EVB" />
      </children>
   </Pane>
	
</VBox>
```
編集中の様子、カスタムコントロールを並べまくってAccessibleTextで初期値を与える。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205783/faa184e9-8c96-a44c-ae3e-71d767ec9a2e.png" width=90%>


実行時、initialize()で設定した値は上書きされました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205783/b4c0fffc-3caf-b789-f2cc-9f49c647e4e6.png" width=50%>

#### まとめ
勉強中に思いついた方法を試したもので的外れな事かもしれないが
画面構築はxmlに、処理等はControllerに集約できるのでソースが見やすくなると思う。