【问题标题】:How to combine multiple uiBinder-based widgets?如何组合多个基于 uiBinder 的小部件?
【发布时间】:2010-05-12 19:49:22
【问题描述】:

我需要将 [数量] 个基于 uiBinder 的小部件插入到另一个特定位置的小部件中。插入的小部件的布局有些复杂,所以我试图在 HTML 中定义它。

referencePanel.add(...) 失败并出现 java.lang.IllegalStateException:此小部件的父级未实现 HasWidgets。不知道它对哪个小部件的父级不满意 - innerPanel 或 referencePanel。

如果 ReferenceUI 对象被添加到 RootPanel,然后它被添加到页面底部。但如果先添加到 RootPanel, 然后在添加到 referencePanel 时会出现 JavaScriptException Code 3 (HIERARCHY_REQUEST_ERR)。

有什么建议吗?

public class AppUIDemo extends Composite {
    @UiTemplate("AppUIDemo.ui.xml")
    interface AppUIDemoUiBinder extends UiBinder<Widget, AppUIDemo> {
    }

    @UiTemplate("ReferenceUI.ui.xml")
    interface ReferenceUIUiBinder extends
            UiBinder<Widget, ReferenceUI> {
    }

    private static AppUIDemoUiBinder uiBinder = GWT
            .create(AppUIDemoUiBinder.class);
    private static ReferenceUIUiBinder refUIBinder = GWT
            .create(ReferenceUIUiBinder.class);

    @UiField
    FlowPanel referencePanel;

    public AppUIDemo() {
            initWidget(uiBinder.createAndBindUi(this));
            ReferenceUI reference = new ReferenceUI(refUIBinder);

            HTMLPanel innerPanel = reference.getRefPanel();
            innerPanel.getElement().setId(HTMLPanel.createUniqueId());
            referencePanel.add(innerPanel);
        }
}

 

public class ReferenceUI extends Composite {

    interface ReferenceUIUiBinder extends
            UiBinder<Widget,ReferenceUI> {
    }

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


    @UiField
HTMLPanel refPanel;

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

    public CreditReferenceUI(final UiBinder<Widget, CreditReferenceUI> binder) {
        initWidget(binder.createAndBindUi(this));
    }

    public HTMLPanel getRefPanel() {
        return refPanel;
    }
}

参考UI.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:gwittir="urn:import:com.totsp.gwittir.client.ui">
            <g:HTMLPanel ui:field="referencePanel">
            <table>
            <tr>
                <td>
                    <b>First Name</b></td>
                <td>
                    <b>Last Name</b></td>
                <td>
                    <b>Phone</b></td>
                <td>
                    <b>Fax</b></td>
            </tr>
            <tr>
                <td>
                    <gwittir:TextBox ui:field="referenceFirstName" styleName="input"/></td>
                <td>
                    <gwittir:TextBox ui:field="referenceLastName" styleName="input"/></td>
                <td>
                    <table><tr>
            <td> ( </td> <td>
                <gwittir:TextBox ui:field="referencePhoneAreaCode" styleName="input" maxLength="3"/></td>
                <td> ) </td> <td>
                <gwittir:TextBox ui:field="referencePhoneNumber" styleName="input" maxLength="7"/></td>
            <td> # </td> <td>
                <gwittir:TextBox ui:field="referencePhoneExtension" styleName="input" maxLength="25"/></td>
        </tr></table></td>
                <td>
                     <table><tr>
            <td> ( </td> <td>
                <gwittir:TextBox ui:field="referenceFaxAreaCode" styleName="input" maxLength="3"/></td>
                <td> ) </td> <td>
                <gwittir:TextBox ui:field="referenceFaxNumber" styleName="input" maxLength="7"/></td>
        </tr></table></td>
                </tr>
            <tr>
                <td style="text-align:right">
                    <b>Address: </b> Street</td>
                <td>
                    <gwittir:TextBox ui:field="referenceStreet" styleName="input"/></td>
                <td colspan="2" style="width:50%">
                    <table><tr><td>   City</td>
                    <td><gwittir:TextBox ui:field="referenceCity" styleName="input" maxLength="25"/></td>
                    <td> State </td>
                    <td class="state"><gwittir:TextBox ui:field="referenceState" styleName="input" maxLength="2"/></td>
                    <td> ZIP</td>
                    <td><gwittir:TextBox ui:field="referenceZIP" styleName="input" maxLength="9"/></td></tr></table>
                </td>
            </tr>
        </table>
    </g:HTMLPanel>
</ui:UiBinder>

AppUIDemo.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:gwittir="urn:import:com.totsp.gwittir.client.ui">
    <g:HTMLPanel ui:field="basePanel">
        <!--  <div id="MainContent">  -->
        <p><h2><b>Application Demo</b></h2></p>

        <g:FlowPanel ui:field="referencePanel">
        </g:FlowPanel>
    </g:HTMLPanel>
</ui:UiBinder>

