如何在 GWT2 中进行嵌套编辑器?

发布于 2025-01-07 13:15:48 字数 9471 浏览 0 评论 0原文

您能给我嵌套编辑器的工作示例吗?我已阅读文档,但它对我没有帮助。在我的代码中,我有类 PersonOrganization

Organization 具有 Person 类型的字段 contactPerson

所以我为 Person 创建了以下编辑器:

public class PersonEditor extends Composite implements Editor<PersonProxy>
{
    interface PersonEditorUiBinder extends UiBinder<Widget, PersonEditor>
    {
    }

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

    @UiField
    ValueBoxEditorDecorator<String> name;
    @UiField
    ValueBoxEditorDecorator<String> phoneNumber;
    @UiField
    ValueBoxEditorDecorator<String> email;

    @UiField
    CaptionPanel captionPanel;

    public void setCaptionText(String captionText)
    {
        captionPanel.setCaptionText(captionText);
    }

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

其相应的 .ui.xml 是

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:e='urn:import:com.google.gwt.editor.ui.client'

             ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
             ui:generateKeys="com.google.gwt.i18n.server.keygen.MD5KeyGenerator"
             ui:generateLocales="en,ru">
    <ui:style src="../common.css"/>
    <g:CaptionPanel captionText="Test" ui:field="captionPanel">
        <g:HTMLPanel>
            <table class="{style.forform}">
                <tr>
                    <th class="{style.forform}">
                        <div>
                            <ui:msg meaning="person's name">Name:</ui:msg>
                        </div>
                    </th>
                    <td class="{style.forform}">
                        <e:ValueBoxEditorDecorator ui:field="name" stylePrimaryName="{style.forform}">
                            <e:valuebox>
                                <g:TextBox stylePrimaryName="{style.forform}"/>
                            </e:valuebox>
                        </e:ValueBoxEditorDecorator>
                    </td>
                </tr>
                <tr>
                    <th class="{style.forform}">
                        <div>
                            <ui:msg>Phone Number:</ui:msg>
                        </div>
                    </th>
                    <td class="{style.forform}">
                        <e:ValueBoxEditorDecorator ui:field="phoneNumber" stylePrimaryName="{style.forform}">
                            <e:valuebox>
                                <g:TextBox width="100%" stylePrimaryName="{style.forform}"/>
                            </e:valuebox>
                        </e:ValueBoxEditorDecorator>
                    </td>
                </tr>
                <tr>
                    <th class="{style.forform}">
                        <div>
                            <ui:msg>EMail:</ui:msg>
                        </div>
                    </th>
                    <td class="{style.forform}">
                        <e:ValueBoxEditorDecorator ui:field="email" stylePrimaryName="{style.forform}">
                            <e:valuebox>
                                <g:TextBox width="100%" stylePrimaryName="{style.forform}"/>
                            </e:valuebox>
                        </e:ValueBoxEditorDecorator>
                    </td>
                </tr>
            </table>
        </g:HTMLPanel>
    </g:CaptionPanel>
</ui:UiBinder>

它工作得很好。

这是组织的编辑器:

public class OrganizationEditor extends Composite implements Editor<OrganizationProxy>
{
    interface OrganizationEditorUiBinder extends UiBinder<Widget, OrganizationEditor>
    {
    }

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

    @UiField
    CaptionPanel captionPanel;

    @UiField
    ValueBoxEditorDecorator<String> name;

    @UiField
    ValueBoxEditorDecorator<String> address;

    @UiField
    PersonEditor personEditor;

