当前位置: 首页 > 知识库问答 >
问题:

JavaFX:如何在新场景中更新observableArrayList中的选定项。不传递整个支持它的数据集?

黄涵畅
2023-03-14

JavaFX:如何在新场景中更新observableArrayList中的选定项。不传递整个支持它的数据集?

我认为只要把一个选定的项传递到新窗口就有意义了。通过这样做,我无法让observableArrayList反映更改。

我只能通过传入整个数据集来使我的程序工作。ArrayList支持observableArrayList和observableArrayList本身。然后在ArrayList中查找元素,修改元素,将元素重新插入到列表中,然后清除整个ArrayList并将其重新添加到ObservabLearRayList。我肯定这不是最好的办法。作为Javafx的新手,我不知道如何使其工作。

目录结构。

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


  }
}
<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>
<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个答案

艾宏远
2023-03-14

你在编辑一个项目。你不应该为此列出清单。stage.showandwait允许您等待用户完成输入并对其做出反应,我强烈建议您这样做。

除此之外,我还重新评论了几件事情:

>

  • 对按钮单击使用onaction事件,而不是onmouseclicked事件。这样,当按钮聚焦时,您还可以对按下Enter键做出反应,并防止用主按钮以外的鼠标按钮单击触发该按钮。
  • 立即使用selecteditem而不是选定的单元格。这两个是独立的,检查null并不比在某个列表上调用isempty()更难。
  • 不提供对场景节点的直接访问。这只会将处理节点的责任分散到多个类中,使代码更难维护。此外,例如,valuetxtfld属性的setter使代码更加混乱,因为您可能最终得到一个textfield,而不是场景的一部分:您可能传递一个与getvaluetxtfld返回的getvaluetxtfld不同的如果您只提供对正在使用的属性(textfield.text属性)的访问,这就不成问题了。在这种情况下,不需要访问。
  • 在遍历列表时不要修改列表。您可能会获得ConcurrentModificationException。也不要用比较哈希代码来代替相等性检查。这比必要的要复杂得多,而且可能会失败。(假设hashcode实现仅基于string值,那么每个可能的int都有一个字符串,而且有些字符串不包含int值,因此必须有两个不同的对象具有相同的hashcode).
    只需使用indexof:

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

    main.fxml

    xml prettyprint-override"><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();
        }
    
    }
    

  •  类似资料:
    • 对我如何做到这一点有什么建议吗? 这是我到目前为止编写的代码,但它似乎忽略了Thread.Sleep并且只使第三个代码变为蓝色。

    • 问题内容: 我正在尝试学习JavaFX,并将swing应用程序转换为JavaFX。我想做的是使用JavaFX来显示程序的进度。 我以前在Swing中所做的是首先使用自定义JComponent创建一个JFrame。然后让我的主程序调用自定义JComponent的方法,该方法将更改JComponent和repaint()中的形状颜色。 下面给出了我想在JavaFX中实现的目标的想法: 我目前将此作为我

    • 我是JavaFX的新手。我试图编程一个简单的图形用户界面,但我面临着那些可能相关的问题。我用文件选择器设置文件,并想做相当基本的操作: 保存最后使用的文件夹 在VBox中写入选中文件的名称 这是我的代码(编译): 我无法刷新节点以设置当前初始目录或在VBox上显示collecName。我试图通过重新加载对象或调整窗口大小来重新生成它们,但没有任何效果。当我在控制台上打印变量时,我看到它们发生了变化

    • 我有一个登录页面,我正在尝试获得一个用户的电子邮件,他们输入显示在下一个页面,这是他们的主页。这是代码: 这是我试图调用的方法: 我没有错误,只是没有更新nameLbl,我不知道为什么。logincontroller将成功地进入仪表板,它只是不会更新namelBL。 这两个都是完整的代码。 登录控制器: 仪表板控制器: 似乎我的方法在仪表板控制器从来没有被调用,为什么?事先谢谢你的帮助。

    • 我基本上是Java FX 2的新手。 场景: 我有3个场景,我想要一种添加菜单栏的方法,这样我就不想显式地从以前的场景中删除菜单栏并将其添加到新的场景中。例如,父场景或菜单栏以某种方式附加到舞台。我的意思是菜单栏只添加了一次,无论前面有没有场景,它都会一直出现。 如果这是可能的,我该怎么做? 以下是 Oracle 文档提供的 JavaFX http://docs.oracle.com/javafx