【问题标题】:GWT CompositeEditor - Dynamically switched editor not being added to chain properlyGWT CompositeEditor - 动态切换的编辑器未正确添加到链中
【发布时间】:2016-08-10 22:56:14
【问题描述】:

我有一个值类型 Commission,它是更大的编辑器图表的一部分:

public class Commission implements Serializable
{
    private CommissionType commissionType; // enum
    private Money value; // custom type, backed by BigDecimal
    private Integer multiplier;
    private Integer contractMonths;

    // ...
}

我想要实现的是最初只显示commissionType 枚举的下拉列表,然后选择适当的子编辑器以根据所选值编辑其余字段:

我之前使用AbstractSubTypeEditor 实现了多个子类型编辑器(see question here),但这种情况略有不同,因为我没有编辑子类,它们都编辑相同的基本Commission 类型,并且出于某种原因相同方法似乎不适用于编辑相同具体类型的多个编辑器。

我目前有两个子编辑器(都通过自定义接口IsCommissionEditorWidget 实现Editor<Commission>IsWidget),但它们本身有不同的子编辑器,因为Money 可以是便士或英镑,乘数可以代表几天或几个月,以及其他变化。

委员会编辑

我在this question 中查看了类似的问题,并尝试创建一个CompositeEditor<Commission, Commission, Editor<Commission>>

这是我到目前为止所得到的(注意,注释掉的部分是通过实现LeafValueEditor<Commission> 并在amount 上手动调用setValue()getValue(),@ 987654343@和contractMonths):

public class CommissionEditor extends Composite implements CompositeEditor<Commission, Commission, Editor<Commission>>, //LeafValueEditor<Commission>
{
    interface Binder extends UiBinder<HTMLPanel, CommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    CommissionTypeEditor commissionType;

    @UiField
    Panel subEditorPanel;

    private EditorChain<Commission, Editor<Commission>> chain;
    private IsCommissionEditorWidget subEditor = null;
    private Commission value = new Commission();

    public CommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));

        commissionType.box.addValueChangeHandler(event -> setValue(new Commission(event.getValue())));
    }

    @Override
    public void setValue(Commission value)
    {
        Log.warn("CommissionEditor -> setValue(): value is " + value);

        chain.detach(subEditor);

        commissionType.setValue(value.getCommissionType());

        if(value.getCommissionType() != null)
        {
            switch(value.getCommissionType())
            {
                case UNIT_RATE:
                    Log.info("UNIT_RATE");
                    subEditor = new UnitRateCommissionEditor();
                    break;
                case STANDING_CHARGE:
                    Log.info("STANDING_CHARGE");
                    subEditor = new StandingChargeCommissionEditor();
                    break;
                case PER_MWH:
                    Log.info("PER_MWH");
                    // TODO
                    break;
                case SINGLE_PAYMENT:
                    Log.info("SINGLE_PAYMENT");
                    // TODO
                    break;
            }

            this.value = value;
            subEditorPanel.clear();
//            subEditor.setValue(value);
            subEditorPanel.add(subEditor);
            chain.attach(value, subEditor);
        }

    }

//    @Override
//    public Commission getValue()
//    {
//        if(subEditor != null)
//        {
//            return subEditor.getValue();
//        }
//        else
//        {
//        return value;
//        }
//    }

    @Override
    public void flush()
    {
        this.value = chain.getValue(subEditor);
    }

    @Override
    public void setEditorChain(EditorChain<Commission, Editor<Commission>> chain)
    {
        this.chain = chain;
    }

    @Override
    public Editor<Commission> createEditorForTraversal()
    {
        return subEditor;
    }

    @Override
    public String getPathElement(Editor<Commission> commissionEditor)
    {
        return "";
    }

    @Override
    public void onPropertyChange(String... strings)
    {

    }

    @Override
    public void setDelegate(EditorDelegate<Commission> editorDelegate)
    {

    }

}

这是定义每个子编辑器的合同的IsCommissionEditorWidget 接口,也可以添加到面板中:

