Mostrando entradas con la etiqueta GWT. Mostrar todas las entradas
Mostrando entradas con la etiqueta GWT. Mostrar todas las entradas

martes, 23 de agosto de 2011

GWT - Organización de proyectos & compatiblidad con las librerias Java

Una URL muy util sobre como organizar nuestros proyectos en GWT es:


Individual units of GWT configuration are called modules. A module bundles together all the configuration settings that your GWT project needs:
  • inherited modules
  • an entry point application class name; these are optional, although any module referred to in HTML must have at least one entry-point class specified. Es la clase que extiende de EntryPoint.
  • source path entries: Son los archivos que luego seran traducidos a JavaScript
  • public path entries: Lugar donde se colocaran todos los recursos estáticos como imágenes, CSSs, etc.
  • deferred binding rules, including property providers and class generators


Creación de un modulo diferente (otro proyecto) con clases que necesitamos usar en el modulo GWT

Creating a second module doesn't necessarily mean that that module must define an entry point. Typically, you create a new module when you want to package up a library of GWT code that you want to reuse in other GWT projects. An example of this is the Google API Library for Google Web Toolkit (GALGWT), specifically the Gears for GWT API binding. If you download the library and take a look at the gwt-google-apis/com/google/gwt/gears you'll find the Gears.gwt.xml file for the module which doesn't define an entry point. However, any GWT project that would like to use Gears for GWT will have to inherit the Gears.gwt.xml module. For example, a module named "Foo" might want to use GALGWT, so in Foo.gwt.xml an <inherits> entry would be needed.

Por ejemplo, si las entidades de dominio estan en otro modulo diferente (proyecto diferente) al del modulo de GWT, entonces hay que crear un modulo gwt (somemodule.gwt.xml) en el modulo que necesitamos (en el de entidades de dominio) y agregar la dependencia (<inherits name="somemodule"/>) en el modulo donde queremos usar esas entidades (es decir, en el modulo GWT agregamos el tag inherits).



Para el caso de librerias de terceros (third parties) en un modulo GWT: 

Al agregar un JAR (que sea de GWT) como así tambien la dependencia de un modulo:

En el XML (modulo GWT) del modulo en cuestión (Ej  modulePrincipal.gwt.xml) agregar <inherits
name='com.thapar.gwt.user.ui.SimpleDatePicker'/>

El "com.thapar.gwt.user.ui.SimpleDatePicker" corresponde al XML (modulo GWT) del JAR.

Todo JAR a priori tiene que tener el XML (modulo GWT).



Subset de la JRE que son emuladas por la JRE de GWT


Ejemplo de un XML que identifica a un modulo GWT

StockWatcher.gwt.xml

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='stockwatcher'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>


  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <!-- <inherits name='com.google.gwt.user.theme.clean.Clean'/>-->
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
   <inherits name='com.google.gwt.user.theme.dark.Dark'/>     


  <!-- Other module inherits                                      -->


  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/>


  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>
  <source path='shared'/>
  
  <!-- Especificando el LOCALE -->
  <extend-property name="locale" values="de"/>


</module>


<inherits name="logical-module-name" /> 
Para heredar clases de otros modulos para que se traduzcan a Javascript

<entry-point class="classname" /> 
 Especifica el EntryPoint Class. En caso que haya varias, estas seran ejecutadas en orden de aparición.

<source path="path" /> 
Any Java source file appearing in this subpackage or any of its subpackages is assumed to be translatable

<public path="path" />
Any file appearing in this package or any of its subpackages will be treated as a publicly-accessible resource

<servlet path="url-path" class="classname" />
For RPC, this element loads a servlet class mounted at the specified URL path. The URL path should be absolute and have the form of a directory (for example, /calendar). Your client code then specifies this URL mapping by annotating the service interface with the @RemoteServiceRelativePath attribute. Any number of servlets may be loaded in this manner, including those from inherited modules.
NOTE: as of GWT 1.6, this tag does no longer loads servlets in development mode, instead you must configure a WEB-INF/web.xml in your war directory to load any servlets needed.

<stylesheet src="css-url" />
Automatically injects the external CSS file located at the location specified by src


Compatibilidad de GWT con las librerias de java

Ver este link que es muy claro: 
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideCodingBasicsCompatibility.html

GWT - Panels & Widgets & CellWidgets

Las siguientes URLs nos muestran varios ejemplos de paneles, layouts y widgets.

