【发布时间】:2019-11-23 20:13:11
【问题描述】:
我在 JavaFX 中创建了一个 TableView,并注意到当我选择一行时,一旦表中的项目更新,即存储在项目中的数据得到更新,选择就会被清除。我创建了一个可以从您的工作区运行的最小示例。在代码中,我有 Main 类,它创建 UI,将数据添加到表中,然后生成一个随机字符串,用于根据表行的 ID 替换旧值。我还有包含表格视图模型的 Person 类。
我已尝试存储选定的行,然后在选择清除后再次选择它,但这感觉不是一个可行的解决方案,而更像是一个 hack。
主类:
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;
}
}
Person 类:
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;
}
}
我期望该行应该保持选中状态,即使在更新表行中的值之后也是如此。
【问题讨论】:
-
很高兴您提供了minimal reproducible example,尽管在 M 上有一些余地:) 不需要线程,只需 f.i.更改所选项目的按钮。此外,看起来这段代码似乎替换了所有(至少很多人),所以选择可能会混淆。也就是说:在修改数据时,所有具体的 selectionModel 都存在大量错误。不幸的是,在替换项目时不保留所选索引只是其中之一。没什么可做的:大多数错误都在 MultipleSelectionModel 中路由,这是一个包私有的超级...
-
clear-on-replace 被bugs.openjdk.java.net/browse/JDK-8186908 覆盖(针对多种模式进行报告,但也适用于单选)
-
感谢您的快速回复@kleopatra :)。我想知道它是否可能是Java中的错误。不过很遗憾,我认为它不会很快得到修复。我找到了解决这个问题的方法,这比重新选择行更像是一个 hack,我将在下面发布。