Java 更新表中的数据时,选定行将被清除

Java 更新表中的数据时,选定行将被清除,java,javafx,tableview,Java,Javafx,Tableview,我已经在JavaFX中创建了一个TableView,并注意到当我选择一行时,一旦表中的项目得到更新,即存储在项目中的数据得到更新,选择就会被清除。我创建了一个可以从您的工作区运行的最小示例。在代码中,我有一个主类,它创建UI,向表中添加数据,然后生成一个随机字符串,用于根据表行的ID替换旧值。我还有Person类,它包含表视图的模型 我曾尝试存储所选行,然后在选择清除后再次选择它,但这并不是一个可行的解决方案,更像是一个黑客 主要类别: public class Main extends App

我已经在JavaFX中创建了一个TableView,并注意到当我选择一行时,一旦表中的项目得到更新,即存储在项目中的数据得到更新,选择就会被清除。我创建了一个可以从您的工作区运行的最小示例。在代码中,我有一个主类,它创建UI,向表中添加数据,然后生成一个随机字符串,用于根据表行的ID替换旧值。我还有Person类,它包含表视图的模型

我曾尝试存储所选行,然后在选择清除后再次选择它,但这并不是一个可行的解决方案,更像是一个黑客

主要类别:

public class Main extends Application
{

  private TableView<Person> table = new TableView<Person>();

  @Override
  public void start(Stage primaryStage) throws Exception
  {
    Scene scene = new Scene(new Group());
    primaryStage.setTitle("Table View Sample");
    primaryStage.setWidth(450);
    primaryStage.setHeight(500);

    final Label label = new Label("Address Book");
    label.setFont(new Font("Arial", 20));

    table.setEditable(true);

    TableColumn<Person, Integer> IDCol = new TableColumn<>("ID");
    IDCol.setMinWidth(100);
    IDCol.setCellValueFactory(new PropertyValueFactory<Person, Integer>("ID"));

    TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
    lastNameCol.setMinWidth(100);
    lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));

    table.getColumns().add(IDCol);
    table.getColumns().add(lastNameCol);

    final VBox vbox = new VBox();
    vbox.setSpacing(5);
    vbox.setPadding(new Insets(10, 0, 0, 10));
    vbox.getChildren().addAll(label, table);

    ((Group) scene.getRoot()).getChildren().addAll(vbox);

    primaryStage.setScene(scene);
    primaryStage.show();

    addDataToTable();
  }

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

  private void addDataToTable()
  {    
    //If the table has data in it, then we must check if the ID already exist, so that we can replace it.
    //else, we just add the items to the table in the first run.
    Runnable runnable = new Runnable()
    {

      @Override
      public void run()
      {
        while(true)
        {
          ObservableList<Person> data = generateData();
          try
          {
            Thread.sleep(2000);
          } catch (InterruptedException e)
          {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }

          if(table.getItems().size() > 0)
          {
            //first we cycle through the data in the generated list
            //then we cycle through the data in the table itself.
            //if the data is found, we replace it, and break from the loop.
            for(int i = 0; i < data.size(); i++)
            {
              for(int j = 0; j < table.getItems().size(); j++)
              {
                Person newPerson = data.get(i);
                Person currentPerson = table.getItems().get(j);

                if(newPerson.getID() == currentPerson.getID())
                {
                  final int J = j;
                  //now we replace it if it is the same
                  Platform.runLater(new Runnable()
                  {

                    @Override
                    public void run()
                    {
                      table.getItems().set(J, newPerson);
                    }
                  });

                  break;
                }
              }
            }
          }
          else
          {
            //When modifying the data on the table,w e do it on the platform thread, 
            //to avoid any concurrent modification exceptions.
            Platform.runLater(new Runnable()
            {

              @Override
              public void run()
              {
                table.getItems().addAll(data);
              }
            });
          }
        }
      }
    };

    Thread thread = new Thread(runnable);
    thread.setDaemon(true);
    thread.start();
  }

  private ObservableList<Person> generateData()
  {
    ObservableList<Person> values = FXCollections.observableArrayList();

    for(int i = 0; i < 100; i++)
    {
      Person oPerson = new Person(i, randomStringGeneerator());
      values.add(oPerson);
    }

    return values;
  }

  private String randomStringGeneerator()
  {
      String[] sample = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split("");
      String result = "";
      Random oRandom = new Random();

      int length = oRandom.nextInt(10) + 5;
      for(int i = 0 ; i < length; i++)
      {
        result += sample[oRandom.nextInt(sample.length)];
      }

      return result;
  }  
}

我所期望的是,即使在更新表行中的值之后,该行仍应保持选中状态。

因此,似乎有解决此问题的方法,与其说是尝试重新选择行,不如说是一种黑客行为。 替换:

与:


因此,设置属性的值,更新模型中的数据,然后我们只进行刷新,然后重新绘制UI。这不是最好的解决方案,但仍然是一个解决方案。

因此,似乎有一个解决方案可以解决这个问题,它比尝试重新选择行更简单。 替换:

与:


因此,设置属性的值,更新模型中的数据,然后我们只进行刷新,然后重新绘制UI。这不是最好的解决方案,但仍然是一个解决方案。

很好,您提供了一个,尽管M:)不需要线程,只需要一个更改所选项目的按钮。此外,这段代码似乎替换了所有人(至少是许多人),因此选择可能会混淆。也就是说:当涉及到数据修改时,所有具体的SelectionModel都有大量的bug。不幸的是,在替换项目时不保留所选索引只是其中之一。对此也没什么可做的:大多数bug都是在MultipleSelectModel中路由的,MultipleSelectModel是一个包私有的super…clear on replace包含在(针对多个模式报告,但也适用于单一选择)中感谢您的快速响应@kleopatra:)。我想知道这是否是Java中的一个bug。这是悲哀的,虽然,我没有看到它正在修复任何时间很快。我已经找到了一个解决方法,这比重新选择行更简单,我将在下面发布。很好,你提供了一个,虽然在M:)上有一些回旋余地,不需要线程,只需要一个更改所选项目的f.I.按钮。此外,这段代码似乎替换了所有人(至少是许多人),因此选择可能会混淆。也就是说:当涉及到数据修改时,所有具体的SelectionModel都有大量的bug。不幸的是,在替换项目时不保留所选索引只是其中之一。对此也没什么可做的:大多数bug都是在MultipleSelectModel中路由的,MultipleSelectModel是一个包私有的super…clear on replace包含在(针对多个模式报告,但也适用于单一选择)中感谢您的快速响应@kleopatra:)。我想知道这是否是Java中的一个bug。这是悲哀的,虽然,我没有看到它正在修复任何时间很快。我已经找到了一个解决方法,这比重新选择行更简单,我将在下面发布。如果数据设置正确,您不需要刷新。如果数据设置正确,您不需要刷新
public class Person
{
  private final SimpleIntegerProperty ID;
  private final SimpleStringProperty lastName;

  public Person(int ID, String lName)
  {
    this.ID = new SimpleIntegerProperty(ID);
    this.lastName = new SimpleStringProperty(lName);
  }

  public int getID()
  {
    return this.ID.get();
  }

  public void setID(int ID)
  {
    this.ID.set(ID);
  }

  public String getLastName()
  {
    return this.lastName.get();
  }

  public void setLastName(String lName)
  {
    this.lastName.set(lName);
  }

  @Override
  public String toString()
  {
    return "ID: " + ID + " value: " + lastName;
  }
}
table.getItems().set(J, newPerson);
table.getItems().get(J).setLastName(newPerson.getLastName());
table.refresh();