    public void setCaptionText(String captionText)
    {
        captionPanel.setCaptionText(captionText);
    }

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

其相应的 .ui.xml 是

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:e='urn:import:com.google.gwt.editor.ui.client'
             xmlns:c='urn:import:com.zasutki.courierApp.client.customer'
             xmlns:myui='urn:import:com.zasutki.courierApp.client.ui'

             ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
             ui:generateKeys="com.google.gwt.i18n.server.keygen.MD5KeyGenerator"
             ui:generateLocales="en,ru">
    <ui:style src="../common.css"/>
    <g:CaptionPanel ui:field="captionPanel">
        <myui:VerticalFlowPanel>
            <g:HTMLPanel>
                <table class="{style.forform}">
                    <tr>
                        <th class="{style.forform}">
                            <div>
                                <ui:msg meaning="Name of organization">Name:</ui:msg>
                            </div>
                        </th>
                        <td class="{style.forform}">
                            <e:ValueBoxEditorDecorator ui:field="name" stylePrimaryName="{style.forform}">
                                <e:valuebox>
                                    <g:TextBox stylePrimaryName="{style.forform}"/>
                                </e:valuebox>
                            </e:ValueBoxEditorDecorator>
                        </td>
                    </tr>
                    <tr>
                        <th class="{style.forform}">
                            <div>
                                <ui:msg>Address:</ui:msg>
                            </div>
                        </th>
                        <td class="{style.forform}">
                            <e:ValueBoxEditorDecorator ui:field="address" stylePrimaryName="{style.forform}">
                                <e:valuebox>
                                    <g:TextBox stylePrimaryName="{style.forform}"/>
                                </e:valuebox>
                            </e:ValueBoxEditorDecorator>
                        </td>
                    </tr>
                </table>
                <c:PersonEditor ui:field="personEditor" captionText="Contact person">
                    <ui:attribute name="captionText"/>
                </c:PersonEditor>
            </g:HTMLPanel>
        </myui:VerticalFlowPanel>
    </g:CaptionPanel>
</ui:UiBinder>

组织代理的接口

@ProxyFor(value = Organization.class, locator = ObjectifyLocator.class)
public interface OrganizationProxy extends EntityProxy
{
    public String getName();
    public void setName(String name);
    public String getAddress();
    public void setAddress(String address);
    public PersonProxy getContactPerson();
    public void setContactPerson(PersonProxy contactPerson);
}

,最后这里是使用上述所有内容的类

public class NewOrderView extends Composite
{
    interface Binder extends UiBinder<Widget, NewOrderView>
    {
    }

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

    // Empty interface declaration, similar to UiBinder
    interface OrganizationDriver extends SimpleBeanEditorDriver<OrganizationProxy, OrganizationEditor>
    {
    }

    OrganizationDriver driver = GWT.create(OrganizationDriver.class);

    @UiField
    Button save;

    @UiField
    OrganizationEditor orgEditor;

    OrganizationProxy organizationProxy;

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

        organizationProxy = createFactory().contextOrder().create(OrganizationProxy.class);

        // Initialize the driver with the top-level editor
        driver.initialize(orgEditor);

        // Copy the data in the object into the UI
        driver.edit(organizationProxy);
    }

    @UiHandler("save")
    void buttonClick(ClickEvent e)
    {
        e.stopPropagation();

        OrganizationProxy edited = driver.flush();
        PersonProxy person = edited.getContactPerson();
        // person is always null !!!
        if (driver.hasErrors())
        {
        }
    }
}

问题是为什么嵌套编辑器(PersonEditor)不会自动刷新?它应该发生吗?正确的解决方案是什么?

Сould you please give me working example of nested editors ? I've read this document but it didn't help me. In my code I have class Person and Organization.

Organization has field contactPerson of a type Person.

So I created following editor for Person:

public class PersonEditor extends Composite implements Editor<PersonProxy>
{
    interface PersonEditorUiBinder extends UiBinder<Widget, PersonEditor>
    {
    }

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

    @UiField
    ValueBoxEditorDecorator<String> name;
    @UiField
    ValueBoxEditorDecorator<String> phoneNumber;
    @UiField
    ValueBoxEditorDecorator<String> email;

    @UiField
    CaptionPanel captionPanel;

    public void setCaptionText(String captionText)
    {
        captionPanel.setCaptionText(captionText);
    }

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

its corresponding .ui.xml is

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:e='urn:import:com.google.gwt.editor.ui.client'

             ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
             ui:generateKeys="com.google.gwt.i18n.server.keygen.MD5KeyGenerator"
             ui:generateLocales="en,ru">
    <ui:style src="../common.css"/>
    <g:CaptionPanel captionText="Test" ui:field="captionPanel">
        <g:HTMLPanel>
            <table class="{style.forform}">
                <tr>
                    <th class="{style.forform}">
                        <div>
                            <ui:msg meaning="person's name">Name:</ui:msg>
                        </div>
                    </th>
                    <td class="{style.forform}">
                        <e:ValueBoxEditorDecorator ui:field="name" stylePrimaryName="{style.forform}">
                            <e:valuebox>
                                <g:TextBox stylePrimaryName="{style.forform}"/>
                            </e:valuebox>
                        </e:ValueBoxEditorDecorator>
                    </td>
                </tr>
                <tr>
                    <th class="{style.forform}">
                        <div>
                            <ui:msg>Phone Number:</ui:msg>
                        </div>
                    </th>
                    <td class="{style.forform}">
                        <e:ValueBoxEditorDecorator ui:field="phoneNumber" stylePrimaryName="{style.forform}">
                            <e:valuebox>
                                <g:TextBox width="100%" stylePrimaryName="{style.forform}"/>
                            </e:valuebox>
                        </e:ValueBoxEditorDecorator>
                    </td>
                </tr>
                <tr>
                    <th class="{style.forform}">
                        <div>
                            <ui:msg>EMail:</ui:msg>
                        </div>
                    </th>
                    <td class="{style.forform}">
                        <e:ValueBoxEditorDecorator ui:field="email" stylePrimaryName="{style.forform}">
                            <e:valuebox>
                                <g:TextBox width="100%" stylePrimaryName="{style.forform}"/>
                            </e:valuebox>
                        </e:ValueBoxEditorDecorator>
                    </td>
                </tr>
            </table>
        </g:HTMLPanel>
    </g:CaptionPanel>
</ui:UiBinder>

It works nicely.

Here is editor for Organization:

public class OrganizationEditor extends Composite implements Editor<OrganizationProxy>
{
    interface OrganizationEditorUiBinder extends UiBinder<Widget, OrganizationEditor>
    {
    }

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

