私は、MacOSX で Java 1.7.0_04-b21 を使用して、JavaFx 2.1 で単純なバインディングを使用する小さなアプリケーションに取り組んでいました。実際、私は現在、Mac OSX 上の Cocoa のバインド メカニズムを JavaFx と比較しており、いくつかの問題に直面しています。
アプリケーションは、TableView の項目として設定された observableArrayList (messageList と呼ばれる) を保持するモデルを使用します。リストに新しいエントリを追加すると機能します。エントリが TableView に表示されます。
問題 1:選択したアイテムを削除しても機能しません。監視可能なリストからアイテムを削除しても、消えません。
問題 2: TableView で選択されているオブジェクトの 1 つのフィールドに格納されている値を textField に入力したいと考えています。実際、Cocoa では、バインディングの定義の時点でこれが空 (何も選択されていない) であっても、セレクションへのバインディングを定義できます。これは実際には非常に便利な概念であり、これが JavaFX でどのように可能になるかわかりませんでした。
問題 3:オブジェクトが既に選択されている場合にのみバインディングを確立できるため、選択の変更に反応する EventHandler を最終的に記述し、テキスト フィールドとモデル フィールドの正しいバインディングを常に再確立します。しかし、このアプローチでも、私のアプリケーションは、今では理解できない何らかの理由でモデルを破壊します。
追加ボタンを 3 回または 4 回クリックするだけで、エントリを選択して textField の更新を確認できます。モデル内のデータは破壊されて上書きされます - そしてエントリは通常短くなります... 効果の説明は大歓迎です。
これまで、TableView でバインディングの例を見つけることができなかったので、どんな入力でも大歓迎です。
私のデモ プロジェクトのコードは、次のファイルに含まれています。すべてが同じパッケージ com.es.javaFxTest にあります。
MainWindowController.java:
/*
* Created on 19.05.2012
*/
package com.es.javaFxTest;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
public class MainWindowController implements Initializable
{
public Model model;
public TableView<Message> messageListTableView;
public TableColumn<Message, String> messageTableMessageNameColumn;
public Button addMessageButton;
public Button deleteMessageButton;
public TextField messageNameTextField;
public SimpleObjectProperty<Message> selectedMessage;
/* (non-Javadoc)
* @see javafx.fxml.Initializable#initialize(java.net.URL, java.util.ResourceBundle)
*/
@Override
public void initialize(URL arg0, ResourceBundle arg1)
{
model = new Model();
messageTableMessageNameColumn.setCellValueFactory(new PropertyValueFactory<Message, String>("messageName"));
messageListTableView.setItems(model.getMessageList());
addMessageButton.setOnAction(new EventHandler<ActionEvent>() {
StringBuffer str = new StringBuffer("a"); // to fill some dummy data
@Override
public void handle(ActionEvent e)
{
// adding an object to the observed list works and the result is shown in the tableView
model.getMessageList().add(new Message(str.toString()));
str.append("x");
}
});
deleteMessageButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event)
{ // observation does not work here; also the following code does not work.
ObservableList<Integer> selectedIndices = messageListTableView.getSelectionModel().getSelectedIndices();
ArrayList<Integer> selectedIndices2 = new ArrayList<Integer>(selectedIndices);
Collections.sort(selectedIndices2);
for (int i = selectedIndices2.size() - 1; i >= 0; i--)
{
model.getMessageList().remove(selectedIndices2.get(i));
}
}
});
selectedMessage = new SimpleObjectProperty<Message>();
selectedMessage.bind(messageListTableView.getSelectionModel().selectedItemProperty());
selectedMessage.addListener(new ChangeListener<Message>() {
@Override
public void changed(ObservableValue< ? extends Message> observable, Message oldValue, Message newValue)
{
System.out.format("ObservableValue %s, \n oldValue %s\n newValue %s\n\n", observable, oldValue, newValue);
if (oldValue != null)
{
messageNameTextField.textProperty().unbind();
oldValue.messageName.unbind();
}
if (newValue != null)
{
messageNameTextField.textProperty().set(newValue.getMessageName());
newValue.messageName.bindBidirectional(messageNameTextField.textProperty());
}
}
});
}
}
MainWindowLayout.java
package com.es.javaFxTest;
/*
* Created on 18.05.2012
*/
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class MainWindowLayout extends Application
{
@Override
public void start(Stage stage)
{
try
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainWindowLayout.fxml"));
Pane root = (Pane) fxmlLoader.load();
MainWindowController controller = (MainWindowController) fxmlLoader.getController();
Scene scene = new Scene(root);
stage.setTitle("Config");
stage.setScene(scene);
stage.show();
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
}
メッセージ.java
/*
* Created on 19.05.2012
*
*/
package com.es.javaFxTest;
import javafx.beans.property.SimpleStringProperty;
public class Message
{
/**
* @param canId
* @param messageName
*/
public Message(String messageName)
{
this.messageName = new SimpleStringProperty(messageName);
}
SimpleStringProperty messageName;
/**
* @return the messageName
*/
public String getMessageName()
{
return messageName.getValue();
}
/**
* @param messageName the messageName to set
*/
public void setMessageName(String messageName)
{
this.messageName.set(messageName);
}
public String toString ()
{
return String.format("Name:%s",messageName);
}
}
モデル.java
/*
* Created on 20.05.2012
*/
package com.es.javaFxTest;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Model
{
ObservableList<Message> messageList;
SimpleListProperty<Message> messageListProperty;
public Model()
{
messageList = FXCollections.observableArrayList();
messageListProperty = new SimpleListProperty<Message>(this,"messageList",messageList);
}
public final SimpleListProperty<Message> messageListProperty()
{
return messageListProperty;
}
public ObservableList<Message> getMessageList()
{
return messageListProperty.get();
}
public void setMessageList(ObservableList<Message> l)
{
messageListProperty.set(l);
}
}
MainWindowLayout.xml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.collections.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml" fx:controller="com.es.javaFxTest.MainWindowController">
<children>
<SplitPane id="splitPaneHorizontal1" dividerPositions="0.3614457831325301" focusTraversable="true" prefHeight="600.0" prefWidth="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane id="anchorPane1" minHeight="0.0" minWidth="0.0" prefHeight="598.0" prefWidth="390.0">
<children>
<VBox id="VBox" alignment="CENTER" prefHeight="598.0" prefWidth="177.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TableView id="tableView1" fx:id="messageListTableView" editable="true" prefHeight="598.0" prefWidth="406.0">
<columns>
<TableColumn prefWidth="75.0" text="Name" fx:id="messageTableMessageNameColumn" />
</columns>
</TableView>
<HBox id="HBox" alignment="CENTER" spacing="5.0">
<children>
<Button id="button2" fx:id="addMessageButton" text="Add">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
<Button id="button1" fx:id="deleteMessageButton" text="Delete">
<HBox.margin>
<Insets bottom="5.0" right="5.0" top="5.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
<AnchorPane id="anchorPane2" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<HBox id="HBox" alignment="CENTER" layoutX="44.0" layoutY="177.0" spacing="5.0">
<children>
<Label id="label2" text="Name:" />
<TextField id="textField2" fx:id="messageNameTextField" prefWidth="200.0" text="TextField" />
</children>
</HBox>
</children>
</AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>