如何使用自定义对象在JavaFX中填充ListView? [英] How can I Populate a ListView in JavaFX using Custom Objects?

查看:115
本文介绍了如何使用自定义对象在JavaFX中填充ListView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Java,JavaFX和一般编程有点新意,我有一个让我大脑破裂的问题。



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

  ObservableList<字符串> wordsList = FXCollections.observableArrayList(第一个字,第二个字,第三个字,等等); 
ListView< String> listViewOfStrings = new ListView<>(wordsList);

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

  ObservableList< Word> wordsList = FXCollections.observableArrayList(); 
wordsList.add(新词(第一个词,第一个词的定义);
wordsList.add(新词(第二个词,第二个词的定义);
wordsList.add(新词(第三个词,第三个词的定义);
ListView< Word> listViewOfWords = new ListView<>(wordsList);

每个Word对象只有2个属性:wordString(单词的一个字符串)和definition(另一个字符串,即单词的定义).I两者都有getter和setter。



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



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

公共类CellFactories扩展Application {
@Override
public void start(Stage stage){
ObservableList< Word> wordsList = FXCollections.observableArrayList();
wordsList.add(新词(第一个词,第一个词的定义));
wordsList.add(新词(第二个词,第二个词的定义));
wordsList.add(新词(第三个字,第三个词的定义));
ListView< Word> listViewOfWords = new ListView<>(wordsList);
listViewOfWords.setCellFactory(param - > new ListCell< Word>(){
@Override
protected void updateItem(Word item,boolean empty){
super.updateItem(item ,空);

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字符串定义;

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字段的完整信息,带有单词名称和描述用于调试目的)。此外,单元工厂更灵活,因为您可以应用各种图形节点来创建数据的直观表示,而不仅仅是直接的文本字符串(如果您希望这样做)。



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


I'm a bit new to Java, JavaFX, and programming in general, and I have an issue that is breaking my brain.

In most of the tutorials I have looked up regarding populating a ListView (Using an ObservableArrayList, more specifically) the simplest way to do it is to make it from an ObservableList of Strings, like so:

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

But I don't want to use Strings. I would like to use a custom object I made called 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);

Each Word object only has 2 properties: wordString (A string of the word), and definition (Another string that is the word's definition). I have getters and setters for both.

You can see where this is going- the code compiles and works, but when I display it in my application, rather than displaying the titles of every word in the ListView, it displays the Word object itself as a String!

Image showing my application and its ListView

My question here is, specifically, is there a simple way to rewrite this:

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

In such a way that, rather than taking Words directly from wordsList, it accesses the wordString property in each Word of my observableArrayList?

Just to be clear, this isn't for android, and the list of words will be changed, saved, and loaded eventually, so I can't just make another array to hold the wordStrings. I have done a bit of research on the web and there seems to be a thing called 'Cell Factories', but it seems unnecessarily complicated for what seems to be such a simple problem, and as I stated before, I'm a bit of a newbie when it comes to programming.

Can anyone help? This is my first time here, so I'm sorry if I haven't included enough of my code or I've done something wrong.

解决方案

Solution Approach

I advise using a cell factory to solve this problem.

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());
        }
    }
});

Sample Application

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);
    }
}

Implementation Notes

Although you could override toString in your Word class to provide a string representation of the word aimed at representation in your ListView, I would recommend providing a cell factory in the ListView for extraction of the view data from the word object and representation of it in your ListView. Using this approach you get separation of concerns as you don't tie a the graphical view of your Word object with it's textual toString method; so toString could continue to have different output (for example full information on Word fields with a word name and a description for debugging purposes). Also, a cell factory is more flexible as you can apply various graphical nodes to create a visual representation of your data beyond just a straight text string (if you wish to do that).

Also, as an aside, I recommend making your Word objects immutable objects, by removing their setters. If you really need to modify the word objects themselves, then the best way to handle that is to have exposed observable properties for the object fields. If you also want your UI to update as the observable properties of your objects change, then you need to make your list cells aware of the changes to the associated items, by listening for changes to them (which is quite a bit more complex in this case). Note that, the list containing the words is already observable and ListView will take care of handling changes to that list, but if you modified the word definition for instance within a displayed word object, then your list view wouldn't pick up changes to the definition without appropriate listener logic in the ListView cell factory.

这篇关于如何使用自定义对象在JavaFX中填充ListView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