新規プレゼンタの作成
本来であればGWTPのEclipseプラグインを道入すれば、簡単にPresenter及びViewが作成されるはずだが、現在(2011/11/28)うまく動作していない。ここでは、手作業で新たなプレゼンタを作成してみる。
なお、前提として、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)」が正しいか。
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; } }