ラベル GWT の投稿を表示しています。 すべての投稿を表示
ラベル GWT の投稿を表示しています。 すべての投稿を表示

2010年6月18日金曜日

GWT で onTouchStart / onTouchMove / onTouchEnd イベントを処理してみる

動機:
GWTFusenをiPadで使えるようにできないかしら?
あれこれ調べたらこれに出会った.
Lombardi Development Blog » Blog Archive » Supporting multi-touch events with GWT on mobile Safari

で,このコメントにある'touch.tar.gz'が動きそうなのでやってみよう!


やってみた:
1. EclipseのGWTプラグインが入っているとする.'SampleTouch' Web Application Projectを作成.
1.a 使わないものを片っ端から削除
src/test.client.GreetingService.java ファイル
src/test.client.GreetingServiceAsync.java ファイル
src/test.server パッケージ
src/test.shared パッケージ


1.b 'SampleTouch.java'を以下のようにする.
public class SampleTouch implements EntryPoint, TouchStartHandler,
TouchMoveHandler, TouchEndHandler {

private HTML html;

private TouchableFocusPanel tfp;

public void onModuleLoad() {
try {
VerticalPanel panel = new VerticalPanel();
html = new HTML();
panel.add(html);
tfp = new TouchableFocusPanel();
tfp.addTouchStartHandler(this);
tfp.addTouchMoveHandler(this);
tfp.addTouchEndHandler(this);
tfp.setSize("1000px", "1000px");
panel.add(tfp);
RootPanel.get().add(panel);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void onTouchStart(TouchStartEvent event) {
event.preventDefault();
String msg = "Start: ";
msg += createMessage(event.touches());
html.setHTML(msg);
}

@Override
public void onTouchMove(TouchMoveEvent event) {
event.preventDefault();
String msg = "Move: ";
msg += createMessage(event.touches());
html.setHTML(msg);
}

@Override
public void onTouchEnd(TouchEndEvent event) {
event.preventDefault();
String msg = "End: ";
msg += createMessage(event.touches());
html.setHTML(msg);
}

private String createMessage(JsArray touches) {
String msg = "";
if (touches.length() > 0) {
for (int i = 0; i < touches.length(); i++) {
Touch t = touches.get(i);
int x = t.getRelativeX(tfp.getElement());
int y = t.getRelativeY(tfp.getElement());
msg += i + ":{x:" + x + "," + y + "}, ";
}
}
return msg;
}
}



1.c 上記 'touch.tar.gz'を展開した中の'main/gwt/com'の'com'フォルダーをDnD等でプロジェクトのソースフォルダに設置する.

1.d war/SampleTouch.htmlの編集
bodyタグの中身を空っぽにする.

1.e src/com.google.gwt.user.MoblieSafari.gwt.xmlの編集
moduleタグの直下に以下を追加
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.user.UserAgent'/>
<set-property name="user.agent" value="safari" />


1.f src/sample.touch.SampleTouch.gwt.xmlの編集
以下のコメント行の下に
<!-- Other module inherits -->

以下を追加する.
<inherits name='com.google.gwt.user.MobileSafari'/>
<inherits name='com.lombardi.mobilesafari.MobileSafariEvents'/>



2. GWT Compile
2.a プロジェクト内のファイルを選択して, GWT Compileをクリック.


2.b EntryPointModulesから'SampleTouch'以外をRemoveする.



2.c 'Compile'を実行する.


3. 'war'フォルダーをWebでhttpでアクセス可能な場所へ設置
例えば/Library/WebServer/Documents/の下などでWeb共有からアクセスするなど.



結果:
タッチ(スナップとるときどうしても指が動くのでMoveになってしまう…)

マルチタッチ


TwFusen:
で,GWTFusen改めTwFusenとしてこちらに置いてみた

2010年5月28日金曜日

gwt-html5-storageでwebstorage

追記(2010/06/17):Google App Engineに変更 名前もTwFusenとした.

追記:これってドメイン一つに対してKeyValueStorage一つみたいなのでy30.netの中で他になにかが使っていたら衝突して動作に不具合がでるかも.



動機
1.GWTFusenもGoogleGearじゃなくてHTML5系のストレージ(これこれ)に対応したいなぁ…。
2.gwt-html5-storageでつくればKey-Value Data Storageで簡単そう.
3.やってみよう.


参考
gwt-mobile-webkit
感謝


やってみた
1.'gwt-html5-storage-1.0.1.tar.gz'をdownloadしてGWTプロジェクトのbuild pathに追加してあげれば以下が使えるようになる.

(簡単に)できたこと.
ストレージ部用意と追加はこうなる.
Storage storage = Storage.getLocalStorage();
storage.setItem("key", "value");


セッション中だけのストレージならこうなる.
Storage storage = Storage.getSessionStorage();


Key数の取得
int size= storage.getLength();


i番目のKeyの取得(i= 0...)
String key= storage.key(i);


Keyに対応するValueの取得
String value= storage.getItem(key);


KeyとValueの削除
storage.removeItem(key);


Storageのクリア
storage.clear()


2.で,GWTFusenに反映

3.これってドメイン一つに対してKeyValueStorage一つみたいなのでy30.netの中で他になにかが使っていたら衝突する.

2009年2月5日木曜日

GWT + Twitter の 例(?)

Twitterへのリクエストとその戻り値(JSONオブジェクトの配列)を処理.
参考:Using GWT for JSON Mashups

Java Native Interface(JNI)を利用したJavascript直接記述部がポイントでしょうか♪.

pg/net/y30/client/TwitterFactory.java
 protected HashMap<Integer, Object> callbacks = new HashMap<Integer, Object>();
protected HashMap<String, Element> scriptTags = new HashMap<String, Element>();

public void requestTwitter(String name, int count) {
String gdata = "http://twitter.com/statuses/user_timeline/" + name
+ ".json?count=" + count + "&callback=";
String callbackName = reserveCallback();
setup(this, callbackName);
addScript(callbackName, gdata + callbackName);
}

public native static void setup(TwitterFactory g, String callback)
/*-{
$wnd[callback] = function(someData) {
g.@pg.net.y30.client.TwitterFactory::handle(Lcom/google/gwt/core/client/JavaScriptObject;)(someData);
}
}-*/;

public String reserveCallback() {
while (true) {
if (!callbacks.containsKey(new Integer(curIndex))) {
callbacks.put(new Integer(curIndex), null);
return "myCallBack" + curIndex++;
}
}
}

public void addScript(String uniqueId, String url) {
Element e = DOM.createElement("script");
DOM.setElementProperty(e, "language", "JavaScript");
DOM.setElementProperty(e, "src", url);
scriptTags.put(uniqueId, e);
DOM.appendChild(RootPanel.get().getElement(), e);
}

public void handle(JavaScriptObject jso) {
JSONObject json = new JSONObject(jso); // This is an array of twitter's json objects.
JSONValue val;
int i = 0;
while ((val = json.get((new Integer(i++)).toString())) != null) {
JSONObject obj = val.isObject(); // This is a twitter's json object.
Window.alert(obj.toString());
}
}

requestTwitter
スタート♪.urlを作成後,callback関数を用意して関数を用意して, script要素でtwitterへjsonを要求.
setup
reserveCallbackで作成したcallback関数(名)をjavascriptの関数として登録.
reserveCallback
ユニークなcallback関数名を作成.(ユニークでなくてはいけないのかしら?)
addScript
callback関数の形でjsonオブジェクトを返してもらうリクエストをscript要素として追加する.
handle
callback関数の処理の実態.setupの中で記述してあるのは(赤色)これ.


GWTFusenで利用しています.

GWT 1.5.3 + Gears 1.1 Library で作る PropertiesManager

GWTプロジェクトに'Gears 1.1 Library'をclass pathに追加して利用した.
(Gears 1.1 Library はGoogle Gearsを利用するためのライブラリ.)

もっとまともなSQLがかける人のを参考にするべきかもしれませんよ♪.

PropertiesManager.java
import java.util.HashMap;

import com.google.gwt.gears.client.Factory;
import com.google.gwt.gears.client.database.Database;
import com.google.gwt.gears.client.database.DatabaseException;
import com.google.gwt.gears.client.database.ResultSet;

public class PropertiesManager {
private Database _database = null;

private String _tableName = null;

private HashMap<String, String> _hash = new HashMap<String, String>();

public PropertiesManager(String dbName, String tableName) {
if (dbName != null && dbName.length() > 0) {
_database = PropertiesManager.checkDatabase(dbName);
if (_database != null) {
if (tableName != null && tableName.length() > 0) {
_tableName = tableName;
if (PropertiesManager.checkTable(_database, _tableName) == false) {
PropertiesManager.createTable(_database, _tableName);
}
}
}
}
}

public Database get_database() {
return _database;
}

public String getProperty(String key) {
String ret = null;
if (_database != null)
ret = PropertiesManager.selectProp(_database, _tableName, key);
else
ret = _hash.get(key);
return ret;
}

public void setProperty(String key, String value) {
if (_database != null) {
String oldValue = PropertiesManager
.selectProp(_database, _tableName, key);
if (oldValue == null) {
PropertiesManager.insertProp(_database, _tableName, key, value);
} else {
PropertiesManager.updateProp(_database, _tableName, key, value);
}
}
_hash.put(key, value);
}

public static Database checkDatabase(String dbName) {
Database db = null;
try {
Factory factory = Factory.getInstance();
if (factory != null) {
db = factory.createDatabase();
db.open(dbName);
}
} catch (Exception e) {
}
return db;
}

public static boolean createTable(Database db, String tableName) {
if (db == null || tableName == null || tableName.length() == 0) {
return false;
}
boolean ret = false;
try {
db.execute("CREATE TABLE IF NOT EXISTS " + tableName
+ " (id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ " key TEXT, value TEXT)", new String[] {});
ret = true;
} catch (DatabaseException e) {
}
return ret;
}

public static boolean checkTable(Database db, String tableName) {
if (db == null || tableName == null || tableName.length() == 0) {
return false;
}
boolean ret = false;
try {
ResultSet rs = db.execute("SELECT COUNT(*) FROM " + tableName,
new String[] {});
if (rs != null) {
ret = true;
}
} catch (DatabaseException e) {
}
return ret;
}

public static boolean removeProp(Database db, String tableName, String key) {
if (db == null || tableName == null || tableName.length() == 0) {
return false;
}
boolean ret = false;
try {
db.execute("DELETE FROM " + tableName + " WHERE key = ?",
new String[] { key });
ret = true;
} catch (DatabaseException e) {
}
return ret;
}

public static boolean insertProp(Database db, String tableName, String key,
String value) {
if (db == null || tableName == null || tableName.length() == 0) {
return false;
}
boolean ret = false;
try {
db.execute("INSERT INTO " + tableName + " VALUES(NULL, ?, ?)",
new String[] { key, value });
ret = true;
} catch (DatabaseException e) {
}
return ret;
}

public static boolean updateProp(Database db, String tableName, String key,
String value) {
if (db == null || tableName == null || tableName.length() == 0) {
return false;
}
boolean ret = false;
try {
db.execute("UPDATE " + tableName + " SET value=? WHERE key = ?",
new String[] { value, key });

ret = true;
} catch (DatabaseException e) {
}
return ret;
}

public static String selectProp(Database db, String tableName, String key) {
String ret = null;
if (db == null || tableName == null || tableName.length() == 0) {
return null;
}
try {
ResultSet rs = db.execute("SELECT value FROM " + tableName
+ " WHERE key = ?", new String[] { key });
if (rs != null && rs.isValidRow()) {
ret = rs.getFieldAsString(0);
//
rs.next();
if (rs.isValidRow()) {
PropertiesManager.removeProp(db, tableName, key);
PropertiesManager.insertProp(db, tableName, key, ret);
}
}
} catch (DatabaseException e) {
}
return ret;
}
}


  • Factory.getInstance();の戻り値がからの場合はGearsが入っていない(んだと思う).
  • 結果を参照する時は以下のようにする作法(?)らしい?.
        ResultSet rs = db.execute("SELECT 句", new String[] { ... });
    for(;rs.isValidRow();rs.next())
    {
    ...
    }


db, table, hashの用意
PropertiesManager _propMgr = new PropertiesManager("DBNAME", "TABLENAME");

getter(dbが無かった時はhashからget)
String PROPERTY_VALUE = _propMgr.getProperty("PROPERTY_KEY");

setter(dbが無かった時はhashにset)
_propMgr.setProperty("PROPERTY_KEY", "PROPERTY_VALUE");


繰り返しますが,もっとまともなSQLがかける人のを参考にするべきかもしれませんよ♪.

一応,GWTFusenで利用中.

2009年1月31日土曜日

Twitter+Fusenを懲りずに再び

追記(2009/2/2): Safariな人が少ないらしいのでGoogle Gearsで保存するように変更してみた.



Twitter+Fusenを懲りずにまたやってみた

今回利用したのは以下の話.


ではどうぞ

  • とりあえずimportボタンをポチットしてみてください.
  • kyubotterから最新5つのツブヤキがとれます.
  • 出てきたのをドラッグ アンド ドロップしてみてください.それだけのサイトです.
  • (配置したツブヤキ達はClient-side Database storageに記録しますがこれはSafari3.1以上のみ対応です.)
  • (保存情報は/Users/username/Library/Safari/Databases/http_y30.net_0/*.dbが保存されているデータです.(SQLite Database BrowserなどがあるとGUIで見れますよ))
  • (保存情報の削除は環境設定/セキュリティ/データベースの保存の項目にある'データベースを表示'ボタンによってでるダイアログで消してください(GWTFusen Database).

  • (配置したツブヤキはGoogleGearsで保存します (2009/2/2変更))
  • (保存情報はMac-Safariだと/Users/username/Library/Application Support/Google/Google Gears for Safari/y30.net/http_80/GWTFusen#databaseで保存されていた.(SQLite Database BrowserなどがあるとGUIで見れますよ))


やった事の記事についてはまた後日.

2009年1月25日日曜日

GWT / Hosted Web BrowserでCGIを利用する

プロジェクト名: MyApplication
クラス名: com.mycompany.client.MyApplication

始めた場合

1. src/com.mycompany/publicの下にcgi/sample.plがあるとする.
2. 1.の'cgi'フォルダをtomcat/webapps/Rootの下に複写する.(sample.plはtomcat/webapps/Root/cgi/sample.plとなる)
3. Tomcat 6.xのcatalina.jarを用意する(CGIServletをつかうため.gwt-dev-mac.jarにない).
4. MyApplication-shell中のclasspathの最後にcatalina.jarを追加する.
5. tomcat/webapps/ROOT/WEB-INF/web.xmlに以下を追加する(web-app要素の中に).
(tomcatフォルダは一度Hostedモードで動かせば(MyApplication-shellなど)作られます.)
 <servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
<param-name>clientInputTimeout</param-name>
<param-value>100</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>6</param-value>
</init-param>
<init-param>
<param-name>cgiPathPrefix</param-name>
<param-value>cgi</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/com.mycompany.MyApplication/cgi/*</url-pattern>
</servlet-mapping>

6. 'new RequestBuilder(RequestBuilder.POST, "cgi/sample.pl")'な感じで使う.
7. MyApplication-shellで実行

2008年8月22日金曜日

GWTでCanvasタグを使ってみる (drawImageメソッドの補完)

GWTを使ってみている.
Canvasタグ周りはgwt-canvasというプロジェクトでサポートしていた.
こいつを使う(gwt-canvas-x.x.x.jarにパスを通す)とこう書ける.

Test.gwt.xml
<module> 
<inherits name="com.google.gwt.user.User"/>
<inherits name='gwt.canvas.gwt-canvas'/>
<entry-point class='sample.client.Test'/>
</module>


sample.client.Test.java
package sample.client;

import gwt.canvas.client.Canvas;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;

public class Test implements EntryPoint {

public void onModuleLoad() {
Canvas canvas = new Canvas(300, 300);

canvas.beginPath();
canvas.moveTo(0, 0);
canvas.lineTo(300, 300);
canvas.stroke()
;

RootPanel.get().add(canvas);
}

}


こんな感じ.


Contextを取得しないらしい'2d'限定.まぁ今のところ2dしか仕様にもないらしいので問題にならないのだろうけど….
2dコンテキストのメソッドはこことかにある.(感謝.)

さて, drawImageが使いたかったのだがこれが未実装とのことでちょっと困った.
だがこれをJSNIとJavaScriptObjectで対応することで回避できた.(JSNIとJavaScriptObject関連の解説はここにある.感謝)
つまりCanvasの位置,大きさや装飾はGWTで管理して描画はレガシーな方法で逃げるということである.どうせ直ぐに対応されていらなくなるtipsであるだろうけどw.

コードは以下.
sample.client.Test.java
package sample.client;

import gwt.canvas.client.Canvas;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.ui.RootPanel;

public class Test implements EntryPoint {

public void onModuleLoad() {
Canvas canvas = new Canvas(300, 300);
RootPanel.get().add(canvas);

JavaScriptObject context = getCtx();
JavaScriptObject image = createImage("http://www.google.com/images/logo.gif");
canvas.fillRect(0, 0, 300, 300);
drawImage(context, image, 5, 5);
}

protected native JavaScriptObject getCtx()
/*-{
var canvas= $doc.getElementsByTagName('canvas');
$wnd.ctx= canvas[0].getContext('2d');
return $wnd.ctx;
}-*/;

protected native JavaScriptObject createImage(String imageUrl)
/*-{
var image= new Image();
image.src= imageUrl;
return image;
}-*/;

protected native void drawImage(JavaScriptObject ctx,
JavaScriptObject image, int x, int y)
/*-{
ctx.drawImage(image, x, y);
}-*/;
}


JSNIのコメントの付け方はEclipseでフォーマットを走らせたときにズレていかないようにするための対応(のつもり).

こんな感じ.


欠点いろいろ(というか私の不勉強):
  • 上のコードの欠点はImageまでJSNIしなくてはいけない.GWTで作ってJSNIで取り出せるとうれしいんだけどImageの場合どっから取り出すと良いのだろう?docmentかなにかかな?
  • Canvasは作ってタグ名で検索して配列の最初のモノとベタに決め込んでいるところがダメ.GWTで要素に一意にするにはaddStyleNameが正攻法なのかな.

    まぁ参考にもならないだろうけど最近更新してないのでネットのノイズとして掲載.
  • 2008年3月10日月曜日

    'GWT on Rails'のサンプル(再び)

    ここまでのまとめをスクリプトとして置いておいてみる.この方が私が文書を書くより確実に情報(それが何かはわからないが)が伝わるだろう.
    環境: MacOS X 10.5.2 / Ruby 1.8.6(OS付属) / Java 1.5.0(OS付属) / Rails 2.0.2(portsより) / GWT 1.4.61(download)
    モデル名: Project
    アプリ名: dashboard
    #! /bin/sh
    #------------------------------------------------------
    #
    PRJ_NAME=GWT_on_Rails
    GWT_HOME=/path/to/gwt-mac-1.4.61

    #------------------------------------------------------
    #
    rm -rf ${PRJ_NAME}

    #------------------------------------------------------
    #
    rails ${PRJ_NAME}

    #------------------------------------------------------
    #
    cd ${PRJ_NAME}

    #------------------------------------------------------
    #--Rails-----------------------------------------------
    #------------------------------------------------------
    #
    script/plugin install http://labnotes.org/svn/public/ruby/rails_plugins/json_request

    #------------------------------------------------------
    #
    script/generate scaffold Project name:string

    #------------------------------------------------------
    #
    mv app/controllers/projects_controller.rb app/controllers/projects_controller.rb.orig

    #------------------------------------------------------
    #
    sed 's/xml/json/g' app/controllers/projects_controller.rb.orig > app/controllers/projects_controller.rb

    #------------------------------------------------------
    #
    script/generate migration InsertProjects

    #------------------------------------------------------
    #
    patch db/migrate/002_insert_projects.rb << EOF
    2a3,4
    > Project.create(:name=>"Foo")
    > Project.create(:name=>"Bar")
    EOF

    #------------------------------------------------------
    #
    rake db:migrate

    #------------------------------------------------------
    #--GWT-------------------------------------------------
    #------------------------------------------------------
    #
    script/plugin install http://gwt-on-rails.googlecode.com/svn/trunk/gwt_on_rails

    #------------------------------------------------------
    #
    script/generate gwt_resource Project dashboard

    #------------------------------------------------------
    #
    rake db:migrate

    #------------------------------------------------------
    #
    script/generate gwt_client dashboard ${GWT_HOME}

    #------------------------------------------------------
    #
    patch app/gwt/dashboard/src/dashboard/client/Dashboard.java << EOF
    3a4,6
    > import com.google.gwt.core.client.GWT;
    > import com.google.gwt.http.client.Request;
    > import com.google.gwt.user.client.Window;
    8a12,18
    > import com.kaboomerang.gwt.rest.client.handler.ResourceResponseHandler;
    > import com.kaboomerang.gwt.rest.client.resource.Resource;
    > import com.kaboomerang.gwt.rest.client.resource.ResourceCollection;
    > import com.kaboomerang.gwt.rest.client.resource.ResourceFactory;
    > import com.kaboomerang.gwt.rest.client.resource.impl.RailsJsonResourceCollection;
    >
    > import dashboard.client.resource.Project;
    23a34,51
    > ResourceCollection projects = new RailsJsonResourceCollection(
    > "/projects/", new ResourceFactory() {
    > public Resource create() {
    > return (Resource) GWT
    > .create(Project.class);
    > }
    > });
    > projects.find(1,
    > new ResourceResponseHandler() {
    > public void onSuccess(Resource resource) {
    > Window.alert("Project name is " + ((Project) resource).getName());
    > }
    >
    > public void onError(Request request, Throwable exception) {
    > Window.alert("Something went wrong.");
    > }
    > });
    >
    EOF

    #------------------------------------------------------
    #
    rake dashboard:compile


    後はサーバを起動する.
    > cd ${PRJ_NAME}
    > script/server


    と,アクセスするぐらい.
    http://localhost:3000/dashboard/

    GWT on Rails : CRUDの'R'の拡張? 'Index'

    ということ(?)でDashboard.javaを編集してみる.一覧だ..
    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    //import類は省くが困ったらgwtのモノを選んどけばたいてい大丈夫
    public class Dashboard implements EntryPoint {
    public void onModuleLoad() {
    final Button button = new Button("Click me");
    final Label label = new Label();
    button.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {

    //add
    ResourceCollection projects = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT.create(Project.class);
    }
    });
    projects.findAll(new CollectionResponseHandler() {
    public void onSuccess(Collection resources) {
    String msg= "[";
    Iterator projectIter= resources.iterator();
    while(projectIter.hasNext()) {
    Project p= (Project) projectIter.next();
    msg += (msg.length()>1)?", ":"";
    msg += p.getName();
    }
    msg += "]";
    label.setText(msg);
    }
    public void onError(Request request, Throwable exception) {
    label.setText("Something went wrong.");
    }
    });

    //add

    if (label.getText().equals(""))
    label.setText("Hello World!");
    else
    label.setText("");
    }
    });
    //slotは'app/views/dashboard/index.html.erb'内のidでの定義.
    //button, labelはそこにハマる.
    RootPanel.get("slot1").add(button);
    RootPanel.get("slot2").add(label);
    }
    }

    これは登録されている全てのProjectを取ってくる例.取ってきた結果のnameを文字列に詰め込んでlabelに入れているあたりがちょっと新しいかなw.

    > rake dashbaord:compile
    > script/server

    ブラウザにて'http://localhost:3000/dashboard/'へアクセス

    GWT on Rails : CRUDの'D'

    ということでDashboard.javaを編集してみる.削除だ..
    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    //import類は省くが困ったらgwtのモノを選んどけばたいてい大丈夫
    public class Dashboard implements EntryPoint {
    public void onModuleLoad() {
    final Button button = new Button("Click me");
    final Label label = new Label();
    button.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {

    //add
    ResourceCollection projects = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT.create(Project.class);
    }
    });
    projects.find(1, new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("Project(id=1) exists");
    }

    public void onError(Request request,
    Throwable exception) {
    Window.alert("Project(id=1) doesn't exist");
    }
    });
    ResourceCollection projects2 = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT.create(Project.class);
    }
    });
    projects2.delete(1, new StatusResponseHandler() {
    public void onSuccess() {
    ResourceCollection projects3 = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT
    .create(Project.class);
    }
    });
    projects3.find(1, new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("Project(id=1) exists");
    }
    public void onError(Request request,
    Throwable exception) {
    Window.alert("Project(id=1) doesn't exist");
    }
    });
    }
    public void onError(Request request, Throwable exception) {
    }
    });

    //add

    if (label.getText().equals(""))
    label.setText("Hello World!");
    else
    label.setText("");
    }
    });
    //slotは'app/views/dashboard/index.html.erb'内のidでの定義.
    //button, labelはそこにハマる.
    RootPanel.get("slot1").add(button);
    RootPanel.get("slot2").add(label);
    }
    }

    これはid=1のデータを削除する例.流れはまずid=1を取得し成功/不成功をalertで表示する.次にid=1のデータ削除を要求する.成功した際は,再度id=1の取得を試み成功/不成功をalertで表示する.

    > rake dashbaord:compile
    > script/server

    ブラウザにて'http://localhost:3000/dashboard/'へアクセス

    2008年3月9日日曜日

    GWT on Rails : CRUDの'U' Update

    ということでDashboard.javaを編集してみる.更新だ..
    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    //import類は省くが困ったらgwtのモノを選んどけばたいてい大丈夫
    public class Dashboard implements EntryPoint {
    public void onModuleLoad() {
    final Button button = new Button("Click me");
    final Label label = new Label();
    button.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {

    //add
    ResourceCollection projects = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT.create(Project.class);
    }
    });
    projects.find(1, new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("Before: Project name is "
    + ((Project) resource).getName());
    Project p = (Project) resource;
    p.setName("ABC");
    ResourceCollection projects2 = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT
    .create(Project.class);
    }
    });
    projects2.update(p, new StatusResponseHandler() {
    public void onSuccess() {
    Window.alert("SUCCESS");
    ResourceCollection projects3 = new RailsJsonResourceCollection(
    "/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT
    .create(Project.class);
    }
    });
    projects3.find(1, new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("After: Project name is "
    + ((Project) resource).getName());
    }
    public void onError(Request request, Throwable exception) {
    }
    });
    }
    public void onError(Request request,
    Throwable exception) {
    Window.alert("ERROR");
    }
    });

    }
    public void onError(Request request, Throwable exception) {
    }
    });

    //add

    if (label.getText().equals(""))
    label.setText("Hello World!");
    else
    label.setText("");
    }
    });
    //slotは'app/views/dashboard/index.html.erb'内のidでの定義.
    //button, labelはそこにハマる.
    RootPanel.get("slot1").add(button);
    RootPanel.get("slot2").add(label);
    }
    }

    これはid=1のname属性を'ABC'へ更新する例.流れはまずid=1を取得しそのname属性をalertで表示する.次にname=ABCと置き換え,それを更新処理にまわす.再度id=1を取得しそのname属性をalertで表示する.
    実際はupdateメソッドの第一引数となるオブジェクトのid値を更新対象とするためidを書き換えれば呼出した対象と異なる対象が更新される.例えばsetId(2)とすれば更新されるのは(JSON Requestは)id=2のデータである.

    > rake dashbaord:compile
    > script/server

    ブラウザにて'http://localhost:3000/dashboard/'へアクセス

    GWT on Rails : CRUDの'C' Create

    ということでDashboard.javaを編集してみる.生成だ..
    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    //import類は省くが困ったらgwtのモノを選んどけばたいてい大丈夫
    public class Dashboard implements EntryPoint {
    public void onModuleLoad() {
    final Button button = new Button("Click me");
    final Label label = new Label();
    button.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {

    //add
    ResourceCollection projects = new RailsJsonResourceCollection(
    "http://localhost:3000/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT
    .create(Project.class);
    }
    });
    Project p= new Project();
    p.setName("abc");
    java.util.Date d= new java.util.Date();
    p.setCreatedAt(d);
    p.setUpdatedAt(d);
    projects.create(p,
    new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("Project name is " + ((Project) resource).getName());
    }

    public void onError(Request request, Throwable exception) {
    Window.alert("Something went wrong.");
    }
    });

    //add

    if (label.getText().equals(""))
    label.setText("Hello World!");
    else
    label.setText("");
    }
    });
    //slotは'app/views/dashboard/index.html.erb'内のidでの定義.
    //button, labelはそこにハマる.
    RootPanel.get("slot1").add(button);
    RootPanel.get("slot2").add(label);
    }
    }

    これはname=abcを生成する例.name=abcを生成後,成功時にはその生成オブジェクトのname属性をalertで表示する.

    > rake dashbaord:compile
    > script/server

    ブラウザにて'http://localhost:3000/dashboard/'へアクセス

    GWT on Rails : CRUDの'R' Read (Referenceではないんだ…)

    ということでDashboard.javaを編集してみる.まずは初回同様参照.
    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    //import類は省くが困ったらgwtのモノを選んどけばたいてい大丈夫
    public class Dashboard implements EntryPoint {
    public void onModuleLoad() {
    final Button button = new Button("Click me");
    final Label label = new Label();
    button.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {

    //add
    ResourceCollection projects = new RailsJsonResourceCollection(
    "http://localhost:3000/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT
    .create(Project.class);
    }
    });
    projects.find(1,
    new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("Project name is " + ((Project) resource).getName());
    }

    public void onError(Request request, Throwable exception) {
    Window.alert("Something went wrong.");
    }
    });

    //add

    if (label.getText().equals(""))
    label.setText("Hello World!");
    else
    label.setText("");
    }
    });
    //slotは'app/views/dashboard/index.html.erb'内のidでの定義.
    //button, labelはそこにハマる.
    RootPanel.get("slot1").add(button);
    RootPanel.get("slot2").add(label);
    }
    }

    これはid=1を取得する例.id=1を取得後,name属性をalertで表示する.
    RailsJsonResourceCollectionの第一引数はJSON Requestを処理するアクセスポイントである.なので単に"/projects/"でも動く.その方が便利かも.

    > rake dashbaord:compile
    > script/server

    ブラウザにて'http://localhost:3000/dashboard/'へアクセス
    RailsJsonResourceCollectionの第一引数とこのアクセスサーバは文字列的に同じでないとXMLHttpRequestがセキュリティーを問題視して問合せをしないので注意.してしまうブラウザはそれはそれで注意(そんなのあるの?).そういう意味でも"http://.../projects/"とするより"/projects/"の方が便利であり可搬性(?)があるね.

    GWT on Rails : JSON Requestを処理できるようにしたその後とEclipseに入れてみる

    さて改めてJSON Request / REST が処理できるサーバができたところからを復習すると以下の感じになる(Rails 2.0.2).
    > script/plugin install http://gwt-on-rails.googlecode.com/svn/trunk/gwt_on_rails
    > script/generate gwt_resource Project dashboard
    > rake db:migrate
    > script/generate gwt_client dashboard ${GWT_HOME}

    Project: Railsに作ったモデル.
    dashboard: Webアプリケーション(サービス)の名前(アクセス時のパスにもなる)
    出来上がるファイル
    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    app/views/dashboard/index.html.erb
    等を編集.その後コンパイル.
    > rake dashboard:compile



     さてGWTを使うんだからEclipseにて編集したいのは私だけではないと思う(思いたい).
     部分的にJava編集のためだけ使ってそれ以外はすべてコンソールでもいっこうに良いと思う.
    'File/New/Java Project'にてCreate Java Projectダイアログをだし,Contentsのチェックで'Create project from existing source'側を選択し${RAILS_PROJECT}/app/gwt/dashboardを指定すれば良い.自動的にsrcを認識してくれるしディレクトリツリー下にあるjarをライブラリとして組み込んでくれる.あと外部Jarとして${GWT_HOME}/gwt-user.jarを入れてあげることもお忘れなく.(GWT1.4系はJava1.5系の<>で囲んで型を書くやつ(ジェネリクス?)が使えないのでEclipse側のJRE等も1.4系にしておくと良いかも)
     また全体をEclipseに入れるとしても同じようにしてあげればよい.この時はvendor/plugins/gwt_on_rails下のjarもライブラリとして登録されるので外しておく.あとは部分的の場合と同じ.この場合External Toolとしてrakeが呼べるので下の画像の用に登録してあげて動かす.

    GEM_HOMEが不明で動かない場合は環境変数を入れてあげる.

    Refeshタブのチェックボックスも入れといても良いかもね.

    これでEclipseからGWTのコンパイルが呼べるし,まぁその他いろいろ便利になるかもしれない.

    2008年3月7日金曜日

    'GWT on Rails'のサンプル(参照だけ)

    追記
    '1. JSON Request/RESTを処理するサーバを作る'について別の方法を書いた
    http://edotprintstacktrace.blogspot.com/2008/03/json-requestrest.html



    GWTで開発したいがサーバサイドとのやり取りをRPCにすることはちょと無理.という状況に一つの解決案がありました.それが
    GWT on Rails
    http://code.google.com/p/gwt-on-rails/
    です.

    これは
    1.Railsで作ったモデルをJavaクラスにしてくれます.
     (これはGWTでコンパイルしてクライアントで使えるようになる.)
    2.このJavaクラスの値が必要な場合JSON Request/RESTを発行し,サーバに問い合わせてクライアント側で利用できるように親クラスができあがります.
     (こいつもGWTでコンパイルしてクライアントで使えるようになる.)
    という事ができます.

    ということでこいつをやってみました(サンプル的に参照(show)のみ).



    ところでまず"JSON Request/RESTを処理できるサーバ"が必要になります.
    こいつは実はRails2系だと以下のようにするだけで動くようです.
    (Leopardに2系を入れる話はこれ
    1. JSON Request/RESTを処理するサーバを作る
    1.0 下準備
    (Projectというモデルを作りid=1を登録しておくところまで)
    script/generate model Project

    db/migrate/001_create_projects.rb
    class CreateProjects < ActiveRecord::Migration
    def self.up
    create_table :projects do |t|
    t.primary_key :id
    t.string :name, :null => false

    t.timestamps
    end
    end

    def self.down
    drop_table :projects
    end
    end

    script/generate migration InsertProjects

    db/migrate/002_insert_projects.rb
    class InsertProjects < ActiveRecord::Migration
    def self.up
    Project.create(:id=>1, :name=>"FooBar")
    end

    def self.down
    end
    end

    rake db:migrate


    1.1 コントローラの実装(showだけ)
    script/generate controller Projects

    app/controllers/projects_controller.rb
    class ProjectsController < ApplicationController
    def show
    @project = Project.find(params[:id])
    respond_to do |format|
    format.xml { render :xml=>@project }
    format.json { render :json=>@project }
    end
    end

    end

    (コントローラ,ビューをしっかり書けば1.2系でも動くハズ)

    1.2 REST処理用のルートの指定
    config/routes.rb
    ActionController::Routing::Routes.draw do |map|
    map.resources :projects

    2行目に追加(評価順序の都合で上の方に追加)

    rake routes















    projectsGET/projects{:action=>"index", :controller=>"projects"}
    formatted_projectsGET/projects.:format{:action=>"index", :controller=>"projects"}
    POST/projects {:action=>"create", :controller=>"projects"}
    POST/projects.:format{:action=>"create", :controller=>"projects"}
    new_projectGET/projects/new{:action=>"new", :controller=>"projects"}
    formatted_new_projectGET/projects/new.:format{:action=>"new", :controller=>"projects"}
    edit_projectGET/projects/:id/edit{:action=>"edit", :controller=>"projects"}
    formatted_edit_projectGET/projects/:id/edit.:format{:action=>"edit", :controller=>"projects"}
    projectGET/projects/:id{:action=>"show", :controller=>"projects"}
    formatted_projectGET/projects/:id.:format{:action=>"show", :controller=>"projects"}
    PUT/projects/:id {:action=>"update", :controller=>"projects"}
    PUT/projects/:id.:format{:action=>"update", :controller=>"projects"}
    DELETE/projects/:id {:action=>"destroy", :controller=>"projects"}
    DELETE/projects/:id.:format{:action=>"destroy", :controller=>"projects"}
    /:controller/:action/:id
    /:controller/:action/:id.:format


    ここまででJSON Request/RESTを処理するサーバ完成.
    1.x 確認
    起動
    script/server

    wget --header='Accept: application/xml' http://localhost:3000/projects/1
    curl -H 'Accept: application/xml' http://localhost:3000/projects/1
    <?xml version="1.0" encoding="UTF-8"?>
    <project>
    <created-at type="datetime">2008-03-08T00:00:00+09:00</created-at>
    <id type="integer">1</id>
    <name>FooBar</name>
    <updated-at type="datetime">2008-03-08T00:00:00+09:00</updated-at>
    </project>

    wget --header='Accept: application/json' http://localhost:3000/projects/1
    curl -H 'Accept: application/json' http://localhost:3000/projects/1
    {"name": "FooBar", "updated_at": "2008/03/08 00:00:00 +0900", "id": 1, "created_at": "2008/03/08 00:00:00 +0900"}
    できた♪

    2. GWTのコードを生成する.
    2.0 下準備 肝心要のPlug-in♪
    script/plugin install http://gwt-on-rails.googlecode.com/svn/trunk/gwt_on_rails


    2.1 Resource部分
    モデルのProjectをまずは反映します.
    アプリケーション名をここではdashboardとしています.
    script/generate gwt_resource Project dashboard


    2.2 Client部分
    もう一度migrate.
    rake db:migrate

    script/generate gwt_client dashboard ${GWT_HOME}

    ここで${GWT_HOME}はgwtの展開ディレクトリまでのパスです.
    (macだと'gwt-mac-1.4.61'フォルダとか / GWTここからダウンロードする.)

    app/gwt/dashboard/src/dashboard/client/Dashboard.java
    (id=1のProjectを取得してnameの値をAlertダイアログで表示というのをGWTのサンプルに追加)

    button.addClickListener(new ClickListener() {
    public void onClick(Widget sender) {
    ResourceCollection projects = new RailsJsonResourceCollection(
    "http://localhost:3000/projects/", new ResourceFactory() {
    public Resource create() {
    return (Resource) GWT
    .create(Project.class);
    }
    });
    projects.find(0,
    new ResourceResponseHandler() {
    public void onSuccess(Resource resource) {
    Window.alert("Project name is " + ((Project) resource).getName());
    }

    public void onError(Request request, Throwable exception) {
    Window.alert("Something went wrong.");
    }
    });


    if (label.getText().equals(""))
    label.setText("Hello World!");

    "http://localhost:3000/projects/"はJSON Requestを投げるURL

    2.3 GWTコンパイル
    rake dashboard:compile

    完成♪

    3. 試す
    3.1
    scripte/server


    3.2
    ブラウザでhttp://localhost:3000/dashboard/を開く
    重要!! Dashboard.java編集時に用いたJSON Requestを投げるサーバと文字列的に同じでないとセキュリティーエラーとなりRequestを投げないので注意!(これでハマった.Ajax屋さんは常識なんでしょうねw.)

    3.3
    clickボタンをクリック.Alert Dialogが表示される. ここにid=1の要素のname属性が表示される(FooBar).


    って感じ.

    2008年2月17日日曜日

    GWT-Ext用のEclipse内でのbuild.xmlを考える.

    ・必要なファイル達についてはこちらの'0'の項を参照してください.
    ・プロジェクト('MyProject')の作成はこちらの'1-3'を参照してください.


    (必要なら)web.xmlを用意.
    MyProject/WEB/web.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>

    <welcome-file-list>
    <welcome-file>MyProject.html</welcome-file>
    </welcome-file-list>

    </web-app>



    MyProject/build.properties
    #
    src.dir=src
    dist.dir=dist

    #
    gwt.location=GWT_HOME
    gwtext.location=GWTExt_HOME
    ext.location=ExtJS_HOME

    #
    project.package=com.mycompany
    src.public.dir=${src.dir}/${project.package}/public
    gwt.entrypoint.class=${project.package}.MyProject
    content.dir=${dist.dir}/${gwt.entrypoint.class}
    war.name=MyProjectWeb

    #
    tomcat.webapps=TOMCAT_HOME/webapps


    MyProject/build.xml
    <project name="MyProject" default="build" basedir=".">
    <property file="build.properties" />

    <path id="gwt.compile.classpath" >
    <pathelement path="${java.class.path}/" />
    <pathelement location="${src.dir}" />
    <pathelement location="${gwt.location}/gwt-user.jar" />
    <pathelement location="${gwt.location}/gwt-dev-mac.jar" />
    <pathelement location="${gwtext.location}/gwtext.jar" />
    </path>

    <target name="clean" >
    <delete dir="${dist.dir}" />
    </target>

    <target name="build" >
    <java classpathref="gwt.compile.classpath"
    classname="com.google.gwt.dev.GWTCompiler"
    maxmemory="128m"
    fork="true">
    <arg value="-out" />
    <arg value="${dist.dir}" />
    <arg value="${gwt.entrypoint.class}" />
    </java>
    </target>

    <target name="dist" depends="build">
    <mkdir dir="${content.dir}/js/ext" />
    <copy todir="${content.dir}/js/ext">
    <fileset dir="${ext.location}">
    <exclude name="*-debug.js" />
    <include name="*.js" />
    <include name="adapter/**/*" />
    <include name="resources/**/*" />
    </fileset>
    </copy>
    <copy todir="${content.dir}/WEB-INF">
    <fileset dir="WEB-INF">
    <include name="web.xml"/>
    </fileset>
    </copy>
    <mkdir dir="${content.dir}/WEB-INF/lib" />
    <copy todir="${content.dir}/WEB-INF/lib">
    <fileset dir="${gwt.location}">
    <include name="gwt-servlet.jar"/>
    </fileset>
    </copy>
    <mkdir dir="${content.dir}/WEB-INF/classes" />
    <copy todir="${content.dir}/WEB-INF/classes">
    <fileset dir="bin">
    <include name="**/*.class"/>
    </fileset>
    </copy>
    <jar jarfile="${dist.dir}/${war.name}.war"
    basedir="${dist.dir}/${gwt.entrypoint.class}" />
    </target>

    <target name="deploy" depends="dist">
    <copy todir="${tomcat.webapps}"
    file="${dist.dir}/${war.name}.war" />
    </target>
    </project>

    #WEB-INF以下にclasses/**/*.class, lib/servlet.jarをcopyするところはRPC用.


    プロジェクトはこんな感じ.



    Ant実行終了時にできたファイル等をExplorerに反映するためにRefreshにチェックをいれておくと便利.


    MyProject.javaをいじる前にMyProject.gwt.xmlのmodule要素の直下に一行追加するのをお忘れないように…
    #私が忘れてハマっただけです…
    MyProject/src/sample/MyProject.gwt.xml
    <module>
    <inherits name='com.gwtext.GwtExt' />

    2008年2月16日土曜日

    GWT RPCの例(というより梱包するjarについて

    GWT RPCの例としてこちらを参考にしました.
    最近のちょっ得: Google Web Toolkit まとめ
    http://salt.air-nifty.com/salt/2006/06/google_web_tool_7bcf.html




    で,
    (ホントは、ここに書かれてるとおり、webapps/MyApplication/WEB-INF/lib の中に、gwt-user.jar から javax フォルダを消して再圧縮した gwt-user.jar を置けばいいみたいなのだけど。)

    って事なんですがそんな面倒な,それくらい用意しているんじゃないの?ってことであれこれjarをあけてみるとgwt-servlet.jarがありました.これって最近のことなんでしょうかね?苦労された方々の上になりたっているですねきっと.

    で,
    WEB-INF/lib/gwt-servlet.jar

    と置くだけであとは勝手に使ってくれました(JAKARTA_TOMCAT).

    ちなみにMyApplicationはapplicationCreatorが作ったもののonClickの中を以下のようにしてみた.
    client/MyApplication.java
     tService.myMethod("send message", new AsyncCallback() {
    public void onFailure(Throwable caught) {
    }
    public void onSuccess(Object result) {
    String str = (String) result;
    if (label.getText().equals("----"))
    label.setText(str);
    else
    label.setText("----");
    }
    });


    MyServiceImplのmyMethodはこんな感じ
    server/MyServiceImpl.java
     public String myMethod(String s) {
    s+= "*";
    return s;
    }


    warへ固めることを考えるとcompileした時に作られるwwwの下にWEB-INF関連も作ってくれれば良いのにね.
    www/com.mycompany.MyApplication/WEB-INF/web.xml
    www/com.mycompany.MyApplication/WEB-INF/classes/**/*.class
    www/com.mycompany.MyApplication/WEB-INF/lib/gwt-servlet.jar

    みたいに.

    でもって
    www/com.mycompany.MyApplication/*

    も含めてwarを作ればよいわけだ.
    > cd ${MyProject_loc}/www/com.mycompany.MyApplication
    > jar cvf ../com.mycompany.MyApplication.war *

    って感じ.

    #あるのか?そういうオプションかなにかがあるのか?
    #'-eclipse'みたいな何かが?

    GWT自体がApacheライセンス2.0らしいのでApache2.0のライセンス文書もwarに梱包してgwt-servlet.jarも含めて配布ってことでいいっすか?

    GWT開発をEclipseで開始する時の方法(これが正攻法?

    ここに書いてあった.
    Getting Started - Google Web Toolkit - Google Code
    http://code.google.com/webtoolkit/gettingstarted.html



    0.ディレクトリを用意.
    > mkdir MyProject
    > cd MyProject


    1.Eclipseのプロジェクト(関連ファイル)作成
    > ${GWT_HOME}/projectCreator -eclipse MyProject


    2.GWTのプロジェクト作成
    > ${GWT_HOME}/applicationCreator -eclipse MyProject com.mycompany.client.MyApplication


    3.EclipseにImport
     メニューの'File/Import...'を選択.
     Dialogが表示される. 'General/Existing Projects into Workspace'を選択.
     Select root directory ...にてMyProjectディレクトリを選択.
     Projects中にMyProjectが表示される(はず).
     FInish!.

    4.実行
     メニューの'Run/Open Run Dialog...'を選択
     Dialogが表示される.Java Applicationの中にMyApplicationという項があるので選択.
     Run!.


    5.表示
     GWTのサーバが起動.
     ブラウザが以下のように表示される.
     

     こいつの苦労は...orz.

    2008年2月15日金曜日

    GWT-ExtのHelloWorldをやってみる / Eclipse 3.3 / MacOSX 10.5

    追記(2008/09/29)
    このページをみていただいたそうですが私よりわかりやすい文章の解説ページが作成されていました.
    Ext.JS情報|株式会社エイシーエル
    http://www.acl-inc.co.jp/modx/gwt_ext.html


    追記
    最近このページへのアクセスがちょっと多いのでコメントしときますがEclipse+GWTの開発はこっちがおそらく正攻法です.



    参考はこれ.
    Tutorial:Introduction to GWT-Ext 2.0
    http://gwt-ext.com/wiki/index.php/Tutorial:Introduction_to_GWT-Ext_2.0



    0. 用意するもの
     参考にある用意するもののうちJava SDKはLeopard付属のモノ(JDK1.5)をつかう.

    0.1 GWT
     ここここからdownload (1.4.61).
     #10.5なのでLeopard用(!).
     どこかに展開しておく.

     開発用の道具等も含まれているのでそれなりの所に.
     この展開した場所をGWT_HOMEと呼ぶことにする.

    0.2 Ext JS
     ここここからdownload (2.0.1).
     どこかに展開しておく.

     参考にもあるように最終的に必要なのは以下だ.
     (-debug.jsはいらないように思う)
    * /adapter
    * /resources
    * ext-all.js
    * ext-all-debug.js
    * ext-core.js
    * ext-core-debug.js


    0.3 GWT-Ext
     ここここからdownload (2.0.1).

     こいつで必要なのは'gwtext.jar'のみ.
     この展開した場所をGWTExt_HOMEと呼ぶことにする.

    1. プロジェクトの作成
     とりあえずJavaプロジェクト(名前は'GWTExt_HelloWorld'とした.)で.
     (あと作成時に'Project Layout'として'Create separate folders for sources and class files'を選んでます.

    2.外部jarの設定
     必要なのjarとして以下のjarをプロジェクトのPropertiesでJava Build Path項のLibrariesタブにて設定する.
     #あとでlib/gwtext.jarを説明のしやすさの都合で置くのでgwtext.jarについてはこちらでも良い.
    GWT_HOME/gwt-dev-mac.jar
    GWT_HOME/gwt-user.jar
    GWTExt_HOME/gwtext.jar

    追記:gwt-dev-mac.jarはいらないみたいです.すみません.
       (画像との整合性の都合で消さないですけど…)



    3.説明の都合で行う作業
     プロジェクト内にlibフォルダを作成.
     libにgwtext.jar(GWTExt_HOME/gwtext.jar)をimportする.

     ここまでのプロジェクトはこんな感じ.


    4.(GWTとしての)プロジェクトの作成
     外部ツールの設定を行う.
     このアイコンからメニューを出して'Open External Tool Dialog ...'を選ぶ.


     で,左のツリーの中からProgramというアイテムを選択しておいて左上'New'(下のアイコン)のボタンを押す.

     でもって各値を設定(Mainタブだけですw).
    Locatoin: ${GWT_HOME}/applicationCreator
    Working Directory: ${workspace_loc:GWT_Ext_HelloWorld}
    Argument: com.mycompany.mypackage.client.HelloWorld

     LocationはBrowse File System...でGWT_HOMEにあるapplicationCreatorを指定.
     ('${GWT_HOME}は自分で設定したら使えるけど通常はないので直接選択すればよい.
     Working DirectoryはBrowse Workspace...でGWTExt_HelloWorldを指定.
     Argumentsは参考のままw.(clientの文字はないといけないみたい.)
     Nameはテキとー.

     でRun!

     プロジェクトルートでコンテキストメニュ(右クリック)を出してRefreshすると作成されたファイルが見える.
     こんな感じ.


    5.Ext JSを配置する.
     src/com/mycompany/mypackage/publicの下に'js/ext'ディレクトリを作成
     0.2でも書いた以下のファイルをこのextディレクトリにimportする.
    * /adapter
    * /resources
    * ext-all.js
    * ext-core.js

     こんな感じになる.


    6.HelloWorld-compileを編集
     javaコマンドのクラスパス(-cpの次の引数)に'GWTExt_HOME/gwtext.jar'を追加する.
     3.をやっている人は'./lib/gwtext.jar'となる.
    変更前: .../gwt-dev-mac.jar" com.google.gwt.dev.GWTCompiler ...
    変更後: .../gwt-dev-mac.jar:./lib/gwtext.jar" com.google.gwt.dev.GWTCompiler ...


    7.HelloWorld-shellを編集
     javaコマンドのクラスパス(-cpの次の引数)に'GWTExt_HOME/gwtext.jar'を追加する.
     3.をやっている人は'./lib/gwtext.jar'となる.
    変更前: .../gwt-dev-mac.jar" com.google.gwt.dev.GWTShell ...
    変更後: .../gwt-dev-mac.jar:./lib/gwtext.jar" com.google.gwt.dev.GWTShell ...


    8.src/com/mycompany/mypackage/HelloWorld.gwt.xmlを編集
     参考のとおり内容を以下に置き換える.
    <module>
    <!-- Inherit the core Web Toolkit stuff. -->
    <inherits name='com.google.gwt.user.User' />
    <!-- Inherit the GWTExt Toolkit library configuration. -->
    <inherits name='com.gwtext.GwtExt' />
    <!-- Specify the app entry point class. -->
    <entry-point class='com.mycompany.mypackage.client.HelloWorld' />
    <stylesheet src="js/ext/resources/css/ext-all.css" />
    <script src="js/ext/adapter/ext/ext-base.js" />
    <script src="js/ext/ext-all.js" />
    </module>



    9.src/com/mycompany/mypackage/public/HelloWorld.htmlを編集
     参考のとおり内容を以下に置き換える.
     #開くときはそのままだとWeb Browserで開く(ことがある).
     #コンテキストメニュ(右クリック)でOpen With .../Text Editorとする.
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <meta http-equiv="Content-Language" content="en-us">
    <meta http-equiv="Content-Author" content="Sankar Gorthi">
    <title>Hello World</title>
    </head>
    <body>
    <iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>
    <!-- The GWT js file generated at run time -->
    <script type="text/javascript" src='com.mycompany.mypackage.HelloWorld.nocache.js'></script>
    </body>
    </html>


    10.src/com/mycompany/mypackage/client/HelloWorld.javaを編集
     参考の通り'public void onModuleLoad()'メソッドの内容を以下に置き換える.
    public void onModuleLoad() {
    Panel mainPanel = new Panel();

    // Setting the Panel's properties
    mainPanel.setTitle("Hello World!");
    mainPanel.setHeight(300);
    mainPanel.setWidth(500);
    RootPanel.get().add(mainPanel);
    }

     Panelはcom.gwtext.client.widgets.Panelをimportする.

    11.起動
     HellowWorld-shellを実行.

     外部ツールの設定を行う.
     このアイコンからメニューを出して'Open External Tool Dialog ...'を選ぶ.


     で,左のツリーの中からProgramというアイテムを選択しておいて左上'New'(下のアイコン)のボタンを押す.

     でもって各値を設定(Mainタブだけですw).
    Locatoin: ${workspace_loc:/GWTExt_HelloWorld/HelloWorld-shell}
    Working Directory: ${workspace_loc:GWTExt_HelloWorld}
    Argument:

     LocationはBrowse Workspace ...でGWTExt_HelloWorld(プロジェクト)にあるHelloWorld-shellを指定.
     Working DirectoryはBrowse Workspace...でGWTExt_HelloWorldを指定.
     Argumentsは空.
     Nameはテキとー.

     でRun!

     'tomcat'というディレクトリができるこいつはGWTのサーバの環境用らしい.

    12.表示.
     起動した'Google Web Toolkit Development Shell / Port 8888'ウインドウとそのブラウザでの表示.



    13.コンパイル
     HellowWorld-compileを実行.
     外部で(GWTのサーバでなく)使うためのコードを用意するため(?).

     外部ツールの設定を行う.
     このアイコンからメニューを出して'Open External Tool Dialog ...'を選ぶ.


     で,左のツリーの中からProgramというアイテムを選択しておいて左上'New'(下のアイコン)のボタンを押す.

     でもって各値を設定(Mainタブだけですw).
    Locatoin: ${workspace_loc:/GWTExt_HelloWorld/HelloWorld-compile}
    Working Directory: ${workspace_loc:GWTExt_HelloWorld}
    Argument:

     LocationはBrowse Workspace ...でGWTExt_HelloWorld(プロジェクト)にあるHelloWorld-compileを指定.
     Working DirectoryはBrowse Workspace...でGWTExt_HelloWorldを指定.
     Argumentsは空.
     Nameはテキとー.

     でRun!

     'www'というディレクトリにファイル群ができる.
     この中のHelloWorld.htmlファイルをFinder等で表示して直接クリックすればSafariがfile://...でアクセスして表示する.

    GWT-ExtのShowcase2 Demoをローカルで動かす.

    00. GWT-ExtDemo (Showcase2)が面白かったのでとりあえずダウンロード

    01. で,展開してみた.

    02. samplesディレクトリ発見.降りていく.

    03. 'samples/Showcase2/www/com.gwtext.sample.showcase2.Showcase2/Showcase2.html'を発見.

    04. こいつをクリック.file:...でブラウザ(Safari)が起動.

    05. …おっイメージないけどInitalizingとか出てるなー.…止まってるのか..orz

    06. Safari:ウインドウ/構成ファイル一覧を確認..../js/ext以下がないらしい.

    07. そんな(''samples/Showcase2/www/com.gwtext.sample.showcase2.Showcase2/js/ext')ディレクトリない.

    08. ‘!’.そっかextのjsはExt JSから取ってくるのか.

    09. Ext JSからダウンロード

    10. 'ext-2.0.1.zip'を取得. 展開. 'ext-2.0.1'ディレクトリができる.

    11. 先ほどの'samples/Showcase2/www/com.gwtext.sample.showcase2.Showcase2/js/'に移動させる.

    12. 'ext-2.0.1'から'ext'に名前変更.
    結果jsディクレクトリの中はこうなる.


    13. 再度'samples/Showcase2/www/com.gwtext.sample.showcase2.Showcase2/Showcase2.html'をクリック.

    14. Safariが起動.

    15. おぉ.でたでた.


    って感じでした.
    #経緯をそのまま.