JavaFX: Как обновить выбранный элемент из observableArrayList в новой сцене.Не передавая во всем наборе данных, подтверждающих это? - PullRequest
1 голос
/ 16 апреля 2019

JavaFX: как обновить выбранный элемент из observableArrayList в новой сцене. Не передавая во всем наборе данных, подтверждающих это?

Я думаю, что имеет смысл просто передать один выбранный элемент в новое окно. Я не могу получить observableArrayList для отражения изменений, делая это.

Мне удалось заставить мою программу работать только путем передачи всего набора данных. И ArrayList, поддерживающий observableArrayList, и observableArrayList сами по себе. Затем найдите элемент в ArrayList, измените элемент, повторно вставьте элемент обратно в список, а затем очистите и повторно добавьте весь ArrayList в observableArrayList. Я уверен, что это не лучший способ сделать это. Будучи новичком в Javafx, я не уверен, как заставить это работать.

Вот рабочий пример того, как я достиг этого, чтобы работать. Надеюсь, это подчеркивает, что я делаю неправильно и что мне нужно изменить.

Обратите внимание: Я не хочу использовать статические классы, если это возможно. Это небольшой проект, который я планирую распространить на более крупный проект, и я хочу избежать ловушек при использовании статических классов.

Обратите внимание: Я не публикую импорт сообщений. Предположим, у меня есть правильный импорт.

Визуальная ссылка на мой пример кода Visual example of my working example,

Структура каталогов.

    --example
           main.fxml
           Main.java
           MainController.java
           modify.fxml
           ModifyController.java
           myData.java

Main.java

    public class Main extends Application {  
    @Override
    public void start(Stage primaryStage) throws Exception {

      ArrayList<myData> values = new ArrayList<>();
      values.add(new myData("1"));
      values.add(new myData("2"));
      values.add(new myData("3"));

      FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
      Parent root = loader.load();
      MainController myController = loader.getController();
      myController.initialize(values);
      primaryStage.setTitle("Hello World");
      Scene mainScene = new Scene(root);
      primaryStage.setScene(mainScene);
      myController.setMainStage(primaryStage);
      primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
      }
    }

MainController.java

    public class MainController {    
    @FXML
    private Button modifyButton;
    @FXML
    private TableView<myData> valueTable;
    @FXML
    private TableColumn valueCell;    

    private ObservableList<myData> observableDataModels;
    private ArrayList<myData> values;
    private Stage primaryStage;    

    public void initialize(ArrayList<myData> values) {
    this.values = values;
    this.observableDataModels = FXCollections.observableArrayList(values);
    this.valueCell.setCellValueFactory(new PropertyValueFactory<>("value"));
    this.valueTable.setItems(observableDataModels);
    }    

    public void setMainStage(Stage primaryStage) {
    this.primaryStage = primaryStage;
    }    

    public void onMouseClicked(MouseEvent mouseEvent) throws IOException {    

    if (!this.valueTable.getSelectionModel().getSelectedCells().isEmpty()) {
      myData selectedItem = this.valueTable.getSelectionModel().getSelectedItem();    

      FXMLLoader loader = new FXMLLoader(getClass().getResource("modify.fxml"));
      Parent root = loader.load();
      ModifyController mpc = loader.getController();
      mpc.setData(selectedItem);
      mpc.setObservableDataModels(this.observableDataModels);
      mpc.setValues(this.values);
      TextField t = mpc.getValueTxtFld();
      t.setText(selectedItem.getValue());
      mpc.setValueTxtFld(t);
      Stage modifyStage = new Stage();
      Scene modfifyPartScene = new Scene(root);
      modifyStage.setScene(modfifyPartScene);
      mpc.setCurrStage(modifyStage);
      modifyStage.show();
          }
        }
      }

ModifyController.java

public class ModifyController {

  @FXML
  private TextField valueTxtFld;
  @FXML
  private Button mdfSaveBtn;
  @FXML
  private Stage currStage;
  private myData data;
  private ObservableList<myData> observableDataModels;
  private ArrayList<myData> values;

  public void setObservableDataModels(
      ObservableList<myData> observableDataModels) {
    this.observableDataModels = observableDataModels;
  }

  public ArrayList<myData> getValues() {
    return values;
  }

  public void setValues(ArrayList<myData> values) {
    this.values = values;
  }

  public TextField getValueTxtFld() {
    return valueTxtFld;
  }

  public void setValueTxtFld(TextField valueTxtFld) {
    this.valueTxtFld = valueTxtFld;
  }

  public void setData(myData selectedItem) {
    this.data = selectedItem;
  }

  public void setCurrStage(Stage modifyStage) {
    this.currStage = modifyStage;
  }

