Как объединить несколько виджетов на основе uiBinder? - PullRequest
6 голосов
/ 12 мая 2010

Мне нужно вставить [количество] виджетов на основе uiBinder в другой, в определенном месте. Вставленный виджет имеет несколько сложную компоновку, поэтому я пытаюсь определить его в HTML.

referencePanel.add (...) завершается с java.lang.IllegalStateException: родитель этого виджета не реализует HasWidgets. Не знаю, какого родителя виджета он недоволен - innerPanel или referencePanel.

Если объект ReferenceUI добавляется в RootPanel, а затем он добавляется в конец страницы. Но если он будет добавлен в RootPanel первым, затем есть код JavaScriptException 3 (HIERARCHY_REQUEST_ERR) при добавлении в referencePanel.

Есть предложения?

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>

Ответы [ 2 ]

13 голосов
/ 14 мая 2010

Я начну с исправления, а затем перейду к объяснению.

Исправление проблемы

Самый простой способ решить эту проблему заключается в следующем. Вот ваш код:

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 и не поддерживает удаление своего виджета.

3 голосов
/ 13 мая 2010

К сожалению, IIRC вы не можете установить идентификатор для виджета в коде UiBinder (я думаю, что вы можете только для обычного HTML). Таким образом, вы можете установить правильный идентификатор с помощью someWidget.getElement().setId() (как вы сделали в коде выше).

То, что сейчас не хватает, я думаю, это заполнитель (div, span и т. Д.) С правильным идентификатором в HTMLPanel referencePanel, например:

<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.refPanel из класса ReferenceUI (и предоставить идентификатор) - чтобы вы не связывались с «внутренностями» виджета из некоторых внешних виджетов .


Хорошо, я думаю, что понял. Исключение IllegalStateException генерируется, потому что вы добавляете ReferenceUI.refPanel (или ReferenceUI.referencePanel, я не знаю, какое имя является текущим) к AppUIDemo (ReferenceUI, очевидно, не реализует HasWidgets) - когда вам нужно добавить весь ReferenceUI reference композит :) Я не знаю, почему вы сделали это таким образом (возможно, из-за всей путаницы с идентификаторами), но код должен выглядеть примерно так:

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

        referencePanel.add(reference);
    }
...