我正在使用 JavaFx 2.1 中的简单绑定在 MacOSX 上使用 java 1.7.0_04-b21 开发一个小型应用程序。实际上,我目前将 Mac OSX 上 Cocoa 的绑定机制与 JavaFx 进行比较,并面临几个问题:
该应用程序使用一个模型来保存一个 observableArrayList(称为 messageList),它被设置为 TableView 的项目。向列表中添加新条目有效。该条目出现在 TableView 中。
问题 1:删除所选项目不起作用。当我从可观察列表中删除一个项目时,它不会消失。
问题 2:我想用存储在 TableView 中选择的对象的一个字段中的值填充 textField。实际上,在 Cocoa 中,即使在绑定定义的时间点 this 为空(因此没有选择任何内容),也可以定义对选择的绑定。这实际上是一个非常有用的概念,我没有发现这在 JavaFX 中是如何实现的。
问题 3:只有当已经选择了一个对象时,才能建立绑定,以便我最终编写了一个 EventHandler 对不断变化的选择做出反应,并始终重新建立我的文本字段与模型字段的正确绑定。但是对于这种方法,我的应用程序出于某种我现在不明白的原因破坏了模型。
只需单击添加按钮三四次,然后选择条目并查看 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>