2016-04-15 16 views
17

Tôi là một chút mới đối với Java, JavaFX và lập trình nói chung, và tôi có một vấn đề đang phá vỡ bộ não của tôi.Làm thế nào tôi có thể điền một ListView trong JavaFX bằng cách sử dụng các đối tượng tùy chỉnh?

Trong hầu hết các hướng dẫn Tôi đã nhìn lên về Populating một ListView (Sử dụng một ObservableArrayList, cụ thể hơn) cách đơn giản nhất để làm điều đó là để làm cho nó từ một ObservableList của Strings, như vậy:

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

Nhưng tôi không muốn sử dụng Strings. Tôi muốn sử dụng một đối tượng tùy chỉnh tôi khiến gọi từ:

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

Mỗi đối tượng Lời chỉ có 2 thuộc tính: wordString (Một chuỗi của từ này), và định nghĩa (Một chuỗi đó là định nghĩa của từ). Tôi có getters và setters cho cả hai.

Bạn có thể thấy mã này đang đi đâu - mã biên dịch và hoạt động, nhưng khi tôi hiển thị nó trong ứng dụng của tôi, thay vì hiển thị tiêu đề của mỗi từ trong ListView, nó sẽ hiển thị đối tượng Word như một chuỗi!

Image showing my application and its ListView

Câu hỏi của tôi ở đây là, đặc biệt, là có một cách đơn giản để viết lại này:

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

Trong một cách như vậy mà, chứ không phải lấy từ trực tiếp từ wordsList, nó truy cập vào wordString tài sản trong mỗi Word của observableArrayList của tôi?

Chỉ cần rõ ràng, đây không phải là dành cho Android và danh sách các từ sẽ được thay đổi, lưu và tải sau cùng, vì vậy tôi không thể tạo một mảng khác để giữ chuỗi từ. Tôi đã thực hiện một chút nghiên cứu trên web và có vẻ là một thứ gọi là 'Nhà máy di động', nhưng có vẻ phức tạp không cần thiết cho những gì dường như là một vấn đề đơn giản như vậy, và như tôi đã nói trước đây, tôi có một chút một người mới khi nói đến lập trình.

Có ai giúp được không? Đây là lần đầu tiên của tôi ở đây, vì vậy tôi xin lỗi nếu tôi đã không bao gồm đủ mã của tôi hoặc tôi đã làm điều gì đó sai trái.

Trả lời

20

Solution Approach

Tôi khuyên sử dụng một cell factory để giải quyết vấn đề này.

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

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

Thực hiện Ghi chú

Mặc dù bạn có thể ghi đè lên toString trong lớp Word của bạn để cung cấp một chuỗi đại diện của từ nhằm đại diện trong ListVie của bạn w, tôi sẽ khuyên bạn nên cung cấp một nhà máy di động trong ListView để trích xuất dữ liệu xem từ đối tượng từ và đại diện của nó trong ListView của bạn. Sử dụng cách tiếp cận này, bạn có được sự tách biệt các mối quan tâm khi bạn không gắn một khung nhìn đồ họa của đối tượng Word của bạn với phương thức toString văn bản của nó; do đó toString có thể tiếp tục có đầu ra khác nhau (ví dụ như thông tin đầy đủ về các trường Word với một tên từ và một mô tả cho các mục đích gỡ lỗi). Ngoài ra, một nhà máy di động linh hoạt hơn vì bạn có thể áp dụng các nút đồ họa khác nhau để tạo ra một biểu diễn trực quan về dữ liệu của bạn ngoài chỉ một chuỗi văn bản thẳng (nếu bạn muốn làm điều đó).

Ngoài ra, như một sang một bên, tôi khuyên bạn nên tạo đối tượng Word của mình immutable objects, bằng cách xóa người định vị của chúng. Nếu bạn thực sự cần phải sửa đổi các đối tượng từ, thì cách tốt nhất để xử lý đó là có các thuộc tính quan sát được tiếp xúc cho các trường đối tượng. Nếu bạn cũng muốn giao diện người dùng cập nhật khi các thuộc tính có thể quan sát của đối tượng thay đổi, thì bạn cần phải làm cho các ô danh sách của bạn nhận biết các thay đổi đối với các mục được liên kết, bằng cách lắng nghe những thay đổi đối với chúng (điều này phức tạp hơn một chút trường hợp). Lưu ý rằng, danh sách chứa các từ đã được quan sát và ListView sẽ xử lý các thay đổi trong danh sách đó, nhưng nếu bạn sửa đổi định nghĩa từ trong một đối tượng từ được hiển thị, thì chế độ xem danh sách của bạn sẽ không nhận các thay đổi đối với định nghĩa mà không có logic người nghe thích hợp trong nhà máy sản xuất ô ListView.

+0

Cảm ơn rất nhiều câu trả lời rất chi tiết của bạn! Bây giờ tôi sẽ cố gắng ghi đè phương thức toString(), nhưng tôi sẽ thực hiện một số đọc thêm về các Nhà máy di động để hiểu rõ hơn về chúng và sau đó sửa đổi ứng dụng để sử dụng chúng theo đề xuất của bạn. Tôi sẽ chỉ sửa đổi 'định nghĩa' của từng từ riêng lẻ bằng nút chỉnh sửa đó và chế độ xem danh sách chỉ theo dõi thuộc tính 'từ', vì vậy nó không cần theo dõi các thay đổi đối với 'định nghĩa'. –

1

Tôi sẽ đặt cược cho bạn một nickel rằng ListView đang gọi phương thức toString() trên Word. Nếu bạn không ghi đè nó, nó sẽ sử dụng phương thức toString() mặc định, nó chỉ xuất ra ... thông tin không hữu ích. Ghi đè nó để xuất ra một String được định dạng đẹp, và bạn nên làm tốt!

+0

Hmmm, có ý nghĩa! Tôi sẽ cho một phát bắn; ngay bây giờ tôi có một lớp học để tham dự, nhưng tôi sẽ thử nó sau và xem nó có hoạt động không. –

+0

Nhưng nó không phải là một giải pháp rất tốt: bạn có thể muốn phương thức 'toString()' trả về một cái gì đó khác với những gì bạn muốn hiển thị trong giao diện người dùng. –

0

Loại ListView của bạn hiển thị tại thời điểm này là ToString của Word(). Để khắc phục vấn đề của bạn chỉ cần thêm các phương pháp sau đây trong lớp Word của bạn (điều này chỉ là một ví dụ):

@Override 
public String toString(){ 
    return (this.word + " --- Definition: " + this.definition); 
} 
Các vấn đề liên quan