Esta URL se lleva todos los premios
http://gwt.google.com/samples/Showcase/Showcase.html

Y aqui tenemos mas URLs muy utiles
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiPanels.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiWidgets.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiCustomWidgets.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiCellWidgets.html

http://code.google.com/intl/es/webtoolkit/doc/latest/RefWidgetGallery.html
https://sites.google.com/site/gwttutor/2-absolutepanel
http://www.java2s.com/Code/Java/GWT/CatalogGWT.htm


CellWidgets

Cell widgets (data presentation widgets) are high-performance, lightweight widgets composed of Cells for displaying data. Examples are lists, tables, trees and browsers. These widgets are designed to handle and display very large sets of data quickly. A cell widget renders its user interface as an HTML string, using innerHTML instead of traditional DOM manipulation. This design follows the flyweight pattern where data is accessed and cached only as needed, and passed to flyweight Cell objects. A cell widget can accept data from any type of data source. The data model handles asynchronous updates as well as push updates. When you change the data, the view is automatically updated.

Las implementaciones de los CellWidgets son:

  • CellList
  • CellTable
  • CellTree
  • CellBrowser
  • CellSampler
  • CellValidation

Cells are the basic blocks of a user interface and come in a variety of available cell types. They render views of data, interpret browser events and can be selected. A Cell has a type based on the data that the cell represents; for example, DatePickerCell is a Cell<Date> that represents a Date and allows the user to select a new Date. Cells must implement a render method that renders the typed value as an HTML string. In addition, cells can override onBrowserEvent to act as a flyweight that handles events that are fired on elements that were rendered by the cell.

GWT offers a number of concrete Cell implementations that you can use immediately. See the Cell Sampler for examples.

Text
  • TextCell - A non-editable cell that displays text
  • ClickableTextCell - A text field; clicking on the cell causes its ValueUpdater to be called
  • EditTextCell - A cell that initially displays text; when clicked, the text becomes editable
  • TextInputCell - A field for entering text
Buttons, Checkboxes and Menus
  • ActionCell<C> - A button that takes a delegate to perform actions on mouseUp
  • ButtonCell - A button whose text is the data value
  • CheckboxCell - A checkbox that can be checked or unchecked
  • SelectionCell - A drop-down menu for selecting one of many choices
Dates
  • DateCell - A date that conforms to a specified date format
  • DatePickerCell - A date picker that displays a month calendar in which the user can select a date
Images
  • ImageCell - A cell used to render an image URL
  • ImageResourceCell - A cell used to render an ImageResource
  • ImageLoadingCell - A cell used to render an image URL. A loading indicator is initially displayed
Numbers
  • NumberCell - A number that conforms to a specified number format
  • Compositions
  • CompositeCell<C> - A composition of multiple Cells
Decorators
  • IconCellDecorator<C> - A decorator that adds an icon to another Cell

A. CellList - Ejemplo

...
...

RootPanel.get("cellList").add(buildCellList());
...
...

private Widget buildCellList(){
   List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", 
                     "Wednesday", "Thursday", "Friday", "Saturday");
  // Create a cell to render each value in the list.
   TextCell textCell = new TextCell();
   // Create a CellList that uses the cell.
   CellList<String> cellList = new CellList<String>(textCell);
   cellList.setRowCount(DAYS.size(), true);
   // Push the data into the widget.
   cellList.setRowData(0, DAYS);
   
   return cellList;
}


B. CellTable - Ejemplo
...

...

RootPanel.get("cellTable").add(buildCellTable());
...
...


private Widget buildCellTable(){
List<StockPrice> stocks = Arrays.asList(
   new StockPrice("100", 1040),
   new StockPrice("200", 2345));
// Create a CellTable.
   CellTable<StockPrice> table = new CellTable<StockPrice>();

   // Create id column.
   TextColumn<StockPrice> idColumn = new TextColumn<StockPrice>() {
     @Override
     public String getValue(StockPrice stockPrice) {
       return stockPrice.getSymbolId();
     }
   };

   // Create price column.
   TextColumn<StockPrice> priceColumn = new TextColumn<StockPrice>() {
     @Override
     public String getValue(StockPrice stockPrice) {
       return String.valueOf(stockPrice.getPrice());
     }
   };

   // Add the columns.
   table.addColumn(idColumn, "Symbol ID");
   table.addColumn(priceColumn, "Price");

   // Set the total row count. This isn't strictly necessary, but it affects
   // paging calculations, so its good habit to keep the row count up 
            // to date.
   table.setRowCount(stocks.size(), true);

   // Push the data into the widget.
   table.setRowData(0, stocks);
   
   return table;
}


