我有一个对象的TreeView。我想添加一个ChangeListener,它将在右窗格上绘制我的对象,并删除旧的对象(如果存在)。但是我不能这样做,因为不明显的原因,我的旧值始终为null。
这是我的听众:

treeView.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends TreeItem<Asset>> ov, TreeItem<Asset> t, TreeItem<Asset> t1) -> {
            t.getValue().derepresent();
            t1.getValue().represent();
        });


此代码使我的应用能够很好地“表示”对象。
java - JavaFX TreeView ChangeListener的旧值始终为null-LMLPHP

但是当我选择另一个项目时,什么也没发生。
java - JavaFX TreeView ChangeListener的旧值始终为null-LMLPHP

然后切换回我的对象​​(我要表示)后,应用会创建它的第二个实例(cause previous wasn t已删除)。java - JavaFX TreeView ChangeListener的旧值始终为null-LMLPHP

所以我问,我该如何解决?

编辑:
这是我的Controller类中的有用代码:

public class Controller implements Initializable {

@FXML
private VBox infoVBox;

@FXML
private TreeView<Asset> treeView;

private Stage stage;

@Override
public void initialize(URL location, ResourceBundle resources) {
}

public void selectRootOnClick(ActionEvent actionEvent) {
    try {
        final DirectoryChooser directoryChooser = new DirectoryChooser();
        final File selectedDirectory = directoryChooser.showDialog(stage);
        TreeItem<Asset> treeItem = new TreeItem<>(new Asset(selectedDirectory.getAbsolutePath(), infoVBox));
        createTree(treeItem);
        treeItem.getChildren().sort(Comparator.comparing(t -> t.getValue().getAssetPath().toLowerCase()));
        treeView.setRoot(treeItem);
        treeView.setCellFactory(new Callback<>() {
            public TreeCell<Asset> call(TreeView<Asset> tv) {
                return new TreeCell<>() {
                    @Override
                    protected void updateItem(Asset item, boolean empty) {
                        super.updateItem(item, empty);
                        setText((empty || item == null) ? "" : item.getAssetPath());
                    }
                };
            }
        });
        treeView.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends TreeItem<Asset>> ov, TreeItem<Asset> t, TreeItem<Asset> t1) -> {
            if (t != null) t.getValue().derepresent();
            t1.getValue().represent();
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public void createTree(TreeItem<Asset> rootItem) throws IOException {
    try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(rootItem.getValue().getAssetPath()))) {
        for (Path path : directoryStream) {
            TreeItem<Asset> newItem;
            if (!Files.isDirectory(path)) {
                String extension = "";
                int i = path.toString().lastIndexOf('.');
                if (i > 0) extension = path.toString().substring(i + 1);
                switch (extension) {
                    case "mp3":
                        newItem = new TreeItem<>(new Audio(path.toString(), infoVBox));
                        rootItem.getChildren().add(newItem);
                        break;
                    default:
                        newItem = new TreeItem<>(new Asset(path.toString(), infoVBox));
                        rootItem.getChildren().add(newItem);
                        break;
                }
            } else {
                newItem = new TreeItem<>(new Asset(path.toString(), infoVBox));
                newItem.setExpanded(true);
                rootItem.getChildren().add(newItem);
                createTree(newItem);
            }
        }
    }
}
}


我有一个类的层次结构。在此层次结构中,音频类继承了Asset类。
这是资产类:

public class Asset {

protected final String assetPath;

public String getAssetPath() {
    return assetPath;
}

protected VBox parent;

public Asset() {
    assetPath = "";
    parent = null;
}
public Asset(String path, VBox node) {
    assetPath = path;
    parent = node;
}

public void represent() {}

public void derepresent() {}

}


我的音频课:

public final class Audio extends Asset {
private Media media;
private MediaPlayer mediaPlayer;
private MediaControl mediaControl;

public Audio() {
    super();
}
public Audio(String path, VBox parent) {
    super(path, parent);
}

@Override
public void represent() {
    media = new Media("file:///"+assetPath);
    mediaPlayer = new MediaPlayer(media);
    mediaControl = new MediaControl(mediaPlayer);
    parent.getChildren().add(mediaControl);
}

@Override
public void derepresent() {
    mediaControl = null;
    mediaPlayer = null;
    media = null;
    parent.getChildren().remove(mediaControl);
}
}


我也有MediaControl,但是我想它的实现对于当前线程是不必要的。

最佳答案

您将mediaControl设置为null的时间过早,因此parent.getChildren().remove(mediaControl)基本上只是parent.getChildren().remove(null),它总是抛出NullPointerException

derepresent()更改为:

@Override
public void derepresent() {
    // you can drop this null-check when you're sure that mediaControl is set
    if(mediaControl != null) {
        parent.getChildren().remove(mediaControl);
    }
    mediaControl = null;
    mediaPlayer = null;
    media = null;
}


我还建议删除构造函数Audio(),因为当NullPointerException仍为derepresent()时,您可能会在representparent中得到一个null

09-11 18:54