  public void onMouseClicked(MouseEvent mouseEvent) {

    myData dataBuffer = this.data;
    int i = dataBuffer.hashCode();
    this.data.setValue(this.valueTxtFld.getText());

    int count = 0;
    for (myData d : values) {
      if (i == d.hashCode()) {
        values.remove(count);
        values.set(count, this.data);
      } else {
        count += 1;
      }
    }

    observableDataModels.removeAll(values);
    observableDataModels.addAll(values);
    this.currStage.close();


  }
}

main.fxml

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="example.ModifyController">
   <children>
      <TextField fx:id="valueTxtFld" layoutX="193.0" layoutY="169.0" />
      <Button fx:id="mdfSaveBtn" layoutX="261.0" layoutY="219.0" mnemonicParsing="false" onMouseClicked="#onMouseClicked" text="Save" />
   </children>
</AnchorPane>

1053 ** * modify.fxml 1054 ** * 1055

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="example.ModifyController">
   <children>
      <TextField fx:id="valueTxtFld" layoutX="193.0" layoutY="169.0" />
      <Button fx:id="mdfSaveBtn" layoutX="261.0" layoutY="219.0" mnemonicParsing="false" onMouseClicked="#onMouseClicked" text="Save" />
   </children>
</AnchorPane>

1 Ответ

2 голосов
/ 16 апреля 2019

Вы редактируете один элемент.Вы не должны список по этой причине.Stage.showAndWait позволяет подождать, пока пользователь завершит ввод и отреагирует на него, что я настоятельно рекомендую сделать.

В дополнение к этому я рекомендую изменить несколько вещей:

  • Используйте onAction события для нажатия кнопок вместо onMouseClicked событий.Таким образом, вы также будете реагировать на нажатие клавиши Enter , когда кнопка находится в фокусе, и предотвращает срабатывание кнопки при нажатии кнопок мыши, кроме основной.
  • Использование selectedItemсразу вместо выбранных ячеек.Эти 2 являются независимыми вещами, и проверка для null на самом деле не сложнее, чем вызов isEmpty() в некотором списке.
  • Не предоставляйте прямой доступ к узлам сцены.Это просто распределяет ответственность за обработку узлов по нескольким классам, делая код сложнее в обслуживании.Более того, например, установщик для свойства valueTxtFld делает код еще более запутанным, поскольку вы можете получить TextField, который не является частью сцены: вы можете передать TextField, отличный от того, который возвращает getValueTxtFldsetValueTxtFld, что приводит к ошибке, которая не является самой простой для отладки.Если вы просто предоставите доступ к свойству, которое вы используете (свойство TextField.text), это не будет проблемой.Однако в этом случае доступ не требуется.
  • Не изменяйте список во время его итерации.Вы можете получить ConcurrentModificationException.Также не заменяйте сравнение хеш-кодов проверкой на равенство.Это сложнее, чем необходимо, и может не получиться.(Предполагая, что ваша реализация hashCode основана только на значении String, есть строка для каждого возможного int, и есть строки, которые не содержат значений int, поэтому должно быть 2 разных объекта с одинаковым хеш-кодом).
    Просто используйте indexOf вместо:

    int index = values.indexOf(data);
    values.set(index, ...);
    

main.fxml

<Button fx:id="mdfSaveBtn" layoutX="261.0" layoutY="219.0" mnemonicParsing="false" onAction="#modify" text="Save" />

modify.fxml

<Button fx:id="mdfSaveBtn" layoutX="261.0" layoutY="219.0" mnemonicParsing="false" onAction="#save" text="Save" />
public class MainController {    
    ...

   // you can leave out the event parameter here, if you don't need it;
   // otherwise be sure to use a parameter of type ActionEvent    
    @FXML
    private void modify() throws IOException {
        myData data = valueTable.getSelectionModel().getSelectedItem();
        if (data != null) {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("modify.fxml"));
            Parent root = loader.load();
            ModifyController mpc = loader.getController();
            mpc.setData(data);
            Stage modifyStage = new Stage();
            Scene modfifyPartScene = new Scene(root);
            modifyStage.setScene(modfifyPartScene);
            modifyStage.showAndWait();
            if (mpc.isEdited()) {
                valueTable.refresh(); // or update the table by other means
            }
        }
    }
}
public class ModifyController {

    @FXML
    private TextField valueTxtFld;
    @FXML
    private Button mdfSaveBtn;

    private myData data;

    // flag indicating, if the edit was submitted or not
    private boolean edited;

    public boolean isEdited() {
        return edited;
    }

    public void setData(myData selectedItem) {
        if (selectedItem == null) {
            throw new IllegalArgumentException();
        }
        this.data = selectedItem;
        valueTxtFld.setText(selectedItem.getValue());
        edited = false;
    }

    public void save() {
        data.setValue(valueTxtFld.getText());
        edited = true;
        mdfSaveBtn.getScene().getWindow().hide();
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...