public interface IsCommissionEditorWidget extends Editor<Commission>, IsWidget
{

}

UnitRateCommissionEditor

当用户选择CommissionType.UNIT_RATE时,我想将其添加到编辑器链中以应用于剩余的3个字段:

public class UnitRateCommissionEditor extends Composite implements IsCommissionEditorWidget
{
    interface Binder extends UiBinder<Widget, UnitRateCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPenceBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public UnitRateCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

//    @Override
//    public void setValue(Commission commission)
//    {
//        amount.setValue(commission.getAmount());
//        multiplier.setValue(commission.getMultiplier());
//        contractMonths.setValue(commission.getContractMonths());
//    }
//
//    @Override
//    public Commission getValue()
//    {
//        return new Commission(CommissionType.UNIT_RATE, amount.getValue(), multiplier.getValue(), contractMonths.getValue());
//    }
}

StandingChargeCommissionEditor

CommissionType.STANDING_CHARGE被选中时我想要这个(UiBinders也有点不同,但主要区别是MoneyPoundsBox而不是MoneyPenceBox):

public class StandingChargeCommissionEditor extends Composite implements IsCommissionEditorWidget
{
    interface Binder extends UiBinder<Widget, StandingChargeCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPoundsBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public StandingChargeCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

//    @Override
//    public void setValue(Commission commission)
//    {
//        amount.setValue(commission.getAmount());
//        multiplier.setValue(commission.getMultiplier());
//        contractMonths.setValue(commission.getContractMonths());
//    }
//
//    @Override
//    public Commission getValue()
//    {
//        return new Commission(CommissionType.STANDING_CHARGE, amount.getValue(), multiplier.getValue(), contractMonths.getValue());
//    }
}

当前父类型的flush()(正在编辑的类型包含Commission)返回一个带有未定义amountmultipliercontractMonths 的委员会。我可以让这些值传入和传出的唯一方法是手动将其编码(注释代码)。

  • 我的副编辑是否正确附加到EditorChain

编辑 1:提出的解决方案

我决定创建一个新的中间类来分别包装每个子类型的佣金,using AbstractSubTypeEditor like I did in this question

委员会编辑

仍然是CompositeEditor,但它只有一个或零个子编辑器,它只会是CommissionSubtypeEditor

public class CommissionEditor extends Composite implements CompositeEditor<Commission, Commission, CommissionSubtypeEditor>, LeafValueEditor<Commission>
{
    interface Binder extends UiBinder<HTMLPanel, CommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    @Ignore
    CommissionTypeEditor commissionType;

    @UiField
    Panel subEditorPanel;

    private EditorChain<Commission, CommissionSubtypeEditor> chain;

    @Ignore
    @Path("")
    CommissionSubtypeEditor subEditor = new CommissionSubtypeEditor();

    private Commission value;

    public CommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));

        commissionType.box.addValueChangeHandler(event -> setValue(new Commission(event.getValue())));
    }

    @Override
    public void setValue(Commission value)
    {
        Log.warn("CommissionEditor -> setValue(): value is " + value);

        commissionType.setValue(value.getCommissionType());

        if(value.getCommissionType() != null)
        {
            this.value = value;
            subEditorPanel.clear();
            subEditorPanel.add(subEditor);
            chain.attach(value, subEditor);
        }

    }

    @Override
    public Commission getValue()
    {
        Log.info("CommissionEditor -> getValue: " + value);
        return value;
    }

    @Override
    public void flush()
    {
        chain.getValue(subEditor);
    }

    @Override
    public void setEditorChain(EditorChain<Commission, CommissionSubtypeEditor> chain)
    {
        this.chain = chain;
    }

    @Override
    public CommissionSubtypeEditor createEditorForTraversal()
    {
        return subEditor;
    }

    @Override
    public String getPathElement(CommissionSubtypeEditor commissionEditor)
    {
        return "";
    }

    @Override
    public void onPropertyChange(String... strings)
    {

    }

    @Override
    public void setDelegate(EditorDelegate<Commission> editorDelegate)
    {

    }

}

