我正在MacOSX上使用java 1.7.0_04-b21在JavaFx 2.1中使用简单绑定开发一个小应用程序。实际上我目前比较了Mac OSX上Cocoa与JavaFx的绑定机制,并面临几个问题:
应用程序使用一个包含observableArrayList(名为messageList)的模型,该模型被设置为TableView的项目。添加新条目到列表工作。该条目出现在TableView中。
问题1:删除所选项目不起作用。当我从可观察列表中删除项目时,它不会消失。
问题2:我想用textView填充一个textField,该值存储在TableView中选中的对象的一个字段中。 实际上,在Cocoa中,可以定义对选择的绑定,即使在绑定定义的时间点它是空的(因此没有选择任何内容)。这实际上是一个非常有用的概念,我没有发现在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);
}
}
Message.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);
}
}
Model.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>
答案 0 :(得分:5)
第1期 - 您进入了一个着名的Java自动装箱陷阱。
model.getMessageList().remove(selectedIndices2.get(i)); // get(i) returns Integer
按预期调用List.remove(Object o)
而不是List.remove(int idx)
。
使用
model.getMessageList().remove(selectedIndices2.get(i).intValue());
代替。
发布2-3
只需将监听器附加到selectedItem
并在更改时重新绑定:
messageListTableView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Message>() {
@Override
public void changed(ObservableValue<? extends Message> ov, Message old, Message newM) {
messageNameTextField.textProperty().unbindBidirectional(old.messageName);
messageNameTextField.textProperty().bindBidirectional(newM.messageName);
}
});
并更新您的Message类。要正确使用TableView,它需要是完整的FX“bean”并通过方法公开属性:
public StringProperty messageNameProperty() {
return messageName;
}