【问题讨论】:

  • 您确定为 ReferenceUI 组合定义了 id 吗? (或者您确定您的 ReferencePanel 中有一个具有适当 id 的持有人?)我在代码中看不到任何内容。顺便说一句,你能提供 UiBinder 代码吗?
  • *.ui.xml 中的参考面板定义为 。我将如何定义复合材料的 id - 你能举个例子吗?本地没有UiBinder代码,UiBinder是从com.google.gwt.uibinder.client.UiBinder导入的。
  • 能否把 AppUIDemo 和 ReferenceUI 的 UiBinder 模板贴出来?很高兴看到小部件的层次结构是什么样的。
  • ...实际上,你怎么能打电话给new ReferenceUI(refUIBinder);?这是ClientReferenceUI 的错字吗?
  • 层次结构中没有ClientReferenceUI

标签: java xml gwt widget uibinder


【解决方案1】:

我将从修复开始,然后继续解释它。

解决问题

解决此问题的最简单方法如下。这是你的代码:

HTMLPanel innerPanel = reference.getRefPanel();
innerPanel.getElement().setId(HTMLPanel.createUniqueId());
referencePanel.add(innerPanel);

将其替换为以下代码。请注意,只有最后一行发生了变化。

HTMLPanel innerPanel = reference.getRefPanel();
innerPanel.getElement().setId(HTMLPanel.createUniqueId());
referencePanel.add(reference);

这样,您将添加Composite 对象。对用户来说没有区别,因为HTMLPanel(您的innerPanel)将直接附加到文档中。


一些背景

向复杂面板添加小部件

当您将小部件添加到复杂面板(包含多个子小部件的面板)时,会依次发生四件事:

  1. 小部件被告知要从其当前父级中移除自己
  2. 面板将小部件添加到其子级列表中
  3. 面板将小部件添加到文档中
  4. 小部件被告知将面板设置为其新父级

告诉一个小部件将自己从其父级中移除

当孩子被告知要从其父母中移除自己时,会发生以下情况之一:

  • 如果小部件没有父级,它什么也不做
  • 如果小部件是实现HasWidgets 的面板的子级,则小部件会告诉面板删除该小部件
  • 否则,小部件会抛出 IllegalStateException 并显示消息“此小部件的父级未实现 HasWidgets

复合小部件

调用initWidget(Widget) 时,小部件的父级设置为Composite 对象。

问题

当您尝试添加innerPanel 时,它会被告知从其当前父级中删除自己。 innerPanel 实际上是你的 UiBinder 模板的根。它的父对象是Composite 对象(特别是ReferenceUI)。这会导致抛出异常,因为 Composite 没有实现 HasWidgets 并且不支持删除其小部件。

【讨论】:

  • +1 很好,你没看错 - 我实际上在阅读你的答案之前编辑了我的答案,结果我基本上写了同样的东西>_
  • 非常感谢您提供有效的答案和详细的解释。
  • 很高兴它成功了,jprusakova。并赞成你的答案伊戈尔 - 似乎伟大的思想都一样!
【解决方案2】:

不幸的是,IIRC 您不能在 UiBinder 的代码中为 Widget 设置 id(我认为您只能用于普通 HTML)。因此,您可以通过 someWidget.getElement().setId() 设置正确的 id(就像您在上面的代码中所做的那样)。

我认为现在缺少的是在HTMLPanel referencePanel 中具有正确 id 的占位符(一个 div、span 等等),如下所示:

<g:HTMLPanel ui:field="referencePanel">
    <div ui:field="referencePanelInner" />
</g:HTMLPanel>

AppUIDemo:

@UiField
DivElement referencePanelInner;
// ...
public AppUIDemo() {
    // ...
    referencePanelInner.setId(reference.getRefPanelId());
}

...除非您想将 ReferenceUI 直接添加到 referencePanel - 在这种情况下您应该只使用 FlowPanel :)

PS:恕我直言,您应该从ReferenceUI 类生成并设置ReferenceUI.refPanel 的唯一ID(并公开ID)-这样您就不会从某些外部小部件中弄乱小部件的“内部” .


好的,我想我明白了。 IllegalStateException 异常被抛出,因为您将ReferenceUI.refPanel(或ReferenceUI.referencePanel,我不知道哪个是当前名称)添加到AppUIDemoReferenceUI 显然没有实现HasWidgets) -当您应该添加整个 ReferenceUI reference 复合材料时:) 我不知道您为什么首先这样做(可能是因为整个 id 混乱),但代码应该看起来像这样:

public AppUIDemo() {
        initWidget(uiBinder.createAndBindUi(this));
        ReferenceUI reference = new ReferenceUI(refUIBinder);

        referencePanel.add(reference);
    }

【讨论】:

  • 我将 referencePanel 更改为 FlowPanel。 FlowPanel.add() 不带 id 参数,只是要添加的小部件:referencePanel.add(reference);现在出现不同的错误:java.lang.IllegalStateException:此小部件的父级未实现 HasWidgets。您知道它对哪个小部件的父级不满意 - innerPanel 还是 referencePanel?
  • 它应该指向发生异常的行 - 什么? HTMLPanelFlowPanel 当然都实现了HasWidgets,所以这意味着问题出在你的代码上——你能发布当前的 *.ui.xml 文件吗?
  • 异常指向生成的 JavaScript 代码,有什么方法可以追溯到 Java 源代码?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多