[英]How can I Populate a ListView in JavaFX using Custom Objects?
我對 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(單詞定義的另一個字符串)。 我有兩者的 getter 和 setter。
您可以看到這是怎么回事——代碼可以編譯和工作,但是當我在我的應用程序中顯示它時,它不是在 ListView 中顯示每個單詞的標題,而是將 Word 對象本身顯示為一個字符串!
我的問題是,具體來說,是否有一種簡單的方法來重寫它:
ListView<Word> listViewOfWords = new ListView<>(wordsList);
以這種方式,而不是直接從 wordsList 中獲取 Words,它訪問我的 observableArrayList 的每個 Word 中的 wordString 屬性?
需要說明的是,這不適用於 android,單詞列表最終會被更改、保存和加載,所以我不能只創建另一個數組來保存 wordStrings。 我在網上做了一些研究,似乎有一個叫做“細胞工廠”的東西,但對於一個看起來如此簡單的問題來說,它似乎不必要地復雜,而且正如我之前所說,我有點編程方面的新手。
誰能幫忙? 這是我第一次來這里,所以如果我沒有包含足夠的代碼或者我做錯了什么,我很抱歉。
解決方法
我建議使用細胞工廠來解決這個問題。
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());
}
}
});
示例應用程序
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 中提供一個單元工廠,以便從單詞對象中提取視圖數據並在您的列表顯示。 使用這種方法,您可以分離關注點,因為您不會將 Word 對象的圖形視圖與其文本 toString 方法聯系起來; 因此 toString 可以繼續具有不同的輸出(例如,帶有單詞名稱和用於調試目的的描述的 Word 字段的完整信息)。 此外,單元工廠更靈活,因為您可以應用各種圖形節點來創建數據的可視化表示,而不僅僅是純文本字符串(如果您希望這樣做)。
另外,順便說一句,我建議通過刪除它們的設置器來使您的 Word 對象成為不可變對象。 如果您確實需要修改單詞對象本身,那么最好的處理方法是為對象字段公開可觀察的屬性。 如果您還希望您的 UI 在對象的可觀察屬性發生變化時更新,那么您需要通過偵聽對關聯項目的更改來讓列表單元了解對關聯項目的更改(這在此過程中要復雜得多)情況下, 提取器可以提供幫助)。 請注意,包含單詞的列表已經是可觀察的,並且 ListView 將負責處理對該列表的更改,但是如果您修改了單詞定義,例如在顯示的單詞對象中,那么您的列表視圖將不會獲取對ListView 單元工廠(或者,最好是提取器)中沒有適當的偵聽器邏輯的定義。
目前,您的ListView顯示的是Word的toString()。 要解決您的問題,只需在Word類中添加以下方法(這只是一個示例):
@Override
public String toString(){
return (this.word + " --- Definition: " + this.definition);
}
我敢打賭,ListView 正在 Word 上調用 toString() 方法。 如果您沒有覆蓋它,它會使用默認的 toString() 方法,該方法只是輸出......不太有用的信息。 覆蓋它以輸出格式精美的字符串,您應該一切順利!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.