The SelectionModel is a simple interface that views use to determine if an item is selected. Cell widgets provide several selection models for selecting the children of a node: DefaultSelectionModel, NoSelectionModel, SingleSelectionModel and MultiSelectionModel. One of these is likely to fit your need.

For demonstrations of selection, the CwCellList widget creates a SingleSelectionModel, whereas CwCellTable implements a MultiSelectionModel using checkboxes.

C. CellList with SelectionModel - Ejemplo
....
....
RootPanel.get("cellListWithModel").add(buildCellListWithSelectionModel());
....
....
private Widget buildCellListWithSelectionModel(){

List<String> DAYS = Arrays.asList("Sunday", "Monday", "Tuesday", 
                    "Wednesday", "Thursday", "Friday", "Saturday");
// Create a cell to render each value in the list.
TextCell textCell = new TextCell();
// Create a CellList that uses the cell.
CellList<String> cellList = new CellList<String>(textCell);
        cellList.setKeyboardSelectionPolicy(
                         KeyboardSelectionPolicy.ENABLED);
// Add a selection model to handle user selection.
       final SingleSelectionModel<String> selectionModel 
                            = new SingleSelectionModel<String>();
       cellList.setSelectionModel(selectionModel);
       
               selectionModel.addSelectionChangeHandler(new 
                               SelectionChangeEvent.Handler() {
          public void onSelectionChange(SelectionChangeEvent event) {
       String selected = selectionModel.getSelectedObject();
          if (selected != null) {
             Window.alert("You selected: " + selected);
          }
         }
        });
// Set the total row count. This isn't strictly necessary, 
                // but it affects
// paging calculations, so its good habit to keep the row count 
                // up to date.
cellList.setRowCount(DAYS.size(), true);
// Push the data into the widget.
cellList.setRowData(0, DAYS);
return cellList;

}


Otros componentes


Primer Imagen

private Widget buildAbsolutePanel() {

AbsolutePanel panel = new AbsolutePanel();
panel.setSize("200px", "120px");
panel.addStyleName("demo-panel");

Label label = new Label("Label");
label.setWidth("100px");
label.setStyleName("demo-label");
panel.add(label, 50, 50);

return panel;
}


Segunda Imagen


private Widget buildHTMLPanel(){

String html = "<div id='one' "
+ "style='border:3px dotted blue;'>"
+ "</div><div id='two' "
+ "style='border:3px dotted green;'"
+ "></div>";
HTMLPanel panel = new HTMLPanel(html);
panel.setSize("200px", "120px");
panel.addStyleName("demo-panel");
panel.add(new Button("Do Nothing"), "one");
panel.add(new TextBox(), "two");

return panel;
}


Tercer Imagen
private Widget buildScrollPanel(){
String lorem = "Lorem ipsum dolor sit amet,
               consectetuer adipiscing elit. Morbi sit amet massa
               ornare mauris lobortis laoreet. Pellentesque vel 
               est at massa condimentum porta. Aliquam tincidunt 
               scelerisque orci. Donec sit amet elit nec leo 
               egestas 
               vestibulum. Mauris et nibh quis ipsum 
               volutpat congue. 
               Ut tellus nibh, convallis sed, consectetuer sit 
               amet, 
               facilisis eget, lectus. Morbi hendrerit, dolor eget 
               tincidunt tristique, velit enim laoreet erat, nec 
              condimentum eros mi quis tellus. Fusce pharetra nibh 
               vestibulum lacus. Integer vulputate eros at nisi. 
              Phasellus elit quam, dignissim quis, volutpat vitae, 
               egestas nec, nisi. Nullam sodales sagittis quam. 
               Aliquam iaculis neque ut magna. Donec convallis 
               interdum sem. Sed suscipit.";

ScrollPanel panel = new ScrollPanel(new HTML(lorem));
panel.setSize("200px", "120px");

return panel;
}


Cuarta Imagen

private Widget buildSimplePanel(){
SimplePanel panel = new SimplePanel();
panel.setSize("200px", "120px");
panel.addStyleName("demo-panel");

Label label = new Label("Label");
label.setWidth("100px");
label.setStyleName("demo-label");
panel.add(label);
return panel;
}



GWT - RPC

