简体   繁体   English

如何将JavaFX Label绑定到ListView中的选定项目

[英]How to bind a JavaFX Label to the selected item from a ListView

I have a ListView full of POJOs and want a label in the GUI to display informations from the selected item. 我有一个装满POJO的ListView,并希望GUI中有一个标签来显示所选项目的信息。

My POJO looks something like that: 我的POJO看起来像这样:

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

Now when the user selects a customer from the list I want the name of the selected customer displayed in a label. 现在,当用户从列表中选择客户时,我希望在标签中显示所选客户的名称。

Obviously I can't bind to the name directly because it is not a Property . 显然我不能直接绑定到name ,因为它不是Property (And I don't want to replace my Customers String s with StringProperty -objects because the SimpleStringProperty is not serializable and I need the Customer to be transfered via RMI.) (而且我不想用StringProperty -objects替换我的Customers String ,因为SimpleStringProperty不可serializable ,我需要通过RMI传输Customer 。)

I've tried the BeanPathAdapter from JFXtras (which looks really nice by the way) like this: 我已经尝试过JFXtrasBeanPathAdapter (顺便说一句看起来很不错),如下所示:

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

But this solution only throws me an Exception: 但是这个解决方案只给我一个例外:

...
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

So I hoped there would be a better solution than to use lstCustomers.getSelectionModel().selectedItemProperty().addListener(...) and handle the population of the labels there manually. 所以我希望有一个更好的解决方案,而不是使用lstCustomers.getSelectionModel().selectedItemProperty().addListener(...)并手动处理那里的标签填充。

A better solution I think, to the one I gave before, is to use the BeanPathAdapter as you tried. 我认为,对于之前给出的更好的解决方案是使用BeanPathAdapter。
However the BeanPathAdapter needs to have the following property added to it: 但是,BeanPathAdapter需要添加以下属性:

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

Then in your code you need the following: 然后在您的代码中,您需要以下内容:

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

I don't think that there's a simple one liner that you are looking for. 我不认为你正在寻找一个简单的衬垫。
You could do the following: 您可以执行以下操作:

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

But you will need to modify your Customer POJO like so: 但您需要修改您的客户POJO,如下所示:

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

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

I don't think this is recommended though because properties are expected to reflect changes in the underlying data and the above will only reflect the name as it was when nameProperty is called. 我不认为这是推荐的,因为预期属性会反映基础数据的变化,而上述内容只会反映调用nameProperty时的名称。 So if setName is called the property won't reflect the change. 因此,如果调用setName,则属性不会反映更改。 If the Customer name never changes then you could get away with this. 如果客户名称永远不会改变,那么您可以逃避这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM