love fish大鵬一曰同風(fēng)起,扶搖直上九萬里

          常用鏈接

          統(tǒng)計

          積分與排名

          friends

          link

          最新評論

          Google Web Toolkit(翻譯)

          原文出處:XML.comhttp://www.xml.com/pub/a/2006/07/12/google-web-toolkit-ajax-java-ant-xml.html
          翻譯:劉嘉晗 http://www.aygfsteel.com/johnlau

          Google Web Toolkit

          By Bruce Perry
          2006年7月12日

          如果你是一名Java軟件或Ajax開發(fā)者,可能Google Web Toolkit(GWT)已經(jīng)引起了你的注意。

          2006年5月,Google發(fā)布了這一免費(fèi)的工具箱,遵循Apache風(fēng)格的許可證。GWT被設(shè)計用于以Java語言編寫Ajax應(yīng)用。Google已經(jīng)提供了Windows和Linux下的beta版本,并承諾以后增加Mac OS X版本。

          本文描述了在Max OS X上一個簡單的Ajax應(yīng)用的開發(fā),使用GWT和常用的Java工具,如Apache Ant,Tomcat 5.0 Servlet容器,以及IntelliJ IDEA集成開發(fā)環(huán)境(后者是一款商業(yè)IDE)。本文假設(shè)讀者具有Java和Ant的基本知識。

          結(jié)合使用Ant與GWT


          我下載了GWT Linux beta版本,用Java編寫了我的應(yīng)用程序,然后用一個Ant構(gòu)建文件編譯和在一個Tomcat 5.0實(shí)例上部署了此程序。Ant文件執(zhí)行GWT Java-to-JavaScript編譯器。此“編譯器”是一個命令行腳本,它執(zhí)行一個GWT Java類,而后者為應(yīng)用程序輸出JavaScript腳本。

          使用GWT beta包括兩種開發(fā)模式:宿主(host)模式和web模式。

          宿主模式是一個開發(fā)中的中間步驟,它使用內(nèi)嵌的GWT瀏覽器;在這種模式下,已編譯代碼繼續(xù)在Java虛擬機(jī)(JVM)中運(yùn)行。然而,宿主模式對于我們這些借用Linux版本的Mac OS X用戶還不可用。Mac OS X下的宿主模式要等到Max OS X版本發(fā)布了。

          一種不同的web開發(fā)方式


          本文探討了GWT開發(fā)者在為遠(yuǎn)程過程調(diào)用(RPC)創(chuàng)建服務(wù)時可能面對的一些典型的web開發(fā)相關(guān)的任務(wù)。RPC是用于使用面向服務(wù)架構(gòu)(SOA)的應(yīng)用的軟件模型的一部分。這些開發(fā)任務(wù)包括:

          • 使用構(gòu)建文件自動化開發(fā)和開發(fā)步驟(構(gòu)建過程運(yùn)行GWT編譯器,然后將編譯器的輸出和服務(wù)器端Java類文件部署到一個servlet容器,如Tomcat,Jetty或Resin)。
          • 使用Firefox的DOM Inspector查看GWT應(yīng)用程序生成的HTML。
          • 重新設(shè)計頁面控件而不需改動底層HTML(因為你在使用GWT的Java API)。
          • 確定HTML已合法地標(biāo)記,例如,基于你的組織所要求的特定格式的XHTML文檔。

          為您服務(wù)


          首先,我會簡要描述該應(yīng)用程序創(chuàng)建的服務(wù)。它被設(shè)計用來展示GWT采用的模式。

          該應(yīng)用程序在瀏覽器中顯示一個表單,要求用戶輸入名字,年齡,以及國家。當(dāng)用戶通過點(diǎn)擊按鈕提交表單時,程序在一個文本區(qū)內(nèi)顯示一條服務(wù)器回應(yīng)而不需刷新頁面。圖1是程序在Safari瀏覽器中的顯示。

          圖1: GWT生成的一個簡單視圖

          例如,當(dāng)用戶在一個文本框為空時點(diǎn)擊OK,Submit按鈕時,結(jié)果如圖2所示。

          圖2: 應(yīng)用程序以紅色顯示一條錯誤信息

          巧妙的服務(wù)機(jī)制


          在Ajax應(yīng)用中使用RPC消除了顯式地處理XMLHttpRequest和相關(guān)聯(lián)的服務(wù)器返回值的需要,因為GWT對象會為你處理這些通訊工作。

          程序定義的每個服務(wù)需要兩個Java接口和一個Java類。為了編譯這些類,需要確定gwt-user.jar庫在classpath中(Ant文件中增加一個條目就可以解決)。以下代碼示范了定義我們的服務(wù)的Java接口。


          package?com.parkerriver.gwt.testapp.client;

          import?com.google.gwt.user.client.rpc.RemoteService;

          public?interface?ShowRespService?extends?RemoteService{
          ????String?displayResponse(String?req);
          }


          服務(wù)接口必須擴(kuò)展GWT接口RemoteService。它只定義了一個方法 displayResponse()。

          你還需要定義一個接口,客戶端或最終被下載的JavaScript代碼將會用它調(diào)用服務(wù)方法。GWT使用了一種回調(diào)設(shè)計模式,當(dāng)我給出客戶端代碼的時候會再來描述它(請看MyForm.java)。

          package?com.parkerriver.gwt.testapp.client;

          import?com.google.gwt.user.client.rpc.AsyncCallback;

          public?interface?ShowRespServiceAsync?{
          ????
          public?void?displayResponse(String?s,
          ????????????????????????????????AsyncCallback?callback);
          }


          要使一個服務(wù)在GWT中可用必須遵守命名約定;在服務(wù)接口名(ShowRespService)后增加Async后綴。AsyncCallback對象是GWT API的一部分,它的目的是為客戶端處理服務(wù)響應(yīng)。不管怎樣,等你看了這段代碼應(yīng)用的地方后會對這一行為有更清晰的了解。這些對象定義都位于用于生成客戶端JavaScript的Java代碼中。

          一個改頭換面的servlet


          最后,你需要定義一個Java類來實(shí)現(xiàn)遠(yuǎn)程服務(wù)接口。這個類將會存在于你的Ajax應(yīng)用程序的服務(wù)器端。

          package?com.parkerriver.gwt.testapp.server;

          import?com.parkerriver.gwt.testapp.client.ShowRespService;
          import?com.google.gwt.user.server.rpc.RemoteServiceServlet;
          import?java.util.Date;

          public?class?ShowRespServiceImpl?extends?RemoteServiceServlet
          ????????
          implements?ShowRespService??{
          ????
          public?String?displayResponse(String?req)?{
          ????????
          if(req.length()?<?1)?{
          ????????????
          throw?new?IllegalArgumentException(
          ????????????????????
          "Blank?submissions?from?the?client?are?invalid.");
          ????????}
          ????????StringBuffer?buf?
          =?new?StringBuffer("Your?submission:?");
          ????????Date?date?
          =?new?Date();
          ????????String?serverInfo?
          =?this.getServletContext().getServerInfo();
          ????????buf.append(req);
          ????????buf.append(
          "\n");
          ????????buf.append(
          "Server?response:?");
          ????????buf.append(date.toString());
          ????????buf.append(
          "\n");
          ????????buf.append(serverInfo);
          ????????
          return?buf.toString();
          ????}
          }


          該類必須擴(kuò)展RemoteServiceServlet,這是一個GWT API對象,它本身擴(kuò)展了javax.servlet.http.HttpServlet。也就是說,該類和它實(shí)現(xiàn)的接口需要被部署到你的servlet容器。

          步驟


          現(xiàn)在我們已經(jīng)定義了服務(wù),讓我們退回幾分鐘來看一看程序的目錄結(jié)構(gòu)。Google Web Toolkit包括了一個名為applicationCreator的命令行腳本,它將會為你生成項目目錄結(jié)構(gòu)。解壓縮GWT下載包后,你可以在頂層目錄中找到applicationCreator。我使用下面的命令行來開始:

          applicationCreator?-out?/Users/bruceperry/1gwt/secondapp/?com.parkerriver.gwt.testapp.client.MyForm

          圖3顯示了目錄結(jié)構(gòu)

          圖3: 一個GWT和IntelliJ項目目錄

          applicationCreator生成./src目錄和MyForm-compile以及MyForm-shell腳本。我的Ant文件執(zhí)行MyForm-compile;另一個腳本運(yùn)行宿主模式。./src目錄包括與最初的包命名相符的嵌套目錄結(jié)構(gòu),如圖4所示。

          圖4:一個GWT應(yīng)用程序的包和模塊

          文件MyForm.gwt.xml是生成的配置文件,GWT稱之為“模塊(module)”。它為你的程序定義了表示“入口點(diǎn)(entry point)”的Java類,類似于包含main()方法的Java類。

          <module>
          ????
          <!--Inherit?the?core?Web?Toolkit?stuff.??????????????????-->
          ????
          <inherits?name="com.google.gwt.user.User"/>
          ????
          <!--Specify?the?app?entry?point?class.???????????????????-->
          ????
          <entry-point?class="com.parkerriver.gwt.testapp.client.MyForm"/>
          </module>


          其它的文件或目錄是IntelliJ Web application project的產(chǎn)物,包括./classes,./WEB-INF,和./gwtproj.ipr,所以不需要特別留意它們。

          另外,./www目錄之前并不會出現(xiàn)(除非你自己創(chuàng)建它),直到運(yùn)行GWT編譯器生成程序代碼。我的項目使用Ant文件getproj.xml,而項目屬性在gwtproj.properties中定義。在我展示Ant構(gòu)建文件之前,我們先看一下代表程序入口點(diǎn)的MyForm.java類。

          入口點(diǎn)


          MyForm.jaca類實(shí)現(xiàn)了GWT API接口EntryPoint。所以,該類必須實(shí)現(xiàn)onModuleLoad()方法,當(dāng)瀏覽器載入你的Ajax程序時,瀏覽器的JavaScript引擎將會調(diào)用它。

          換句話說,GWT編譯器將這個類編譯為JavaScript代碼。MyForm.java類為瀏覽器視圖建立表單控件。該類同時決定了用戶點(diǎn)擊OK,Submit按鈕時的響應(yīng)。代碼中的注釋詳細(xì)描述了到底發(fā)生了什么,所以我在正文中不再贅述。

          package?com.parkerriver.gwt.testapp.client;

          import?com.google.gwt.core.client.EntryPoint;
          import?com.google.gwt.core.client.GWT;
          import?com.google.gwt.user.client.DOM;
          import?com.google.gwt.user.client.Window;
          import?com.google.gwt.user.client.Element;
          import?com.google.gwt.user.client.rpc.ServiceDefTarget;
          import?com.google.gwt.user.client.rpc.AsyncCallback;
          import?com.google.gwt.user.client.ui.*;

          import?java.util.Iterator;

          public?class?MyForm?implements?EntryPoint?{
          ????
          //提供狀態(tài)信息的HTML div元素的id
          ??? private?String?statusId?=?"status";
          ????
          //一個Grid對象;實(shí)際上,是一個HTML table
          ????private?Grid?grid?=?new?Grid(5,?2);
          ????
          //其它用戶界面對象
          ????private?Label??nmLab?=?new?Label();
          ????
          private?Label??ageLab?=?new?Label();
          ????
          private?Label??homeLab?=?new?Label();
          ????
          private?TextBox?nmTxt?=?new?TextBox();
          ????
          private?TextBox?ageTxt?=?new?TextBox();
          ????
          private?TextBox?homeTxt?=?new?TextBox();
          ????
          private?Button?okBut?=?new?Button();
          ????
          private?TextArea?tarea?=?new?TextArea();
          ????
          /* 當(dāng)瀏覽器載入應(yīng)用程序時本方法被調(diào)用。
          ??????? 本方法設(shè)置3個標(biāo)簽和文本框,以及一個
          ??????? 按鈕和用來顯示服務(wù)器相應(yīng)的文本區(qū)
          */
          ?????
          public?void?onModuleLoad()?{

          ????????
          //設(shè)置標(biāo)簽和文本域
          ????????nmLab.setText("Full?Name:");
          ????????nmTxt.setMaxLength(
          25);
          ????????ageLab.setText(
          "Age:");
          ????????ageTxt.setVisibleLength(
          3);
          ????????ageTxt.setMaxLength(
          3);
          ????????homeLab.setText(
          "Home?country:");
          ????????homeTxt.setMaxLength(
          25);
          ????????
          //將這些控件放入Grid中
          ????????grid.setWidget(0,0,nmLab);
          ????????grid.setWidget(
          0,1,nmTxt);
          ????????grid.setWidget(
          1,0,ageLab);
          ????????grid.setWidget(
          1,1,ageTxt);
          ????????grid.setWidget(
          2,0,homeLab);
          ????????grid.setWidget(
          2,1,homeTxt);

          ????????
          //設(shè)置按鈕和文本區(qū)
          ????????tarea.setCharacterWidth(40);
          ????????tarea.setVisibleLines(
          25);
          ????????okBut.setText(
          "OK,?Submit");
          ????????
          //通過增加一個listener對象為按鈕設(shè)置行為
          ????????
          //詳細(xì)地講,一個帶有onClick()事件處理器的
          ????????
          //ClickListener對象。
          ????????okBut.addClickListener(new?ClickListener()?{
          ????????????
          public?void?onClick(Widget?sender)?{
          ????????????????
          //提示用戶遠(yuǎn)程過程調(diào)用的狀態(tài);
          ????????????????
          //見下面的方法
          ????????????????showRpcStatus(true);
          ????????????????
          //為服務(wù)器端服務(wù)創(chuàng)建一個客戶端存根的實(shí)例
          ??????????????? ShowRespServiceAsync?respService?=
          ????????????????????????(ShowRespServiceAsync)?GWT
          ????????????????????????????????.create(ShowRespService.
          class);
          ????????????????ServiceDefTarget?endpoint?
          =?(ServiceDefTarget)?respService;
          ????????????????
          //我們的服務(wù)的實(shí)現(xiàn)是一個RemoteServiceServlet的實(shí)例,
          ????????????????
          //所以提供到該servlet的服務(wù)器路徑
          ????????????????
          //該路徑為web.xml中設(shè)置的值
          ????????????????endpoint.setServiceEntryPoint("/parkerriver/s/showresp");
          ????????????????
          //該接口處理服務(wù)器響應(yīng)。
          ????????????????
          //它會在一個文本區(qū)中顯示服務(wù)器的響應(yīng)。
          ????????????????
          //如果回復(fù)消息表示一個錯誤
          ????????????????
          //則將用紅色字體顯示
          ????????????????AsyncCallback?callback?=?new?AsyncCallback()?{
          ????????????????????
          public?void?onSuccess(Object?result)?{
          ????????????????????????
          //如有,則移除與錯誤消息外觀相關(guān)的‘warning’CSS樣式
          ????????????????????????
          //
          ????????????????????????if(tarea.getStyleName().
          ????????????????????????????????equalsIgnoreCase(
          "warning")){
          ????????????????????????????tarea.removeStyleName(
          "warning");
          ????????????????????????}
          ????????????????????????
          //文本區(qū)顯示服務(wù)器的返回值
          ????????????????????????tarea.setText((String)result);
          ????????????????????}
          ????????????????????
          public?void?onFailure(Throwable?caught)?{
          ????????????????????????
          //文本區(qū)顯示任何異常消息
          ????????????????????????tarea.setStyleName("warning");
          ????????????????????????tarea.setText(
          ????????????????????????????
          "Server?request?raised?an?error;?Java?exception?:?"+
          ????????????????????????????caught?
          ==?null???"An?unknown?exception"?:
          ????????????????????????????????????????caught.getMessage());
          ????????????????????}
          ????????????????};
          ????????????????
          //調(diào)用服務(wù)方法。
          ????????????????
          //首先驗證表單值。
          ????????????????try{
          ????????????????????respService.displayResponse(
          ????????????????????????????getPanelTextContent(grid,
          true),
          ????????????????????????????callback);
          ????????????????}?
          catch?(Exception?e)?{
          ????????????????????tarea.setStyleName(
          "warning");
          ????????????????????tarea.setText(
          "Server?request?raised?an?error:?"+
          ????????????????????????????e.getMessage());
          ????????????????}??
          finally?{
          ????????????????????
          //當(dāng)我們完成RPC調(diào)用時
          ????????????????????
          //移除狀態(tài)信息
          ????????????????????showRpcStatus(false);
          ????????????????}
          ????????????}
          ????????});

          ????????
          //現(xiàn)在將這些控件加到Grid上
          ????????grid.setWidget(3,0,okBut);
          ????????grid.setWidget(
          3,1,tarea);
          ????????
          //為OK按鈕的單元設(shè)定垂直對齊屬性
          ????????grid.getCellFormatter().setVerticalAlignment(3,0,
          ????????????????HasVerticalAlignment.ALIGN_TOP);
          ????????
          //為文本框設(shè)置垂直對齊屬性,
          ????????
          //以使它們合適地排列
          ????????grid.getCellFormatter().setVerticalAlignment(0,1,
          ????????????????HasVerticalAlignment.ALIGN_BOTTOM);
          ????????grid.getCellFormatter().setVerticalAlignment(
          1,1,
          ????????????????HasVerticalAlignment.ALIGN_BOTTOM);
          ????????grid.getCellFormatter().setVerticalAlignment(
          2,1,
          ????????????????HasVerticalAlignment.ALIGN_BOTTOM);


          ????????
          //將grid,實(shí)際上是一個HTML table,加到
          ????????
          //瀏覽器HTML中id值為"gridholder"的div元素中。
          ????????RootPanel.get("gridholder").add(grid);
          ????}
          ????
          /*簡單地測試是否有為空的域,然后以單一字符串返回
          ??? ?? 提交的值

          ??? ?? HasWidgets是Grid和其它panel類型的對象實(shí)現(xiàn)的一個接口。
          ??? ?? 因此,我們可以將grid傳入該方法;遍歷它包含的文本框,
          ??? ?? 并且驗證文本框的內(nèi)容。
          ????
          */
          ????
          private?String?getPanelTextContent(HasWidgets?panelType,
          ???????????????????????????????????????
          boolean?validateContent)?{
          ????????StringBuffer?buf?
          =?new?StringBuffer("");
          ????????String?tmp?
          =?null;
          ????????
          if(panelType?!=?null)?{
          ???????????
          //為了簡介,省略
          ????????}
          ????????
          //返回以空格分隔的文本框的內(nèi)容
          ???????
          return?buf.toString();
          ????}
          ????
          ????
          /* 過于簡化的驗證!?*/
          ????
          private?boolean?validateText(String?_content){
          ????????
          return?_content.length()?>?0;

          ????}

          ????
          private?int?getTextboxCount(HasWidgets?pType){
          ????????
          //未顯示: 返回panel中TextBox控件的數(shù)量
          ???????

          ????}

          ????
          /* 如果響應(yīng)很長時間才到達(dá)
          ???? 則顯示給用戶一個狀態(tài)信息。
          */
          ????
          private?void?showRpcStatus(boolean?_on){
          ????????
          //利用GWT DOM API進(jìn)行JavaScript DOM編程
          ??????

          ????????Element?el?=?DOM.getElementById(statusId);
          ????????
          if(el?!=?null)??{
          ????????????
          if(_on)?{
          ????????????????DOM.setStyleAttribute(el,
          "font-size","1.2em");
          ????????????????DOM.setStyleAttribute(el,
          "color","green");
          ????????????????DOM.setInnerHTML(el,?
          "Fetching?server?info");
          ????????????}??
          else{
          ????????????????DOM.setInnerHTML(el,?
          "");
          ????????????}
          ????????}

          ????}
          }


          代碼中大多部分處理GWT API。值得一提的是如果你需要實(shí)現(xiàn)JavaScript DOM編程,如showRpcStatus()方法中那樣,你可以通過使用com.google.gwt.user.client.DOM類實(shí)現(xiàn)這個任務(wù)。

          構(gòu)建文件


          以下是Ant構(gòu)建文件的重點(diǎn);它:
          1. 編譯Java文件,結(jié)果寫入項目目錄中的./classes目錄。
          2. 執(zhí)行GWT編譯腳本(本例中名為MyForm-compile)。
          3. 將./www目錄中生成的結(jié)果代碼移到一個已部署到Tomcat上的更大的web應(yīng)用。
          4. 復(fù)制編譯后的Java servlet和相關(guān)接口(ShowRespService)到同一個web應(yīng)用。

          負(fù)責(zé)編譯Java類和執(zhí)行到JavaScript的轉(zhuǎn)換的兩個Ant任務(wù)定義為如果產(chǎn)生任何錯誤,則使整個構(gòu)建失敗。

          Ant XML


          這里是gwtproj.properties文件包含的部分內(nèi)容:

          web.deploy.location=/users/bruceperry/parkerriver/gwt
          web.classes.location
          =/users/bruceperry/parkerriver/WEB-INF/classes


          下面的XML表示了上述Ant文件的主要內(nèi)容;完整文件的鏈接在本文的資源一節(jié)中。

          <?xml?version="1.0"?encoding="UTF-8"?>
          <project?name="gwtproj"?default="all">
          ????
          <property?file="gwtproj.properties"/>
          ????
          ?????
          <!--?The?top-level?directory?for?the?project?and
          ????where?the?ant?file?resides?
          -->
          ????
          <dirname?property="module.gwtproj.basedir"?file="${ant.file}"/>
          ????
          ?????
          <!--?The?./classes?directory?inside?the?top-level?directory?-->
          ?????
          <property?name="gwtproj.output.dir"?value=
          ????????????"${module.gwtproj.basedir}/classes"
          />
          ????????????
          ????
          <!--?This?target?calls?MyForm-compile?to?create
          ????all?the?content?in?the?./www?directory?
          -->
          ????
          <target?name="gwt-compile"?depends=
          ????????????"compile.production.classes"

          ????????????description
          ="use?gwt's?compiler">
          ????????
          <delete>
          ????????????
          <fileset?dir="${web.deploy.location}"?includes="**/*"/>
          ????????
          </delete>
          ????????
          <exec?executable=
          ????????????????"${module.gwtproj.basedir}/MyForm-compile"

          ??????????????failonerror
          ="true"/>
          ????????
          <copy?todir="${web.deploy.location}">
          ????????????
          <fileset?dir=
          ????????????????????"${module.gwtproj.basedir}/www"
          >
          ????????????
          </fileset>
          ????????
          </copy>
          ????
          </target>

          ????
          <target?name="compile.production.classes"?description=
          ????????????"Compile?the?gwtproj?production?classes"
          >
          ????????
          <mkdir?dir="${gwtproj.output.dir}"/>
          ????????
          <javac?destdir="${gwtproj.output.dir}"?debug=
          ????????????????"on"
          ?failonerror="true"?nowarn=
          ????????????????"off"
          ?memoryMaximumSize="128m"?fork=
          ????????????????"true"
          ?executable="${module.jdk.home.gwtproj}/bin/javac">
          ????????????
          <classpath?refid="gwtproj.module.classpath"/>
          ????????????
          <src?refid="gwtproj.module.sourcepath"/>
          ????????
          </javac>
          ????
          </target>
          ????
          ??
          <!--?copy?the?Java?servlet?classes?to?the?web?application?-->
          ????
          <target?name="deploy.classes"??depends="gwt-compile"
          ????????????description
          ="copy?classes?to?web?directory">
          ????????
          <copy?todir="${web.classes.location}">
          ????????????
          <fileset?dir="${gwtproj.output.dir}">
          ????????????
          </fileset>
          ????????
          </copy>
          ????
          </target>
          ????
          ????
          <target?name="all"?depends="deploy.classes"
          ????????????description
          ="build?all"/>
          </project>


          你可以在IDE中運(yùn)行該Ant文件(比如在IntelliJ中)或者在包含構(gòu)建文件的目錄中運(yùn)行下面的命令行:

          ant?-buildfile?gwtproj.xml


          大多數(shù)情況下,在更改應(yīng)用程序并運(yùn)行Ant后,你可以通過在瀏覽器中刷新頁面看到所作的改變。

          最后設(shè)置


          在最后的設(shè)置上,你可能需要了解的是添加gwt-user.jar庫到你的web應(yīng)用的/WEB-INF/lib目錄。

          我創(chuàng)建了我自己的JAR文件,去掉了其中的javax包,命名為gwt-user-deploy.jar,并添加到/WEB-INF/lib。這是因為Tomcat將不會載入web應(yīng)用程序中包含servlet API類的庫。

          web開發(fā)者的吹毛求疵


          applicationCreator同時創(chuàng)建了你的Ajax應(yīng)用程序的HTML前端,本例中名為MyForm.html。

          如果你的應(yīng)用程序的HTML需要遵從如XHTML transitional或Strict時怎么辦呢?對于XHTML transitional的情況,我首先在MyForm.html頂端增加了所需的DOCTYPE,以及html標(biāo)簽的相關(guān)屬性:

          <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Transitional//EN"
          ????????"http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"
          >
          <html?xmlns="http://www.w3.org/1999/xhtml"?xml:lang="en"?lang="en">


          然后我上傳MyForm.html到http://validator.w3.org/的World Wide Web協(xié)會的HTML驗證器。

          運(yùn)行驗證器后,我對HTML做了一些簡單的修改,如合適地關(guān)閉元標(biāo)簽以及增加type="text/javascript"到script標(biāo)簽。

          Strict:嘖嘖


          然而,如果你要遵從XHTML Strict標(biāo)準(zhǔn),則可能需要做一些更復(fù)雜的更改。例如,W3C的驗證器將iframe標(biāo)簽標(biāo)為“undefined element”,iframe是GWT的歷史支持所需要的(提供如瀏覽器的后退按鈕同樣的功能)。XHTML已經(jīng)移除了iframe元素。

          這對你可能不是一個問題(可能會同其它明顯問題一起在GWT的未來版本中解決);但是,你可以自己實(shí)現(xiàn)替代策略,如擴(kuò)展GWT的類和創(chuàng)建你自己的兼容的控件。

          使控件各就各位


          視覺外觀設(shè)計是web開發(fā)中總是出現(xiàn)的問題。項目設(shè)計者希望頁面看起來和他們在Adobe Illustrator中創(chuàng)建的一摸一樣,是嗎?

          盡管在復(fù)雜的Ajax項目中你可能無法實(shí)現(xiàn)這一使程序養(yǎng)眼的理想,至少你可以使用Firefox的DOM Inspector來檢視你的Java類最終生成的HTML。那么從這里開始。

          打開Firefox的Tools=>DOM Inspector菜單項(如圖5)

          圖5: 用DOM Inspector查看HTML

          可見Java代碼中的com.google.gwt.user.client.ui.Grid對象實(shí)現(xiàn)為一個HTML table標(biāo)簽。table中包含OK,Submit按鈕的TD標(biāo)簽與一個樣式屬性“verticle-align:top”關(guān)聯(lián)。

          這使按鈕與文本區(qū)頂端對齊。下面是MyForm.java類中設(shè)置對齊方式的代碼:

          //set?the?vertical?alignment?for?the?OK?button's?cell
          ????????grid.getCellFormatter().setVerticalAlignment(3,0,
          ????????????????HasVerticalAlignment.ALIGN_TOP);

          如果代碼中沒有此調(diào)用,按鈕就會很業(yè)余地掛在文本區(qū)的中間區(qū)域。

          現(xiàn)在要做的只是使按鈕與它上面的文本標(biāo)簽左對齊。

          資源

          ?? ?Google Web Toolkit: http://code.google.com/webtoolkit/
          ??? 本文代碼: gwtarticle_jul06.zip

          XML.com Copyright?? 1998-2006 O'Reilly Media, Inc.

          posted on 2006-07-21 01:31 liaojiyong 閱讀(571) 評論(1)  編輯  收藏 所屬分類: Ajax

          評論

          # re: Google Web Toolkit(翻譯) 2013-01-28 14:04 3

          3  回復(fù)  更多評論   

          主站蜘蛛池模板: 咸宁市| 阿拉善盟| 景洪市| 元阳县| 武乡县| 沿河| 寿光市| 江阴市| 定安县| 龙里县| 德州市| 丰城市| 南和县| 噶尔县| 青田县| 满城县| 江安县| 巴林左旗| 河南省| 承德县| 巴彦县| 康定县| 曲沃县| 永德县| 建湖县| 通城县| 永仁县| 商洛市| 翁牛特旗| 伊金霍洛旗| 阳原县| 寿阳县| 内丘县| 错那县| 什邡市| 邳州市| 三都| 北海市| 宝山区| 北川| 佛坪县|