2013-09-04 34 views
6

Tôi có một ListView đầy POJO và muốn có nhãn trong GUI để hiển thị thông tin từ mục đã chọn.Cách liên kết Nhãn JavaFX với mục đã chọn từ một ListView

My POJO trông giống như thế:

class Customer { 
    private String name; 
    ... 
    public String getName() { 
    return name; 
    } 

Bây giờ khi người sử dụng chọn một khách hàng từ danh sách Tôi muốn tên của khách hàng chọn được hiển thị trong một nhãn.

Rõ ràng là tôi không thể liên kết trực tiếp với số name vì nó không phải là Property. (Và tôi không muốn thay thế khách hàng của tôi String s với StringProperty -objects vì SimpleStringProperty không phải là serializable và tôi cần Customer để được chuyển qua RMI.)

Tôi đã thử các BeanPathAdapter từ JFXtras (trông thật sự tốt đẹp bằng cách này) như thế này:

BeanPathAdapter<MultipleSelectionModel> customerBeanPathAdapter; 
    customerBeanPathAdapter = new BeanPathAdapter<>(lstCustomers.getSelectionModel()); 
    customerBeanPathAdapter.bindBidirectional("selectedItem.name", lblCustomerName.textProperty()); 

Nhưng giải pháp này chỉ ném cho tôi một ngoại lệ:

... 
Caused by: java.lang.IllegalArgumentException: Unable to resolve accessor getSelectedItem 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.buildAccessor(BeanPathAdapter.java:3062) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.buildAccessorWithLikelyPrefixes(BeanPathAdapter.java:3022) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.updateMethodHandles(BeanPathAdapter.java:2986) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.<init>(BeanPathAdapter.java:2977) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldBean.performOperation(BeanPathAdapter.java:1348) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldBean.performOperation(BeanPathAdapter.java:1186) 
at jfxtras.labs.scene.control.BeanPathAdapter.bindBidirectional(BeanPathAdapter.java:567) 
at jfxtras.labs.scene.control.BeanPathAdapter.bindBidirectional(BeanPathAdapter.java:369) 
at at.gs1.sync.qm.client.gui.MainWindowController.initialize(MainWindowController.java:61) 
... 22 more 
Caused by: java.lang.IllegalAccessException: symbolic reference class is not public: class javafx.scene.control.ListView$ListViewBitSetSelectionModel, from jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle 
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:512) 
at java.lang.invoke.MethodHandles$Lookup.checkSymbolicClass(MethodHandles.java:1113) 
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1094) 
at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:626) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.buildAccessor(BeanPathAdapter.java:3049) 
... 30 more 

Vì vậy, tôi hy vọng sẽ có một giải pháp tốt hơn so với sử dụng lstCustomers.getSelectionModel().selectedItemProperty().addListener(...) và xử lý dân số của nhãn ở đó theo cách thủ công.

+0

Một phần của vấn đề là khả năng tiếp cận hạn chế thực hiện (trông giống như bộ điều hợp không thể xử lý nó). Khác có thể là lỗi hoặc kỳ vọng không hợp lệ (của tôi cũng như :-) - cập nhật giá trị dường như chỉ xảy ra theo hướng từ thuộc tính bị ràng buộc trở lại thuộc tính được điều chỉnh (đó là đường dẫn), chứ không phải theo cách khác. Ít nhất không thể làm cho nó hoạt động với các hạt đơn giản nhất, không phải với một thuộc tính fx hay một thuộc tính bean java thuần túy. – kleopatra

Trả lời

2

Một giải pháp tốt hơn tôi nghĩ, với cái mà tôi đã đưa ra trước đây, là sử dụng BeanPathAdapter như bạn đã thử.
Tuy nhiên BeanPathAdapter cần phải có tài sản sau đây được thêm vào nó:

private final ObjectProperty<B> beanProp = new SimpleObjectProperty<>(); 
{ 
    beanProp.addListener(new ChangeListener<B>() 
    { 
     @Override 
     public void changed(ObservableValue<? extends B> ob, B oldVal, B newVal) 
     { 
      setBean(newVal); 
     } 
    }); 
} 

public ObjectProperty<B> beanProperty() 
{ 
    return beanProp; 
} 

Sau đó trong mã của bạn, bạn cần như sau:

BeanPathAdapter<Customer> custBean; 
custBean = new BeanPathAdapter<>(new Customer()); // empty or any customer 
custBean.bindBidirectional("name", label.textProperty()); 
custBean.beanProperty().bind(listview.getSelectionModel().selectedItemProperty()); 
+0

Điều đó có vẻ rất hứa hẹn. Tôi sẽ thử ngay hôm nay. Cảm ơn! (btw. xin lỗi vì trả lời muộn!) –

+0

Làm việc như một sự quyến rũ! Cảm ơn!! –

1

Tôi không nghĩ rằng có một lớp lót đơn giản mà bạn đang tìm kiếm.
Bạn có thể làm như sau:

label.textProperty().bind(Bindings.selectString(listview.getSelectionModel().selectedItemProperty(), "name")); 

Nhưng bạn sẽ cần phải sửa đổi POJO khách hàng của bạn như sau:

class Customer 
{ 
    private String name; 
    ... 
    public String getName() { return name; } 

    public ReadOnlyStringProperty nameProperty() 
    { 
     return new SimpleStringProperty(name); 
    } 
} 

Tôi không nghĩ rằng đây chỉ là ví dụ vì thuộc tính này được dự kiến ​​để phản ánh những thay đổi trong dữ liệu cơ bản và ở trên sẽ chỉ phản ánh tên như khi tên gọiProperty được gọi. Vì vậy, nếu setName được gọi là thuộc tính sẽ không phản ánh thay đổi. Nếu tên khách hàng không bao giờ thay đổi thì bạn có thể thoát khỏi điều này.

Các vấn đề liên quan