AbstractSubTypeEditor

这门课的功劳归Florent Bayle。我不认为我可以在没有多态子类型的情况下使用它,但它似乎工作得很好。本质上允许包装子编辑器,接下来将在CommissionSubtypeEditor 中显示。

public abstract class AbstractSubTypeEditor<T, C extends T, E extends Editor<C>> implements CompositeEditor<T, C, E>, LeafValueEditor<T>
{
    private EditorChain<C, E> chain;
    private T currentValue;
    private final E subEditor;

    public AbstractSubTypeEditor(E subEditor)
    {
        this.subEditor = subEditor;
    }

    @Override
    public E createEditorForTraversal()
    {
        return subEditor;
    }

    @Override
    public void flush()
    {
        currentValue = chain.getValue(subEditor);
    }

    @Override
    public String getPathElement(E subEditor)
    {
        return "";
    }

    @Override
    public T getValue()
    {
        return currentValue;
    }

    @Override
    public void onPropertyChange(String... paths)
    {
    }

    @Override
    public void setDelegate(EditorDelegate<T> delegate)
    {
    }

    @Override
    public void setEditorChain(EditorChain<C, E> chain)
    {
        this.chain = chain;
    }

    public void setValue(T value, boolean instanceOf)
    {
        if(currentValue != null && value == null)
        {
            chain.detach(subEditor);
        }
        currentValue = value;
        if(value != null && instanceOf)
        {
            chain.attach((C) value, subEditor);
        }
    }
}

CommissionSubtypeEditor

public class CommissionSubtypeEditor extends Composite implements Editor<Commission>
{

    interface Binder extends UiBinder<HTMLPanel, CommissionSubtypeEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    Panel subEditorPanel;

    @Ignore
    final UnitRateCommissionEditor unitRateCommissionEditor = new UnitRateCommissionEditor();

    @Path("")
    final AbstractSubTypeEditor<Commission, Commission, UnitRateCommissionEditor> unitRateWrapper = new AbstractSubTypeEditor<Commission, Commission,
            UnitRateCommissionEditor>(unitRateCommissionEditor)
    {
        @Override
        public void setValue(Commission value)
        {
            if(value.getCommissionType() == CommissionType.UNIT_RATE)
            {
                Log.info("unitRateWrapper setValue");
                setValue(value, true);

                subEditorPanel.clear();
                subEditorPanel.add(unitRateCommissionEditor);

            }
        }
    };

    @Ignore
    final StandingChargeCommissionEditor standingChargeCommissionEditor = new StandingChargeCommissionEditor();

    @Path("")
    final AbstractSubTypeEditor<Commission, Commission, StandingChargeCommissionEditor> standingChargeWrapper = new AbstractSubTypeEditor<Commission,
            Commission, StandingChargeCommissionEditor>(standingChargeCommissionEditor)
    {
        @Override
        public void setValue(Commission value)
        {
            if(value.getCommissionType() == CommissionType.STANDING_CHARGE)
            {
                Log.info("standingChargeWrapper setValue");
                setValue(value, true);

                subEditorPanel.clear();
                subEditorPanel.add(standingChargeCommissionEditor);

            }
        }
    };

    public CommissionSubtypeEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

UnitRateCommissionEditor 和 StandingChargeCommissionEditor

既简单又实用Editor&lt;Commission&gt;

public class UnitRateCommissionEditor extends Composite implements Editor<Commission>
{
    interface Binder extends UiBinder<Widget, UnitRateCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPenceBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public UnitRateCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

差不多了……

public class StandingChargeCommissionEditor extends Composite implements Editor<Commission>
{
    interface Binder extends UiBinder<Widget, StandingChargeCommissionEditor>
    {
    }

    private static Binder uiBinder = GWT.create(Binder.class);

    @UiField
    MoneyPoundsBox amount;

    @UiField
    IntegerBox multiplier;

    @UiField
    IntegerBox contractMonths;

