2016-04-15 115 views
17

我對Java,JavaFX和一般編程有點新鮮感,而且我遇到了一個打破我的大腦的問題。如何使用自定義對象在JavaFX中填充ListView?

在大多數教程我已經看過了關於填充一個ListView(使用ObservableArrayList,更具體)做最簡單的方法是從字符串的ObservableList使得它,就像這樣:

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

但我不想使用字符串。我想用我製作的一個叫做字的自定義對象:

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

每個字的對象只有2個屬性:wordString(這個詞的字符串),並定義(另一個字符串,它是這個詞的定義)。我有兩個getter和setter。

你可以看到這是怎麼回事 - 代碼編譯和工作,但是當我在應用程序中顯示它而不是在ListView中顯示每個單詞的標題時,它將Word對象本身顯示爲字符串!

Image showing my application and its ListView

我的問題在這裏,具體而言,有一個簡單的方法來改寫這個:

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

在這樣一種方式,而不是直接從wordsList的詞語,它訪問wordString屬性在我的observableArrayList的每個單詞中?

只是要清楚,這不是爲android,並且單詞列表將被最終更改,保存和加載,所以我不能只是讓另一個數組來保存wordStrings。我在網上做了一些研究,似乎有一個叫做「細胞工廠」的東西,但似乎是一個非常簡單的問題,似乎並不複雜,正如我之前所說的,我有點當談到編程時,這是一個新手。

誰能幫助?這是我第一次來這裏,所以我很抱歉,如果我沒有包含足夠的代碼或者我做錯了什麼。

回答

20

解決方案方法

我建議使用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提供這個詞瞄準了一個字符串表示在您的ListVie中的表示w,我建議在ListView中提供一個單元工廠,用於從單詞對象中提取視圖數據並在ListView中表示它。使用這種方法,您可以分離關注點,因爲您不會將Word對象的圖形視圖與其文本的toString方法綁定在一起;所以toString可能會繼續有不同的輸出(例如,爲了調試目的,Word字段中包含單詞名稱和描述的完整信息)。此外,單元工廠更加靈活,因爲您可以應用各種圖形節點來創建數據的可視化表示,而不僅僅是直接的文本字符串(如果您希望這樣做)。

此外,我建議您通過刪除他們的setter讓您的Word對象immutable objects。如果你確實需要修改單詞對象本身,那麼處理這個問題的最好方法就是暴露對象字段的可觀察屬性。如果您還希望UI隨着對象的可觀察屬性更改而更新,那麼您需要通過監聽對其相關項目的更改(通過監聽它們的更改)來讓列表單元識別相關項目的更改(在此更復雜案件)。請注意,包含單詞的列表已經可觀察,ListView將負責處理對該列表的更改,但是如果您在顯示的單詞對象中修改了單詞定義,那麼您的列表視圖將不會更改在ListView單元工廠中沒有適當的監聽器邏輯。

+0

非常感謝您的詳細解答!現在我將嘗試覆蓋toString()方法,但是我將更多地閱讀Cell Factories以更好地理解它們,然後修改應用程序以根據您的建議使用它們。我只會用該編輯按鈕修改每個單詞的「定義」,而列表視圖只跟蹤「單詞」屬性,因此它不需要跟蹤對「定義」的更改。 –

1

我敢打賭你鎳的ListView在Word上調用toString()方法。如果你沒有覆蓋它,它使用默認的toString()方法,它只是輸出...不那麼有用的信息。重寫它以輸出一個精美格式的字符串,你應該很好去!

+0

嗯,這很有道理!我會給你一個鏡頭;現在我有一堂課要參加,但我會稍後再嘗試,看看它是否成功。 –

+0

但這不是一個很好的解決方案:您可能希望'toString()'方法返回與您希望在UI中顯示的內容不同的內容。 –

0

您的ListView此刻顯示的是Word的toString()。爲了解決您的問題只需添加下面的方法在您的Word類(這只是一個例子):

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