我想自定义ListView
单元格的显示。假设有一个ListView
包含Person
类的对象和两个按钮:
Person
Person
我想实现以下目标:
getBasicView()
Person
字段的name
。getExpandedView()
的{{1}},这是一个多行文字Person
。问题是什么?
我写的代码填写了上面给出的要求,但出现了其他错误:
name + "/n" + surname
时,单元格的显示会更改为未实现的Person
方法(因此用户会看到toString()
类似垃圾)。< / LI>
醇>
sample.Person@c4f324
时,奇怪的事情开始发生。已删除的Person
Person
仍保留在向下移动两个单元格的单元格中,因为它不再包含name
对象 - 无法清除它。我尝试向单元格Person
添加侦听器,可以检查项目是否为itemProperty
,之后我可以将文本设置为null
但不幸的是它不起作用。有谁知道如何让我的代码完全正常运行?
提供SSCCE(假设所有文件都在""
包中):
Main.java:
sample
sample.fxml:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
public void start(Stage stage) {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setController(Controller.class);
try {
Parent parent = FXMLLoader.load(getClass().getResource("/sample/sample.fxml"));
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch();
}
}
Controller.java:
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.VBox?>
<HBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.Controller">
<VBox>
<Button text="Add Person" onAction="#addPerson"/>
<Button text="Delete Person" onAction="#deletePerson"/>
</VBox>
<ListView prefHeight="400" prefWidth="400" fx:id="listView"/>
</HBox>
Person.java:
package sample;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.cell.TextFieldListCell;
import java.util.concurrent.ThreadLocalRandom;
public class Controller {
@FXML
private ListView<Person> listView;
private ObservableList<Person> personList = FXCollections.observableArrayList();
private String [] names = {"John", "Katherine", "Michael", "August", "Peter"};
private String [] surnames = {"Jones", "Mayer", "Stevens", "Wayne", "Milton"};
@FXML
private void initialize() {
initializeListCells();
initializeList();
}
private void initializeList() {
for (int i = 0 ; i < 5 ; i++) {
personList.add(generatePerson());
}
listView.setItems(personList);
}
private void initializeListCells() {
listView.setCellFactory(param -> {
TextFieldListCell<Person> cell = new TextFieldListCell<Person>();
cell.selectedProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
cell.itemProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
return cell;
});
}
private void handleCellDisplaying(TextFieldListCell<Person> cell) {
Person person = cell.getItem();
if (person != null) {
Platform.runLater(() -> {
if (!cell.isSelected()) {
cell.setText(person.getBasicView());
} else {
cell.setText(person.getExpandedView());
}
});
} else {
cell.setText("");
}
}
@FXML
private void addPerson() {
personList.add(generatePerson());
}
@FXML
private void deletePerson() {
MultipleSelectionModel<Person> selectionModel = listView.getSelectionModel();
if (!selectionModel.isEmpty()) {
int selectedIndex = selectionModel.getSelectedIndex();
personList.remove(selectedIndex);
}
}
private Person generatePerson() {
int nameRandom = ThreadLocalRandom.current().nextInt(1,5);
int surnameRandom = ThreadLocalRandom.current().nextInt(1,5);
return new Person(names[nameRandom],surnames[surnameRandom]);
}
}
答案 0 :(得分:1)
问题是TextFieldListCell
实现了单元格生命周期方法(updateItem
等)并在各个点有效地调用setText(item.toString())
。这显然会干扰您尝试实施的行为。 (例如,删除最后一个单元格的问题似乎发生,因为setText("")
在之前被调用 TextFieldListCell
将文本重置为其先前的值。如果您使用Platform.runLater(...)
1}} hack以便它包围完整的if
- else
子句,然后这个问题就消失了。但是......)
如果您不需要单元格可编辑,则无需使用TextFieldListCell
:只需使用普通ListCell
。 (另请注意,处理程序中不需要Platform.runLater(...)
更改项目/选定状态。)
package sample;
import java.util.concurrent.ThreadLocalRandom;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MultipleSelectionModel;
public class Controller {
@FXML
private ListView<Person> listView;
private ObservableList<Person> personList = FXCollections.observableArrayList();
private String[] names = { "John", "Katherine", "Michael", "August", "Peter" };
private String[] surnames = { "Jones", "Mayer", "Stevens", "Wayne", "Milton" };
@FXML
private void initialize() {
initializeListCells();
initializeList();
}
private void initializeList() {
for (int i = 0; i < 5; i++) {
personList.add(generatePerson());
}
listView.setItems(personList);
}
private void initializeListCells() {
listView.setCellFactory(param -> {
ListCell<Person> cell = new ListCell<Person>();
cell.selectedProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
cell.itemProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
return cell;
});
}
private void handleCellDisplaying(ListCell<Person> cell) {
Person person = cell.getItem();
if (person != null) {
if (!cell.isSelected()) {
cell.setText(person.getBasicView());
} else {
cell.setText(person.getExpandedView());
}
} else {
cell.setText("");
}
}
@FXML
private void addPerson() {
personList.add(generatePerson());
}
@FXML
private void deletePerson() {
MultipleSelectionModel<Person> selectionModel = listView.getSelectionModel();
if (!selectionModel.isEmpty()) {
int selectedIndex = selectionModel.getSelectedIndex();
personList.remove(selectedIndex);
}
}
private Person generatePerson() {
int nameRandom = ThreadLocalRandom.current().nextInt(1, 5);
int surnameRandom = ThreadLocalRandom.current().nextInt(1, 5);
return new Person(names[nameRandom], surnames[surnameRandom]);
}
}