GWT provides a few different ways to communicate with a server. Which data format you use will ultimately depend on the server you need to interact with.

  • Making Remote Procedure Calls (GWT RPC)
  • Retrieving JSON Data via HTTP
  • Making Cross-Site Requests for JSONP

GWT - RPC

Whether you use GWT RPC or get JSON data via HTTP, all the calls you make from the HTML page to the server are asychronous
The GWT RPC framework makes it easy for the client and server components of your web application to exchange Java objects over HTTP. The server-side code that gets invoked from the client is often referred to as a service. The implementation of a GWT RPC service is based on the well-known Java servlet architecture. Within the client code, you'll use an automatically-generated proxy class to make calls to the service. GWT will handle serialization of the Java objects passing back and forth—the arguments in the method calls and the return value. 
Definición extraida del sitio oficial del GWT (ver bibliografia)

In GWT, an RPC service is defined by an interface that extends the GWT RemoteService interface


Ejemplo de implementación de un RPC-Service


StockPriceService (paquete ...stockwatcher.client)

public interface StockPriceService extends RemoteService {


// Metodo que dado un symbol nos devolvera un price.
StockPrice getPrices(String symbol);
}

StockPriceServiceImpl (paquete ...stockwatcher.server)

public class StockPriceServiceImpl extends RemoteServiceServlet implements StockPriceService {


public StockPrice getPrices(String symbolId) {
return new StockPrice(symbolId, 899);
}
}

StockPriceServiceAsync (paquete ...stockwatcher.client)

Tip: The Google Plugin for Eclipse will generate an error when it finds a synchronous remote service without a matching asynchronous interface. You can right click on the error in Eclipse, select Quick Fix, and choose the "Create asynchronous RemoteService interface" option to automatically generate the asynchronous interface.


public interface StockPriceServiceAsync {


        void getPrice(String symbolId, AsyncCallback<StockPrice> callback);
}

Una vez creado el service (servlet), vamos a incluirlo en el modulo GWT. A partir de la version 1.6, los servlets los definiremos en el web.xml en lugar del StockWatcher-gwt.xml.


web.xml

  <!-- Servlets -->
  <servlet>
    <servlet-name>stockPriceServiceImpl</servlet-name>
 <servlet-class>com.google.gwt.sample.stockwatcher.server.StockPriceServiceImpl
      </servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>stockPriceServiceImpl</servlet-name>
    <url-pattern>/stockwatcher/stockPrices</url-pattern>
  </servlet-mapping>

NOTA:

In the <servlet-mapping> element, the url-pattern can be in the form of an absolute directory path (for example, /spellcheck or /common/login). If you specify a default service path with a @RemoteServiceRelativePath annotation on the service interface (as you did with StockPriceService), then make sure the url-pattern matches the annotation value. Because you've mapped the StockPriceService to "stockPrices" and the module rename-to attribute in StockWatcher.gwt.xml is "stockwatcher" (<module rename-to='stockwatcher'>), the full URL will be: http://localhost:8888/stockwatcher/stockPrices


Llamando a los métodos remotos

When you call a remote procedure, you specify a callback method which executes when the call completes. You specify the callback method by passing an AsyncCallback object to the service proxy class. The AsyncCallback object contains two methods, one of which is called depending on whether the call failed or succeeded: onFailure(Throwable) and onSuccess(T).

private StockPriceServiceAsync stockPriceSvc = GWT.create(StockPriceService.class);


stockPriceSvc.getPrice(symbol, new AsyncCallback<StockPrice>() {

@Override
public void onSuccess(StockPrice result) {


updatePrice(result);
}

@Override
public void onFailure(Throwable caught) {

System.out.println("onFailure....");
}
});

Manejo de excepciones

Agregar throws DelistedException en la interface StockPriceService y StockPriceServiceImpl

y Luego procedemos a capturar la excepcion de la siguiente manera:

stockPriceSvc.getPrice(symbol, new AsyncCallback<StockPrice>() {
@Override
public void onSuccess(StockPrice result) {

System.out.println("onSuccess INICIO ....");
setStockPrice(result);
System.out.println("price " + result.getPrice());
System.out.println("onSuccess FIN ....");
}
@Override
public void onFailure(Throwable caught) {
System.out.println("onFailure INICIO ....");
       String details = caught.getMessage();
       if (caught instanceof DelistedException) {
         details = "Company '" +
                                     ((DelistedException)caught).getSymbol() + 
                                     "' was delisted";
       }
       errorMsgLabel.setText("Error: " + details);
       errorMsgLabel.setVisible(true);
       System.out.println("onFailure FIN ....");
}
});




