如何组合多个基于uiBinder的小部件?
我需要将[数量]个基于 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>
I need to insert a [number of] uiBinder-based widgets into another one, at a particular spot. The inserted widget has a somewhat complicated layout, so I am trying to define it in HTML.
referencePanel.add(...) fails with java.lang.IllegalStateException: This widget's parent does not implement HasWidgets. Don't know which widget's parent it's unhappy about - innerPanel or referencePanel.
If the ReferenceUI object is added to RootPanel, and then it's added to the bottom of the page. But if it's added to RootPanel first,
then there is a JavaScriptException Code 3 (HIERARCHY_REQUEST_ERR) when added to referencePanel.
Any suggestions?
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;
}
}
ReferenceUI.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>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我将从修复开始,然后继续解释。
解决问题
解决此问题的最简单方法如下。这是您的代码:
将其替换为以下代码。请注意,只有最后一行发生了变化。
这样,您就可以添加
Composite
对象。对于用户来说没有什么区别,因为HTMLPanel
(您的innerPanel
)将直接附加到文档中。一些背景
将小部件添加到复杂面板
当您将小部件添加到复杂面板(包含多个子小部件的面板)时,会依次发生四件事:
告诉小部件从其父级中删除自身
当子级被告知时要将其自身从其父级中删除,会发生以下情况之一:
HasWidgets
的面板的子级,则小部件会告诉面板删除该小部件IllegalStateException
并显示消息“此小部件的父级未实现 HasWidgets复合小部件
调用
initWidget(Widget)
时,小部件的父级设置为Composite
对象。问题
当您尝试添加
innerPanel
时,它被告知将其自身从当前父级中删除。innerPanel
实际上是 UiBinder 模板的根。它的父级是一个Composite
对象(具体来说,ReferenceUI
)。这会导致抛出异常,因为Composite
未实现HasWidgets
并且不支持删除其小部件。I'll start with the fix, then move on to explain it afterward.
Fixing the problem
The easiest way to fix this problem is as follows. Here's your code:
Replace that with the following code. Note that only the last line has changed.
This way, you are adding the
Composite
object. There will be no difference to the user, as theHTMLPanel
(yourinnerPanel
) will be directly attached into the document.Some background
Adding a widget to a complex panel
When you add a widget to a complex panel (a panel that holds more than one child widget), four things happen one after the other:
Telling a widget to remove itself from its parent
When a child is told to remove itself from its parent, one of the following occurs:
HasWidgets
, the widget tells the panel to remove that widgetIllegalStateException
with message "This widget's parent does not implement HasWidgetsComposite widgets
When calling
initWidget(Widget)
, the widget's parent is set to theComposite
object.The problem
When you try to add
innerPanel
, it is told to remove itself from its current parent.innerPanel
is actually the root of your UiBinder template. Its parent is aComposite
object (specifically,ReferenceUI
). This results in the exception being thrown, asComposite
does not implementHasWidgets
and does not support removing its widget.不幸的是,IIRC 你不能在 UiBinder 的代码中为 Widget 设置 id(我认为你只能为普通的 HTML)。因此,您只能通过
someWidget.getElement().setId()
设置正确的 id(就像您在上面的代码中所做的那样)。我认为,现在缺少的是
HTMLPanel referencePanel
中具有正确 id 的占位符(div、span 等),如下所示:在
AppUIDemo
中:..除非您想将 ReferenceUI 直接添加到
referencePanel
中 - 在这种情况下您应该只使用FlowPanel
:)PS:恕我直言,您应该生成并设置唯一 id来自
ReferenceUI
类的ReferenceUI.refPanel
(并公开 id) - 这样您就不会从某些外部小部件中弄乱小部件的“内部结构”。好吧,我想我明白了。抛出
IllegalStateException
异常,因为您正在添加ReferenceUI.refPanel
(或ReferenceUI.referencePanel
,我不知道哪个是当前名称)到AppUIDemo
(ReferenceUI
显然没有实现HasWidgets
) - 当您应该添加整个ReferenceUI 参考
复合:)我不知道你为什么这样做(也许是因为 ids 混乱),但代码应该看起来像这样:Unfortunately, IIRC you can't set an id for a Widget in UiBinder's code (I think you can only for normal HTML). So you are left with setting the correct id via
someWidget.getElement().setId()
(like you did in the code above).What's missing now, I think, is a placeholder (a div, span, whatever) with the correct id in the
HTMLPanel referencePanel
, like so:And in
AppUIDemo
:...unless you want to add the ReferenceUI directly into
referencePanel
- in which case you should just use aFlowPanel
:)PS: IMHO, you should generate and set the unique id for the
ReferenceUI.refPanel
from theReferenceUI
class (and expose the id) - that way you don't mess with the widget's "internals" from some external widgets.OK, I think I got it. The
IllegalStateException
exception is being thrown because you are addingReferenceUI.refPanel
(orReferenceUI.referencePanel
, I don't know which is the current name) toAppUIDemo
(ReferenceUI
obviously doesn't implementHasWidgets
) - when you should be adding the wholeReferenceUI reference
composite :) I don't know why you did it this way in the first place (maybe because of the whole mess with the ids), but the code should look something like this: