GWTPプレゼンタの作成



以下の記述は少々古い。後に書き直す予定。

手作業で新たなプレゼンタを作成してみる。

なお、前提として、Eclipseプラグインの「GWTP Project」でプロジェクトを作成する際に、「Generate gwtp-sample-basic」を選択してサンプルコードを生成済みであるとする。

基本的なステップ

ここでは、ごく基本的なステップで最低限の表示ができるまでを記述する。なお、パッケージ名の上位部分は省略している。

  • NameTokensへの追加
  • Presenterの作成
  • Viewの作成
  • ClientModuleへの追加
  • Injectorへの追加

NameTokensへの追加

client.place.NameTokensクラスにPlaceの名称を登録する。Placeというのは、いわばGWTP内でページ切り替えを行う場合の「ページ」にあたる。
GWTでは、基本的に使用するhtmlページはただ一つだけで、その中で仮想的なページ切り替えを行うが、それをPlaceと称している。

public class NameTokens {

  public static final String main = "main";
  public static final String response = "response";
  public static final String something = "something";
  ...

他のPlaceにならってgetSomething()などのメソッドを付加する必要は無い。

Presenterの作成

Presenterは、MVCを改良したMVPモデルのPにあたる。簡単に言えばコントローラの役割である。
Presenterの名称は慣習的にPresenterで終了しなければならない。

SomethingPresenter.java

package com.example.myproject.client.core;

import com.example.myproject.client.place.*;
import com.google.gwt.event.shared.*;
import com.google.inject.*;
import com.gwtplatform.dispatch.shared.*;
import com.gwtplatform.mvp.client.*;
import com.gwtplatform.mvp.client.annotations.*;
import com.gwtplatform.mvp.client.proxy.*;

public class SomethingPresenter extends
    Presenter<SomethingPresenter.MyView, SomethingPresenter.MyProxy> {

  @ProxyStandard
  @NameToken(NameTokens.something)
  public interface MyProxy extends ProxyPlace<SomethingPresenter> {}

  public interface MyView extends View {}

  @Inject
  public SomethingPresenter(final EventBus eventBus, final MyView view,
      final MyProxy proxy, final DispatchAsync dispatcher, final PlaceManager placeManager) {
    super(eventBus, view, proxy);

  }

  @Override
  protected void revealInParent() {
    RevealRootContentEvent.fire(this, this);
  }
}

特にMyProxyにつけられている@NameTokenは重要。この引数を間違えると動作しない。

Viewの作成

ViewはGUI部分になる。これにはSomethingPresenter.MyViewを実装させる。

package com.example.myproject.client.core;

import com.google.gwt.user.client.ui.*;
import com.google.inject.*;
import com.gwtplatform.mvp.client.*;

public class SomethingView extends ViewImpl implements SomethingPresenter.MyView {

  private static String html = "<div id=\"something\"></div>\n";
  private final HTMLPanel panel = new HTMLPanel(html);

  @Inject
  public SomethingView() {
    Button someButton = new Button("do something");
    panel.add(someButton, "something");
  }

  @Override
  public Widget asWidget() {
    return panel;
  }
}

ちなみにHTMLパネルではなく、LayoutPanelなどを使えば普通にGWT DesignerでGUI構築が可能。
ただし、その場合、Presenter側のrevealInParentメソッドによって、ルートとなるパネルがRootPanel相当(?)かRootLayoutPanel相当(?)のいずれかになるかが決まるのでそれを考慮しなければならない(後述)。

ClientModuleへの追加

client.gin.ClientModuleのconfigure()メソッドに以下を追加して、GINがこれらを扱えるようにする。

    bindPresenter(SomethingPresenter.class, SomethingPresenter.MyView.class,
        SomethingView.class, SomethingPresenter.MyProxy.class);

Injectorへの追加

client.gin.ClientGinjectorに以下を追加し、SomethingPresenterを注入できるようにする。

  Provider<SomethingPresenter>getSomethingPresenter();

動作確認

DevelopModeでメインページを表示した後、URLの最後に#somethingをつける。つまり、

http://127.0.0.1:8888/gwtp.html?gwt.codesvr=127.0.0.1:9997#something

といったURLになる。これで「do something」ボタンが表示されれば成功である。

他の方法としては、MainPagePresenterの

    // Then, we transmit it to the ResponsePresenter, which will do the server call
    placeManager.revealPlace(new PlaceRequest(NameTokens.response).with(
        ResponsePresenter.textToServerParam, textToServer));

の部分を

    placeManager.revealPlace(new PlaceRequest(NameTokens.something));

に変更する。この場合、デフォルトプレースのSendボタンをクリックすると画面が切り替わる。

うまくいかない場合のチェック事項

新規作成したPresenter/Viewに全く画面遷移しない場合がある。この場合、エラーらしいものは表示されず、常にデフォルトプレースの表示になってしまうので何が悪いのかわかりにくい。次をチェックしてみること。

  • 新規Presenter内に定義したProxyのアノテーション。上記例の場合は「@NameToken(NameTokens.something)」が正しいか。
  • NameTokens内に定義したトークン文字列に同じものが無いか。
  • ClientModuleのconfigure()内で正しくbindPresenter()の呼び出しが行われているか。
  • ClientGinjector内に正しくPresenter取得メソッドが定義されているか。
  • 新規Presenterを追加した後に、Development Modeを再起動したか(クライアント側だけの問題であるが、再起動しないと動作しない)。

ルートパネルの変更

生のGWTではRootPanel.get()あるいはRootLayoutPanel.get()のどちらを呼び出すかによって、いずれのルートパネルにするかを決定していたが、

※後者の場合は、ブラウザ画面サイズ変更が伝播される。

GWTPの場合には、これをPresenterのrevealInParentメソッドで行う模様。つまり、

  @Override
  protected void revealInParent() {
    RevealRootContentEvent.fire(this, this);
  }

とすると、ViewのルートパネルとしてRootPanelが、

  @Override
  protected void revealInParent() {
    RevealRootLayoutContentEvent.fire(this, this);
  }

とするとRootLayoutPanelが使用される。

例えば、RootLayoutPanelにしておいて、SomethingViewをGWT Designerを使ってGUI構築することができる
(RootPanelでもできるがサイズ指定が必要)。

package com.example.myproject.client.core;

import com.google.gwt.user.client.ui.*;
import com.google.inject.*;
import com.gwtplatform.mvp.client.*;
import com.google.gwt.dom.client.Style.Unit;

public class SomethingView extends ViewImpl implements SomethingPresenter.MyView {

  private final LayoutPanel panel = new LayoutPanel();

  @Inject
  public SomethingView() {

    DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.EM);
    panel.add(dockLayoutPanel);

    HorizontalPanel horizontalPanel = new HorizontalPanel();
    horizontalPanel.setSpacing(5);
    dockLayoutPanel.addNorth(horizontalPanel, 7.7);

    Button btnNewButton = new Button("New button");
    horizontalPanel.add(btnNewButton);

    Button btnNewButton_1 = new Button("New button");
    horizontalPanel.add(btnNewButton_1);

    Button btnNewButton_2 = new Button("New button");
    dockLayoutPanel.add(btnNewButton_2);
  }

  @Override
  public Widget asWidget() {
    return panel;
  }
}