Bibliografia

GWT - I18N (Internacionalización)

Ejemplo de I18N (ingles y alemán)

GWT permite internacionalizar tanto los mensajes como las constantes:


StockWatcherConstants

package com.google.gwt.sample.stockwatcher.client;

import com.google.gwt.i18n.client.Constants;

public interface StockWatcherConstants extends Constants {
  @DefaultStringValue("StockWatcherrrr")
  String stockWatcher();

  @DefaultStringValue("Symbollll")
  String symbol();

  @DefaultStringValue("Priceee")
  String price();

  @DefaultStringValue("Changeee")
  String change();

  @DefaultStringValue("Removeee")
  String remove();

  @DefaultStringValue("Adddd")
  String add();
}


StockWatcherMessages

package com.google.gwt.sample.stockwatcher.client;

import java.util.Date;

import com.google.gwt.i18n.client.Messages;

public interface StockWatcherMessages extends Messages {
  @DefaultMessage("''{0}'' is not a valid symbol.")
  String invalidSymbol(String symbol);

  @DefaultMessage("Last update: {0,date,medium} {0,time,medium}")
  String lastUpdate(Date timestamp);

}

Una vez creados los mensajes y constantes que serán utilizados como locale por defecto, procedemos a crear la primera variante que sera para el idioma Aleman.

StockWatcherConstants_de.properties

stockWatcher = Aktienbeobachter
symbol = Symbol
price = Kurs
change = Änderung
remove = Entfernen
add = Hinzufügen

StockWatcherMessages_de.properties

lastUpdate = Letzte Aktualisierung: {0,date,medium} {0,time,medium}
invalidSymbol = ''{0}'' ist kein gültiges Aktiensymbol.



Usando la I18N

private StockWatcherConstants constants = GWT.create(StockWatcherConstants.class);

private StockWatcherMessages messages = GWT.create(StockWatcherMessages.class);


stocksFlexTable.setText(0, 0, constants.symbol());
stocksFlexTable.setText(0, 1, constants.price());
stocksFlexTable.setText(0, 2, constants.change());
stocksFlexTable.setText(0, 3, constants.remove());


Una vez internacionalizado el sitio, se le tendrá que indicar a GWT cual sera el LOCALE a utilizar. Siempre es una buena practica permitirle al usuario poder seleccionar el idioma que el desee.

Para indicar que el sitio tendrá que ser visto en aleman, se le tendra que agregar a la URL lo siguiente:

?locale=de

Para ingresar al locale por default
  • http://127.0.0.1:8888/StockWatcher.html?gwt.codesvr=127.0.0.1:9997

Para ingresar al locale en aleman
  • http://127.0.0.1:8888/StockWatcher.html?gwt.codesvr=127.0.0.1:9997&locale=de

How does GWT know which one to load at runtime? GWT uses client properties to produce customized JavaScript compilations of your GWT application using a mechanism called deferred binding



I18N & Deferred Binding

GWT generates a unique compilation for every combination of possible client property values. So, for example, if GWT supports 5 web browsers and you translate an application into 4 different languages, the GWT compiler produces a total of 20 different versions of your application. However, each user of your application is served only the code in the permutation matching his or her particular combination of web browser and locale.




Bibliografia

http://code.google.com/intl/es/webtoolkit/doc/latest/tutorial/i18n.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideI18n.html


miércoles, 17 de agosto de 2011

GWT (Google Web Toolkit) - Primer ejemplo

En la pagina oficial del siito de GWT, encontraremos de forma muy facil y sencilla, paso a paso como tener una aplicación GWT configurada y lista para empezar a trabajar.



Archivos creados

  • StockWatcher.gwt.xml
    GWT module definition
  • StockWatcher.html
    host page
  • StockWatcher.css
    application style sheet
  • web.xml
    Java web application descriptor
  • StockWatcher.javaGWT entry point class
  • GreetingService.java, GreetingServiceAsync.java, GreetingServiceImpl.java
    GWT sample RPC classes
  • gwt-servlet.jar
    GWT server runtime library
  • StockWatcherTest.java
    Starter test case for StockWatcher
A continuación mostraremos el código sin comunicación RPC.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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>
  
  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>StockWatcher.html</welcome-file>
  </welcome-file-list>