    public StandingChargeCommissionEditor()
    {
        initWidget(uiBinder.createAndBindUi(this));
    }

}

这确实有效,并且类似于我很早就在CompositeEditor 中使用AbstractSubtypeEditors 时尝试的方法。我认为那里的问题是编辑无法自行调用setValue()。我说的对吗?

非常感谢您提出意见、批评和建议。

【问题讨论】:

  • 你在哪里初始化 editorDriver。这是一个非常普遍的问题。如果用于初始化的 editorDriver 调用无权访问子编辑器(看不到它),则刷新 editorDriver 时不会刷新它。
  • 它只是在与编辑器相同的包中的演示者/视图中。我认为这不是能否看到它的问题——认为一旦它连接到链条上就应该看到它,这就是问题所在。可能我不能同时用父编辑器和子编辑器编辑同一个实体,所以我需要为下拉框创建一个包装器……可以试试。
  • 我对处理不同类型的广告实体做同样的事情,但正如@colin-alworth 提到的,我在抽象类中使用 ValueAwareEditor。您确实必须处理刷新和设置,但为了能够动态添加编辑器的简单性,这是一个小的折衷。
  • 我会用相应的 getValue 和 setValue 实现来实现类似 LeafValueEditor 和 HasSelectionHandlers 的东西。
  • 伙计们,我以另一种方式完成了它,如果您愿意贡献,我们将不胜感激:)

标签: java gwt uibinder gwt-editors


【解决方案1】:

您的复合编辑器被声明为CompositeEditor&lt;Commission, Commission, Editor&lt;Commission&gt;&gt;,这意味着该链将有望提供一些任意的Editor&lt;Commission&gt;。这是一个问题,因为编译器检查了 Editor&lt;Commission&gt; 类型,但没有看到子编辑器,也没有其他编辑器接口(@98​​7654324@、ValueAwareEditor 等),所以没有绑定任何东西。

您提到您有两种不同的 Editor&lt;Commission&gt; 子类型 - 但代码生成器无法提前知道这一点,并且检查每个可能的子类型并构建任何可能适合的接线是没有意义的。无论好坏,编辑器框架都是静态的 - 预先声明所有内容,然后生成器将只创建所需的内容。

我看到的两个选项:

  • 要么创建两个不同的 CompositeEditor,每个子编辑器类型一个,并确保一次只附加一个,或者
  • 从两个编辑器中提取一个通用的超类型/接口,它们具有一致的命名和类型化方法,这些方法返回相同的编辑器类型(出于与上述相同的原因,永远不会简单地返回Editor&lt;Foo&gt;)。这可能会更难做到,但您可以使用ValueAwareEditor 将事情结束,并使用setValueflush() 来记录细节。

【讨论】:

  • 非常感谢您的回复。我声明了CompositeEditor&lt;Commission, Commission, Editor&lt;Commission&gt;&gt;,因为我正在复制具有CompositeEditor&lt;QuestionDataProxy, QuestionDataProxy, Editor&lt;QuestionDataProxy&gt;&gt; 的另一个问题,但我想这可以解释为什么他说他的flush() 方法不起作用。如果我将IsCommissionEditor 接口更改为基类,然后声明CompositeEditor&lt;Commission, Commission, BaseCommissionEditorWidget&gt; 应该可以吗?我试试……
  • 如果有更多问题尝试,请使用BaseCommissionEditorWidget 的正文和任何子类更新问题(可能在---- 下)。
  • 我确实尝试让我的所有子类型都实现BaseCommissionEditorWidget,但由于某种原因,我仍然遇到了同样的问题。但是,您对需要具体类的代码生成器的解释使我意识到我可以在新的具体类中执行逻辑 (CommissionSubtypeEditor) ...我已经在上面发布了我的解决方案,希望它不会太冗长/笨拙。好吧,毕竟是 GWT ;))) 一如既往地感谢科林。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 2013-07-04
  • 2014-06-10
  • 2021-06-29
  • 1970-01-01
相关资源
最近更新 更多