如何使用自定义对象在JavaFX中填充ListView?

时间:2016-04-15 21:42:26

标签: java listview javafx

我对Java,JavaFX以及一般的编程有点新鲜,而且我有一个让我大脑破裂的问题。

在大多数关于填充ListView的教程中(更具体地说,使用ObservableArrayList),最简单的方法是从字符串的ObservableList中创建它,如下所示:

ObservableList<String> wordsList = FXCollections.observableArrayList("First word","Second word", "Third word", "Etc."); 
ListView<String> listViewOfStrings = new ListView<>(wordsList);

但我不想使用字符串。我想使用一个名为Words的自定义对象:

ObservableList<Word> wordsList = FXCollections.observableArrayList();
wordsList.add(new Word("First Word", "Definition of First Word");
wordsList.add(new Word("Second Word", "Definition of Second Word");
wordsList.add(new Word("Third Word", "Definition of Third Word");
ListView<Word> listViewOfWords = new ListView<>(wordsList);

每个Word对象只有2个属性:wordString(单词的一个字符串)和definition(另一个字符串,即单词&#39; s的定义)。我有两个人都有吸气剂和安装者。

你可以看到它的去向 - 代码编译和工作,但是当我在我的应用程序中显示它时,它不是显示ListView中每个单词的标题,而是将Word对象本身显示为String!

Image showing my application and its ListView

我的问题是,具体来说,有一种简单的方法可以重写:

ListView<Word> listViewOfWords = new ListView<>(wordsList);

这样一来,它不是直接从wordsList中获取Words,而是访问我的observableArrayList的每个Word中的wordString属性?

为了清楚起见,这对于android来说并非如此,并且最终将更改,保存和加载单词列表,因此我无法创建另一个数组来保存wordStrings。我在网上做了一些研究,似乎有一个名为“Cell Factories&#39;”的东西,但对于看起来如此简单的问题似乎不必要的复杂,正如我之前所说,我和#39;在编程方面有点新手。

有人可以帮忙吗?这是我第一次来这里,所以如果我没有包含足够的代码或者我做错了,我很抱歉。

3 个答案:

答案 0 :(得分:30)

解决方案方法

我建议使用cell factory来解决此问题。

listViewOfWords.setCellFactory(param -> new ListCell<Word>() {
    @Override
    protected void updateItem(Word item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null || item.getWord() == null) {
            setText(null);
        } else {
            setText(item.getWord());
        }
    }
});

示例应用

add image

import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;

public class CellFactories extends Application {    
    @Override
    public void start(Stage stage) {
        ObservableList<Word> wordsList = FXCollections.observableArrayList();
        wordsList.add(new Word("First Word", "Definition of First Word"));
        wordsList.add(new Word("Second Word", "Definition of Second Word"));
        wordsList.add(new Word("Third Word", "Definition of Third Word"));
        ListView<Word> listViewOfWords = new ListView<>(wordsList);
        listViewOfWords.setCellFactory(param -> new ListCell<Word>() {
            @Override
            protected void updateItem(Word item, boolean empty) {
                super.updateItem(item, empty);

                if (empty || item == null || item.getWord() == null) {
                    setText(null);
                } else {
                    setText(item.getWord());
                }
            }
        });
        stage.setScene(new Scene(listViewOfWords));
        stage.show();
    }

    public static class Word {
        private final String word;
        private final String definition;

        public Word(String word, String definition) {
            this.word = word;
            this.definition = definition;
        }

        public String getWord() {
            return word;
        }

        public String getDefinition() {
            return definition;
        }
    }

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

实施说明

虽然您可以在Word类中覆盖toString以提供针对ListView中表示的单词的字符串表示,但我建议在ListView中提供单元工厂,以便从单词对象中提取视图数据并表示它在你的ListView中。使用这种方法可以分离关注点,因为您不会将Word对象的图形视图与其文本toString方法联系起来;所以toString可以继续有不同的输出(例如Word字段的完整信息,带有单词名称和描述用于调试目的)。此外,单元工厂更灵活,因为您可以应用各种图形节点来创建数据的直观表示,而不仅仅是直接的文本字符串(如果您希望这样做)。

另外,另外,我建议删除他们的setter来制作Word对象immutable objects。如果您确实需要修改单词对象本身,那么处理它的最佳方法是为对象字段提供公开的可观察属性。如果您还希望在对象的可观察属性发生更改时更新UI,那么您需要通过监听对它们的更改来使列表单元格知道相关项目的更改(这在此更加复杂)案件)。请注意,包含单词的列表已经是可观察的,ListView将负责处理对该列表的更改,但如果您在显示的单词对象中修改了单词定义,那么列表视图将不会进行更改在ListView单元工厂中没有适当的监听器逻辑的定义。

答案 1 :(得分:2)

我敢打赌,ListView在Word上调用toString()方法。如果你没有覆盖它,它使用默认的toString()方法,它只输出那些......不那么有用的信息。重写它以输出一个经过精心设计的String,你应该好好去!

答案 2 :(得分:2)

您的ListView目前显示的是Word的toString()。要解决您的问题,只需在Word类中添加以下方法(这只是一个示例):

@Override
public String toString(){
    return (this.word + " --- Definition: " + this.definition);
}