    @UiField
    CaptionPanel captionPanel;

    @UiField
    ValueBoxEditorDecorator<String> name;

    @UiField
    ValueBoxEditorDecorator<String> address;

    @UiField
    PersonEditor personEditor;

    public void setCaptionText(String captionText)
    {
        captionPanel.setCaptionText(captionText);
    }

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

and its corresponding .ui.xml is

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
             xmlns:g='urn:import:com.google.gwt.user.client.ui'
             xmlns:e='urn:import:com.google.gwt.editor.ui.client'
             xmlns:c='urn:import:com.zasutki.courierApp.client.customer'
             xmlns:myui='urn:import:com.zasutki.courierApp.client.ui'

             ui:generateFormat='com.google.gwt.i18n.rebind.format.PropertiesFormat'
             ui:generateKeys="com.google.gwt.i18n.server.keygen.MD5KeyGenerator"
             ui:generateLocales="en,ru">
    <ui:style src="../common.css"/>
    <g:CaptionPanel ui:field="captionPanel">
        <myui:VerticalFlowPanel>
            <g:HTMLPanel>
                <table class="{style.forform}">
                    <tr>
                        <th class="{style.forform}">
                            <div>
                                <ui:msg meaning="Name of organization">Name:</ui:msg>
                            </div>
                        </th>
                        <td class="{style.forform}">
                            <e:ValueBoxEditorDecorator ui:field="name" stylePrimaryName="{style.forform}">
                                <e:valuebox>
                                    <g:TextBox stylePrimaryName="{style.forform}"/>
                                </e:valuebox>
                            </e:ValueBoxEditorDecorator>
                        </td>
                    </tr>
                    <tr>
                        <th class="{style.forform}">
                            <div>
                                <ui:msg>Address:</ui:msg>
                            </div>
                        </th>
                        <td class="{style.forform}">
                            <e:ValueBoxEditorDecorator ui:field="address" stylePrimaryName="{style.forform}">
                                <e:valuebox>
                                    <g:TextBox stylePrimaryName="{style.forform}"/>
                                </e:valuebox>
                            </e:ValueBoxEditorDecorator>
                        </td>
                    </tr>
                </table>
                <c:PersonEditor ui:field="personEditor" captionText="Contact person">
                    <ui:attribute name="captionText"/>
                </c:PersonEditor>
            </g:HTMLPanel>
        </myui:VerticalFlowPanel>
    </g:CaptionPanel>
</ui:UiBinder>

interface for proxy of Organization is

@ProxyFor(value = Organization.class, locator = ObjectifyLocator.class)
public interface OrganizationProxy extends EntityProxy
{
    public String getName();
    public void setName(String name);
    public String getAddress();
    public void setAddress(String address);
    public PersonProxy getContactPerson();
    public void setContactPerson(PersonProxy contactPerson);
}

and finally here is class that uses all described above

public class NewOrderView extends Composite
{
    interface Binder extends UiBinder<Widget, NewOrderView>
    {
    }

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

    // Empty interface declaration, similar to UiBinder
    interface OrganizationDriver extends SimpleBeanEditorDriver<OrganizationProxy, OrganizationEditor>
    {
    }

    OrganizationDriver driver = GWT.create(OrganizationDriver.class);

    @UiField
    Button save;

    @UiField
    OrganizationEditor orgEditor;

    OrganizationProxy organizationProxy;

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

        organizationProxy = createFactory().contextOrder().create(OrganizationProxy.class);

        // Initialize the driver with the top-level editor
        driver.initialize(orgEditor);

