Locked History Actions

Diff for "GWT/GWTP/NewPresenter"

Differences between revisions 13 and 14
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= 新規プレゼンタの作成 = 以下に移動しました。
Line 3: Line 3:

本来であればGWTPのEclipseプラグインを道入すれば、簡単にPresenter及びViewが作成されるはずだが、現在(2011/11/28)うまく動作していない。-->NameTokensを選択した後で、名称がnullのままだとNullPointerExceptionが発生してしまうのがその理由。指定すれば問題無い。

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

なお、前提として、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;
  }
}
}}}
https://www.gwtcenter.com/gwtp-new-presenter

以下に移動しました。

https://www.gwtcenter.com/gwtp-new-presenter