JavaFX:如何在新场景中更新 observableArrayList 中选定的项目。没有传递整组数据支持吗?

标签 java javafx

JavaFX:如何在新场景中更新 observableArrayList 中选定的项目。没有传递整组数据支持吗?

我认为将一个选定的项目传递到新窗口是有意义的。我无法通过这样做让 observableArrayList 反射(reflect)更改。

我只能通过传递整个数据集来让我的程序运行。支持 observableArrayList 的 ArrayList 和 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();


  }
}

ma​​in.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>

修改.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>

最佳答案

您正在编辑单个项目。由于这个原因,您不应该列出 list 。 Stage.showAndWait 允许您等待用户完成输入并对其使用react,我强烈建议您这样做。

除此之外,我还建议更改以下几项内容:

  • 对按钮点击使用 onAction 事件,而不是 onMouseClicked 事件。这样,当按钮获得焦点时,您还可以对按 Enter 键使用react,并防止使用主按钮以外的鼠标按钮进行点击来触发该按钮。
  • 立即使用selectedItem而不是选定的单元格。这两个是独立的东西,检查 null 并不比在某个列表上调用 isEmpty() 更难。
  • 不提供对场景节点的直接访问。这只会将处理节点的责任分散到多个类中,从而使代码更难以维护。此外例如valueTxtFld 属性的 setter 使代码更加困惑,因为您最终可能会得到一个不属于场景的 TextField:您可以传递不同的 TextFieldgetValueTxtFld 返回到 setValueTxtFld 导致的错误不是最简单的调试错误。如果您只是提供对正在使用的属性(TextField.text 属性)的访问权限,那么这不会成为问题。但在这种情况下,不需要访问权限。
  • 迭代列表时不要修改列表。您可能会收到 ConcurrentModificationException。也不要用比较哈希码来代替检查相等性。这比必要的更复杂并且可能会失败。 (假设您的 hashCode 实现仅基于 String 值,则每个可能的 int 都有一个字符串,并且有些字符串不包含int 值,因此必须有 2 个不同的对象具有相同的哈希码)。
    只需使用 indexOf 即可:

    int index = values.indexOf(data);
    values.set(index, ...);
    
<小时/>

ma​​in.fxml

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

修改.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();
    }

}

关于JavaFX:如何在新场景中更新 observableArrayList 中选定的项目。没有传递整组数据支持吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55701298/

相关文章:

java - JPanel 未在 JFrame 中显示

java - 编译器错误: Method cant be applied to types(Factorial Program)

java - getAssets 无法在 Android Studio 中工作,但可以在 Eclipse 中工作

java - 装饰 ObservableList 并保留更改事件的最佳实践

JavaFx CheckBoxTreeItem<Path> 选择根项错误

javafx - 使用 PropertyEditor (ControlsFX) 的属性表示例

java - 在 jetty 热部署简单的应用程序

java - 通过 linux shell 进行 XSLT 2.0 转换

javafx - 如何让 JavaFX 判断我是在 4k 还是 1080p 屏幕上

java - Guava 事件总线 : NullPointerException when Posting from Thread to UI