JavaFX中的JavaBeanProperties没有引入java.desktop(Swing,AWT) [英] JavaBeanProperties in JavaFX without pulling in java.desktop (Swing, AWT)

查看:167
本文介绍了JavaFX中的JavaBeanProperties没有引入java.desktop(Swing,AWT)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些多次实例化的模型类,并且有许多字段。虽然我可以将所有字段初始化为 Simple * Property s,但由于分配(并且懒惰创建属性不是一个选项),这会显着降低性能。

I have some model classes that are instantiated many times and have many fields. While I could initialize all fields as Simple*Propertys, this significantly slows performance due to the allocations (and lazy-creating the properties is not an option).

因此,我更愿意使用 JavaBeanProperties 来创建应用程序中所需的按需绑定(如下所示)一个完整的示例 JavaBean包装与JavaFX属性):

Thus, I would prefer to use JavaBeanProperties to create on-demand bindings where needed in the application like so (see this answer for a full example JavaBean wrapping with JavaFX Properties):

Entity bean = ...
StringProperty nameProperty = JavaBeanStringPropertyBuilder()
  .bean(bean)
  .name("name")
  .build();

但是,我不想依赖 java.desktop module-info.java中的c $ c>和相关的Swing组件

However, I do not want to depend on java.desktop and related Swing components in my module-info.java

我可能会重写通过设置在每个Entity的set *方法上递增的SimpleIntegerProperty,然后在GUI中添加侦听器来实现所需的功能,但这仍然效率较低(不必要的更新)并且表达为使用 JavaBean * Property s

I could potentially re-write the desired functionality by setting a SimpleIntegerProperty that is incremented on each of the Entity's set* methods, and then add listeners in the GUI, but this is still less efficient (unnecessary updates) and expressive as using JavaBean*Propertys

如何在不使用java.desktop的情况下使用JavaBeanProperties(或类似的按需绑定功能)?

How may I use JavaBeanProperties (or similar on-demand binding functionality) without using java.desktop?

推荐答案

您可以使用完全不使用Reflection的通用解决方案:

You could use a generic solution that doesn’t use Reflection at all:

public class DelegatingProperty<B,T> extends ObjectPropertyBase<T>
                                     implements JavaBeanProperty<T> {
    /**
     * Create a property without PropertyChangeEvent based notification.
     */
    public static <O, V> JavaBeanProperty<V> get(O bean, String name,
        Function<? super O, ? extends V> getter,
        BiConsumer<? super O, ? super V> setter) {
        return new DelegatingProperty<>(bean, name, getter, setter, null, null);
    }
    /**
     * Create a property with PropertyChangeEvent based notification.
     */
    public static <O, V> JavaBeanProperty<V> get(O bean, String name,
        Function<? super O, ? extends V> getter, BiConsumer<? super O, ? super V> setter,
        BiConsumer<? super O, ? super PropertyChangeListener> register,
        BiConsumer<? super O, ? super PropertyChangeListener> unregister) {
        return new DelegatingProperty<>(bean, name, getter, setter, register, unregister);
    }
    B bean;
    String name;
    Function<? super B, ? extends T> getter;
    BiConsumer<? super B, ? super T> setter;
    BiConsumer<? super B, ? super PropertyChangeListener> unregister;
    PropertyChangeListener listener;

    private DelegatingProperty(B bean, String name,
        Function<? super B, ? extends T> getter,
        BiConsumer<? super B, ? super T> setter,
        BiConsumer<? super B, ? super PropertyChangeListener> register,
        BiConsumer<? super B, ? super PropertyChangeListener> unregister) {
        this.bean = Objects.requireNonNull(bean);
        this.name = name;
        this.getter = Objects.requireNonNull(getter);
        this.setter = Objects.requireNonNull(setter);
        if(register != null || unregister != null) {
            Objects.requireNonNull(register);
            this.unregister = Objects.requireNonNull(unregister);
            register.accept(bean, listener = event -> fireValueChangedEvent());
        }
    }

    @Override
    public Object getBean() {
        return bean;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public T get() {
        return getter.apply(bean);
    }

    @Override
    public void set(T value) {
        if(isBound()) throw new IllegalStateException("bound property");
        T old = getter.apply(bean);
        setter.accept(bean, value);
        T now = getter.apply(bean);
        if(!Objects.equals(old, now)) fireValueChangedEvent();
    }

    @Override
    protected void invalidated() {
        if(isBound()) {
            setter.accept(bean, super.get());
        }
    }

    @Override
    public void fireValueChangedEvent() {
        super.fireValueChangedEvent();
    }

    @Override
    public void dispose() {
        if(unregister != null && listener != null) {
            unregister.accept(bean, listener);
            listener = null;
        }
    }
}

然后,留在你的例如,您可以获得实体名称属性为

Then, to stay at your example, you could get the name property of Entity as

JavaBeanProperty<String> prop = DelegatingProperty.get(bean, "name",
    Entity::getName, Entity::setName,
    Entity::addPropertyChangeListener, Entity::removePropertyChangeListener);

它更详细,但另一方面,提供更多的编译时安全性,因为所有的存在在编译时检查属性所需的方法,并且可能具有更高的运行时性能。

It’s more verbose, but on the other hand, provides more compile time safety, as the presence of all methods required for the property is checked at compile-time, and will likely have a higher runtime performance.

如果在一个具有事件支持的bean类中有很多属性,您可以从专用工厂方法中受益,例如

When you have a lot of properties in one bean class with event support, you may benefit from a dedicated factory method, e.g.

public static <V> JavaBeanProperty<V> property(Entity theBean, String name,
    Function<? super Entity, ? extends V> getter,
    BiConsumer<? super Entity, ? super V> setter) {
    return DelegatingProperty.get(theBean, name, getter, setter,
        Entity::addPropertyChangeListener, Entity::removePropertyChangeListener);
}

然后您可以将其用作

JavaBeanProperty<String> nameProp
    = property(bean, "name", Entity::getName, Entity::setName);
JavaBeanProperty<String> otherProp
    = property(bean, "other", Entity::getOther, Entity::setOther);

当然,也可以通过bean本身的实例方法提供它们而不是静态工厂方法,也许是一个持有该属性的延迟填充字段等。

Of course, it would also be possible to provide them via instance methods of the bean itself instead of a static factory method, too, perhaps with a lazily populated field holding the property, etc.

有几条路你可以从这个起点出发。

There are several roads you can go from this starting point.

这篇关于JavaFX中的JavaBeanProperties没有引入java.desktop(Swing,AWT)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