我有一个值类型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
类型,由于某种原因,同样的方法似乎不适用于编辑相同具体类型的多个编辑器。
我目前有两个子编辑(通过自定义界面Editor<Commission>
实现IsWidget
和IsCommissionEditorWidget
),但它们本身有不同的子编辑器,Money
可以是便士或磅,乘数可以代表天或月,以及其他变化。
我查看了this question中的类似问题并尝试创建CompositeEditor<Commission, Commission, Editor<Commission>>
。
这是我到目前为止所做的事情(请注意,通过实施LeafValueEditor<Commission>
并手动调用setValue()
和{{1,注释掉的部分是获取我想要的功能的黑客方式在getValue()
,amount
和multiplier
):
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
{
}
时,我想将其添加到编辑器链中以应用于其余3个字段:
CommissionType.UNIT_RATE
选择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());
// }
}
时我想要这个(UiBinder也有点不同,但主要区别在于CommissionType.STANDING_CHARGE
而不是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
,amount
和{的委员会{1}}。我可以将这些值传入和传出的唯一方法是手动编写代码(注释代码)。
multiplier
?我决定创建一个新的中间类,它将分别包装每个子类型委托using AbstractSubTypeEditor
like I did in this question。
还是contractMonths
,但它只有一个或零个子编辑,它们只会是EditorChain
:
CompositeEditor
此课程的学分为Florent Bayle。我没想到我可以使用它而没有子类型是多态的,但似乎工作得很好。基本上允许包装子编辑器,如下面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)
{
}
}
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);
}
}
}
:
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));
}
}
差不多......
Editor<Commission>
这确实有效,类似于我在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));
}
}
时很早就尝试过的事情。我认为问题在于编辑无法自行调用AbstractSubtypeEditor
。我是对的吗?
答案 0 :(得分:2)
您的复合编辑器声明为CompositeEditor<Commission, Commission, Editor<Commission>>
,这意味着该链预计会提供一些任意Editor<Commission>
。这是一个问题,因为编译器检查类型Editor<Commission>
并且没有看到子编辑器,也没有看到其他编辑器接口(LeafValueEditor
,ValueAwareEditor
等),所以不对它进行任何绑定。
您提到您有两种不同的Editor<Commission>
子类型 - 但代码生成器无法提前知道这一点,检查每个可能的子类型并构建任何可能的布线都没有意义这可能适合。无论好坏,编辑器框架都是静态的 - 在前面声明所有内容,然后生成器将只创建所需的内容。
我看到两个选项:
Editor<Foo>
)。这可能会更难做到,但您可以使用ValueAwareEditor
进行整理,并使用setValue
和flush()
来详细说明。