4

私は、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>
4

1 に答える 1

5

問題1-有名なJavaオートボクシングトラップの1つに足を踏み入れました。

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);
        }
    });

メッセージクラスを更新します。TableViewを正しく機能させるには、完全なFX「bean」であり、メソッドを介してプロパティを公開する必要があります。

public StringProperty messageNameProperty() {
    return messageName;
}
于 2012-06-13T14:47:34.420 に答える