</web-app>



StockWatcher.gwt.xml

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='stockwatcher'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>


  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <!-- <inherits name='com.google.gwt.user.theme.clean.Clean'/>-->
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
   <inherits name='com.google.gwt.user.theme.dark.Dark'/>     


  <!-- Other module inherits                                      -->


  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/>


  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>
  <source path='shared'/>


</module>

StockWatcher.css

/** Add css rules here for your application. */

body {
  padding: 10px;
}

/* Add Stock panel */
.addPanel {
  margin: 10px 0px 15px 0px;
}

/* stock list header row */
.watchListHeader {
  background-color: #2062B8;
  color: white;
  font-style: italic;
}

/* stock list flex table */
.watchList {
  border: 1px solid silver;
  padding: 2px;
  margin-bottom:6px;
}

/* stock list Price and Change fields */
.watchListNumericColumn {
  text-align: right;
  width:8em;
}

/* stock list Remove column */
.watchListRemoveColumn {
  text-align: center;
}

/* stock list, the Remove button */
.gwt-Button-remove {
  width: 50px;
}

/* Dynamic color changes for the Change field */

.positiveChange {
  color: green;
}

.negativeChange {
  color: red;
}


StockWatcher.html

<!doctype html>
<!-- The DOCTYPE declaration above will set the    -->
<!-- browser's rendering engine into               -->
<!-- "Standards Mode". Replacing this declaration  -->
<!-- with a "Quirks Mode" doctype may lead to some -->
<!-- differences in layout.                        -->

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <!--                                                               -->
    <!-- Consider inlining CSS to reduce the number of requested files -->
    <!--                                                               -->
    <link type="text/css" rel="stylesheet" href="StockWatcher.css">

    <!--                                           -->
    <!-- Any title is fine                         -->
    <!--                                           -->
    <title>StockWatcher</title>
    
    <!--                                           -->
    <!-- This script loads your compiled module.   -->
    <!-- If you add any GWT meta tags, they must   -->
    <!-- be added before this line.                -->
    <!--                                           -->
    <script type="text/javascript" language="javascript" src="stockwatcher/stockwatcher.nocache.js"></script>
  </head>

  <!--                                           -->
  <!-- The body can have arbitrary html, or      -->
  <!-- you can leave the body empty if you want  -->
  <!-- to create a completely dynamic UI.        -->
  <!--                                           -->
  <body>

    <!-- OPTIONAL: include this if you want history support -->
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
    
    <!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
    <noscript>
      <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
        Your web browser must have JavaScript enabled
        in order for this application to display correctly.
      </div>
    </noscript>

    <h1>StockWatcher</h1>
    <div id="stockList"></div>

  </body>
</html>


StockWatcher,java

package com.google.gwt.sample.stockwatcher.client;

import java.util.ArrayList;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class StockWatcher implements EntryPoint {
/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";

/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

private VerticalPanel mainPanel = new VerticalPanel();
private FlexTable stocksFlexTable = new FlexTable();
private HorizontalPanel addPanel = new HorizontalPanel();
private TextBox newSymbolTextBox = new TextBox();
private Button addStockButton = new Button("Add");
private Label lastUpdatedLabel = new Label();
private ArrayList<String> stocks = new ArrayList<String>();


/**
* This is the entry point method.
*/
@SuppressWarnings("deprecation")
public void onModuleLoad() {

// Create table for stock data.
   stocksFlexTable.setText(0, 0, "Symbol");
   stocksFlexTable.setText(0, 1, "Price");
   stocksFlexTable.setText(0, 2, "Change");
   stocksFlexTable.setText(0, 3, "Remove");
   
   // Add styles to elements in the stock list table.
   // The the header row in the flex table displays white italic headings against a blue background.
   stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader");
   stocksFlexTable.addStyleName("watchList");
   stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn");
   stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn");
   stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn");
   // distancia entre el valor que esta dentro de la celda y los bordes de cada celda. 
   stocksFlexTable.setCellPadding(6);
   // distancia entre cada celda y el bordes de las filas y columnas de la tabla
   stocksFlexTable.setCellSpacing(1);

   
   // Add styles to addPanel
   addPanel.setStyleName("addPanel");
   
// Assemble Add Stock panel.
   addPanel.add(newSymbolTextBox);
   addPanel.add(addStockButton);
   
// Assemble Main panel.
   mainPanel.add(stocksFlexTable);
   mainPanel.add(addPanel);
   mainPanel.add(lastUpdatedLabel);
   
// Associate the Main panel with the HTML host page.
   RootPanel.get("stockList").add(mainPanel);
   
// Move cursor focus to the input box.
   newSymbolTextBox.setFocus(true);
   
   // Listen for mouse events on the Add button.
   addStockButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
addStock();
}
});
   
}