        // Copy the data in the object into the UI
        driver.edit(organizationProxy);
    }

    @UiHandler("save")
    void buttonClick(ClickEvent e)
    {
        e.stopPropagation();

        OrganizationProxy edited = driver.flush();
        PersonProxy person = edited.getContactPerson();
        // person is always null !!!
        if (driver.hasErrors())
        {
        }
    }
}

The question is why nested editor (PersonEditor) doesn't get flushed automatically ? Is it supposed to happen ? What is the proper solution ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

星光不落少年眉 2025-01-14 13:15:48
 <e:ValueBoxEditorDecorator ui:field="contactPerson">
                    <e:valuebox>
                        <c:PersonEditor captionText="Contact person">
                            <ui:attribute name="captionText"/>
                        </c:PersonEditor>
                    </e:valuebox>
                </e:ValueBoxEditorDecorator>

这段代码抛出异常。 之后是 ValueBox 的子类型(例如 TextBox、DoubleBox,...)。您的 PersonEditor 不是 ValueBox(将其设为 ValueBox 是没有意义的)。因此,只需将您的 PersonEditor 添加到 OrganizationEditor 的 ui.xml 中,就像普通的 Widget 一样。

例如:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
    ....>
    <ui:style src="../common.css"/>
    <g:CaptionPanel ui:field="captionPanel">
        <myui:VerticalFlowPanel>
            <g:HTMLPanel>
                <table class="{style.forform}">
            // your other input fields
                </table>
            </g:HTMLPanel>

            // Add the PersonEditor to the FlowPanel
           <c:PersonEditor captionText="Contact person">
                <ui:attribute name="captionText"/>
           </c:PersonEditor>
            </myui:VerticalFlowPanel>
        </g:CaptionPanel>
    </ui:UiBinder>

在Java类中,更改

@UiField
    ValueBoxEditorDecorator<PersonEditor> contactPerson;

@UiField
    PersonEditor contactPerson;
 <e:ValueBoxEditorDecorator ui:field="contactPerson">
                    <e:valuebox>
                        <c:PersonEditor captionText="Contact person">
                            <ui:attribute name="captionText"/>
                        </c:PersonEditor>
                    </e:valuebox>
                </e:ValueBoxEditorDecorator>

This code throws the exception. After <e:valuebox> a sub-type of a ValueBox is expected (e.g. TextBox, DoubleBox,...). Your PersonEditor is not a ValueBox (and it makes no sense to make it one). So just add your PersonEditor in the OrganizationEditor's ui.xml like a normal Widget.

For example:

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
    ....>
    <ui:style src="../common.css"/>
    <g:CaptionPanel ui:field="captionPanel">
        <myui:VerticalFlowPanel>
            <g:HTMLPanel>
                <table class="{style.forform}">
            // your other input fields
                </table>
            </g:HTMLPanel>

            // Add the PersonEditor to the FlowPanel
           <c:PersonEditor captionText="Contact person">
                <ui:attribute name="captionText"/>
           </c:PersonEditor>
            </myui:VerticalFlowPanel>
        </g:CaptionPanel>
    </ui:UiBinder>

In the Java class, change

@UiField
    ValueBoxEditorDecorator<PersonEditor> contactPerson;

to

@UiField
    PersonEditor contactPerson;
节枝 2025-01-14 13:15:48

啊...我必须手动为 contactPerson 创建代理!

public class NewOrderView extends Composite
{
    public NewOrderView()
    {
        initWidget(uiBinder.createAndBindUi(this));

        AdminRequestFactory.OrderRequestContext orderRequestContext = createFactory().contextOrder();
        organizationProxy = orderRequestContext.create(OrganizationProxy.class);
        organizationProxy.setContactPerson(orderRequestContext.create(PersonProxy.class));

        // Initialize the driver with the top-level editor
        driver.initialize(orgEditor);

        // Copy the data in the object into the UI
        driver.edit(organizationProxy);
    }
}

Ah... I have to create proxy for contactPerson manually!

public class NewOrderView extends Composite
{
    public NewOrderView()
    {
        initWidget(uiBinder.createAndBindUi(this));

        AdminRequestFactory.OrderRequestContext orderRequestContext = createFactory().contextOrder();
        organizationProxy = orderRequestContext.create(OrganizationProxy.class);
        organizationProxy.setContactPerson(orderRequestContext.create(PersonProxy.class));

        // Initialize the driver with the top-level editor
        driver.initialize(orgEditor);

        // Copy the data in the object into the UI
        driver.edit(organizationProxy);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文