private void addStock() {

System.out.println("addStock() INICIO");
newSymbolTextBox.setFocus(true);
newSymbolTextBox.selectAll();
// Stock code must be between 1 and 10 chars that are numbers, letters, or dots.
final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
//if (!symbol.matches("^[0-9A-Z\\.]{1,10}$")){
if (!symbol.matches("^[0-9\\.]{1,10}$")){
//Window.alert("No es un valor entre 1 y 9 o letra entre A y Z. Valor ingresado: " + symbol);
Window.alert("No es un valor entre 1 y 9. Valor ingresado: " + symbol);
return;
}
if (stocks.contains(symbol)){
Window.alert("Ya existe este symbol en la tabla de stock, por favor ingrese otro");
return;
}
// Add the stock to the table.
// When you call the setText method, the FlexTable automatically creates new cells as needed; therefore, you don't need to resize the table explicitly. 
int rowCount = stocksFlexTable.getRowCount();
stocks.add(symbol);
stocksFlexTable.setText(rowCount, 0, symbol);
// Add style.
stocksFlexTable.getCellFormatter().addStyleName(rowCount, 1, "watchListNumericColumn");
stocksFlexTable.getCellFormatter().addStyleName(rowCount, 2, "watchListNumericColumn");
stocksFlexTable.getCellFormatter().addStyleName(rowCount, 3, "watchListRemoveColumn");
// Format the data in the Price and Change fields.
Label label = new Label();
if (Integer.parseInt(symbol) > 100){
label.setStyleName("negativeChange");
} else {
label.setStyleName("positiveChange");
}
   String harcodedPriceText = NumberFormat.getFormat("$#,##0.00").format(100);
   label.setText(harcodedPriceText);
   stocksFlexTable.setWidget(rowCount, 1, label);
// Add a button to remove this stock from the table.
Button removeButton = new Button("X");
// Add style dependent on primary style
// La renderizacion seria algo asi: <button class="gwt-Button gwt-Button-remove" tabindex="0" type="button">x</button> 
removeButton.addStyleDependentName("remove");
stocksFlexTable.setWidget(rowCount, 3, removeButton);
removeButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
int indexOf = stocks.indexOf(symbol);
stocks.remove(indexOf);
stocksFlexTable.removeRow(indexOf + 1);
}
});


System.out.println("addStock() FIN");
}
}


http://127.0.0.1:8888/StockWatcher.html?gwt.codesvr=127.0.0.1:9997





A continuación encontraremos todos los componentes GWT con sus correspondientes ejemplos. Muy muy utiles.

http://www.java2s.com/Code/Java/GWT/CatalogGWT.htm
http://code.google.com/intl/es/webtoolkit/doc/latest/RefWidgetGallery.html



Bibliografia

Conceptos básicos

http://code.google.com/intl/es-419/eclipse/docs/getting_started.html
http://code.google.com/intl/es/webtoolkit/doc/latest/tutorial/create.html

Para el capitulo de los eventos, tener en cuenta este best practice.

http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiHandlers.html
http://www.vogella.de/articles/GWT/article.html

I18N

http://code.google.com/intl/es/webtoolkit/doc/latest/tutorial/i18n.html

RPC

http://code.google.com/intl/es/webtoolkit/doc/latest/tutorial/clientserver.html
http://code.google.com/intl/es/webtoolkit/doc/latest/tutorial/RPC.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideServerCommunication.html

Componentes (Widgets varios)

http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiPanels.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideUiWidgets.html
http://code.google.com/intl/es/webtoolkit/doc/latest/RefWidgetGallery.html
https://sites.google.com/site/gwttutor/2-absolutepanel
http://www.java2s.com/Code/Java/GWT/CatalogGWT.htm

Organización de los proyectos

http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideOrganizingProjects.html

Conceptos útiles

http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideCodingBasicsCompatibility.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideCodingBasicsHistory.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideCodingBasicsFormatting.html
http://code.google.com/intl/es/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html

Grupo de GWT para FAQ

http://groups.google.com/group/Google-Web-Toolkit