六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 35|回复: 0

Gwt 教程之实现客户端功能

[复制链接]

升级  86%

9

主题

9

主题

9

主题

童生

Rank: 1

积分
43
 楼主| 发表于 2013-1-23 02:56:07 | 显示全部楼层 |阅读模式
<!----><!----><!----><!---->

 

实现客户端功能

我们的StockWatcher 例子到目前为止已经很好了,回顾一下,我们用GWT的widgets和 panels已经设计并实现了UI,并且为用户实现了键盘单击事件 的初始化。现在,我们要为应用程序写客户端代码,让它实现功能。

验证用户输入

当用户第一次使用StockWatcher ,他需要通过在文本框里输入存货订单标示(一次只能增加一条)来向他的watchlist中增加存货。然而在我们增加一条存货的时候,我们需要检验新输入是否有效,如果无效,我们需要通过一个对话框来警告他。

 

业务顺序的第一步是给addStock()增加代码来完成创建存货。我们使用TextBox widget的getText() 方法来获得文本。GWT的 widgets 和panels包含了丰富的属性和方法,很多都是和HTML DOM元素相类似的。当我们转换用户在一个标准表单中的输入的时候,我们使用正则表达式来检查它的格式(记住在java和JavaScript中使用正则表达式意思是一样的).

以下是更新后的addStock()方法:

private void addStock() {

 final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
 newSymbolTextBox.setFocus(true);

 

 // symbol must be between 1 and 10 chars thatare numbers, letters, or //dots

 

 if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$"))

 {

   Window.alert("'" + symbol + "'is not a valid symbol.");

    newSymbolTextBox.selectAll();

    return;

 }

 

 newSymbolTextBox.setText("");

     

 // now we need to add the stock to the list...

 

}

由于调用了 Window.alert(String)方法, 因此我们需要增加另一个import:

importcom.google.gwt.user.client.Window;

现在,轻松了许多,重编译并运行StockWatcher application来测试输入验证。

如果你在hosted mode 下的浏览器已经打开了,你不需要重启它。只需要点击工具栏上的Refresh按钮来重载你更新后的GWT代码。

<!----><!----><!---->

操纵watch list

尽管StockWatcher已经有了验证存货输入的能力,但它仍然没有实现它的功能:用户依然不能看到增加的存货。现在让我们来继续完成功能吧。回顾一下,我们的UI包含了一个名为stocksFlexTable 的FlexTable窗口,它用于包含watch list。列表的每行都包含一个存货标识,当前价格,价格变动和一个用于移除存货的按钮。当前我们仅关注增加和移除存货功能,不用去担心设定价格和变更。

 

首先,我们需要一个数据结构来保存当前可见的存货标识列表,我们使用标准的Java ArrayList 来调用我们的存货列表:

public class StockWatcher implementsEntryPoint {

 

 private VerticalPanel mainPanel = new VerticalPanel();  

 private FlexTable stocksFlexTable = new FlexTable();

 private HorizontalPanel addPanel = new HorizontalPanel();

 private TextBox newSymbolTextBox = new TextBox();

 private Button addButton = new Button("Add");

 private Label lastUpdatedLabel = new Label();

 

  private ArrayList<String> stocks = newArrayList<String>();

别忘记了新增的import:

import java.util.ArrayList;

接下来是有趣的部分。向addStock()方法中增加如下的代码:

// don't add the stock if it'salready in the watch list

if (stocks.contains(symbol))

 return;

 

// add the stock to the list

int row =stocksFlexTable.getRowCount();

stocks.add(symbol);

stocksFlexTable.setText(row, 0,symbol);

 

// add button to remove this stockfrom the list

Button removeStock = newButton("x");

removeStock.addClickListener(newClickListener(){

  public void onClick(Widget sender) {

    int removedIndex = stocks.indexOf(symbol);

    stocks.remove(removedIndex);

    stocksFlexTable.removeRow(removedIndex+1);

 }     

});

stocksFlexTable.setWidget(row, 3,removeStock);

 

新条件应简单的关联。首先,通过给存货设定第一列的text给我们的FlexTable增加了新的一行,(记住它的 setText(int,int, String) 方法会自动创建你需要的新的单元格,所以我们不需要显示的设定表格大小)。之后,我们创建了移除存货的按钮,并在指定ClickListener 从FlexTable和ArrayList中移除存货前使用setWidget(int,int, Widget)方法把它放在表格的最后一列。

现在的事实:运行或刷新hosted mode下的浏览器。得救了,你可以随意的添加和移除存货信息。现在我们唯一没有实现的功能是存货的价格及其变更。

at will意为随意

<!----><!----><img height="460" border="0" alt="" width="584" /><!---->

刷新存货价格

StockWatcher 最后且最重要的功能是更新我们关心的存货价格。如果我们用传统的web开发技术写应用程序的话,我们想更新价格需要每次都整个页面重载来响应。这可以用手或自动刷新(比如在HTML头部使用<meta http-equiv="refresh"content="5">标签)来实现。在web2.0中这是不够的,那些追捧崇拜的商人需要立马更新更新它们的存货价格,而不是烦人的页面刷新。

幸运的是,百忙中GWT让更新你的应用程序内容变得很容易。让我们使用Timer 类来给StockWatcher增加自动更新存货价格的功能。

使用定时器自动刷新

Timer是单线程,浏览器安全的定时器类,它允许我们在未来某时安排代码运行,或者使用scheduleRepeating(int)或用scheduleRepeating(int)重复。我们使用后面的方法每隔5秒来自动更新我们的存货价格。

为了使用Timer我们在我们的onModuleLoad()方法中创建了一个新的实例并重写了run()方法。当定时器工作的时候run()方法将被调用。在我们的例子中,我们要调用一个将被写的名为refreshWatchList()的方法来实际进行更新操作。给Timer 增加import,之后如下修改onModuleLoad()尾部的尾部:

Add the import for Timer andthen modify the end of the end of the onModuleLoad() method as follows:

importcom.google.gwt.user.client.Timer;

public void onModuleLoad() {

 ...

 

 // add the main panel to the HTML element with the id"stockList"

 RootPanel.get("stockList").add(mainPanel);

 

 // setup timer to refresh list automatically

  Timer refreshTimer = new Timer() {

    public void run() {

      refreshWatchList();       

    }

  };

  refreshTimer.scheduleRepeating(REFRESH_INTERVAL);

 

 // move cursor focus to the text box

 newSymbolTextBox.setFocus(true);

}

In addition to the change to onModuleLoad(), you'llalso need to define the constant that specifies the refresh rate. Add that tothe top of the StockWatcher class.

private static final intREFRESH_INTERVAL = 5000; // ms

在我们继续之前,我们需要增加调用新的refreshWatchList() 方法不止一次。在我们增加新的存货到FlexTable 后我们将在addStock()方法中立即调用它。(所以新的存货会马上获得它的价格及变更情况):

private void addStock() { 

 ...

 

 Button removeStock = new Button("x");

 removeStock.addClickListener(new ClickListener(){

    public void onClick(Widget sender) {

       int removedIndex =stocks.indexOf(symbol);

       stocks.remove(removedIndex);

      stocksFlexTable.removeRow(removedIndex+1);

   }     

 });

 stocksFlexTable.setWidget(row, 3, removeStock);

 

 // get stock price

 refreshWatchList();

}

 

private void refreshWatchList() {

 // Code will be added in the next section

}

StockPrice

GWT中主要方式的一种就是在java语言中允许我们传播AJAX的开发。因此,我们可以采取静态类型检查和面向对象编程的嵌入时间(time-tested)模式,可以和现代的IDE特性结合,如代码补全和自动重构等,使得它以良好的代码管理为基础,比以往更加简单的去写健壮的AJAX应用程序。

对于StockWatcher来说,我们将存货价格数据放到它自己的类中进行重构。创建一个名为StockPrice 位于com.google.gwt.sample.stockwatcher.client包下的java类(in Eclipse, File -> New ->Class).

<!----><!----><img height="599" border="0" alt="" width="500" /><!---->

以下是我们的新类的完整实现:

packagecom.google.gwt.sample.stockwatcher.client;

 

public class StockPrice {

 

 private String symbol;

 private double price;

 private double change;

 

 public StockPrice() {

 }

 

 public StockPrice(String symbol, double price, double change) {

   this.symbol = symbol;

   this.price = price;

   this.change = change;

 }

     

 public String getSymbol() {

   return this.symbol;

 }

 

 public double getPrice() {

   return this.price;

 }

 

 public double getChange() {

   return this.change;

 }

 

 public double getChangePercent() {

   return 10.0 * this.change / this.price;

 }

 

 public void setSymbol(String symbol) {

   this.symbol = symbol;

 }

 

 public void setPrice(double price) {

   this.price = price;

 }

 

 public void setChange(double change) {

   this.change = change;

 }

}

生成存货价格

既然我们有一个StockPrice 类来封装存货价格数据,让我们使用它来更新watch list表格。首先,我们需要生成实际数据。作为从在线数据源中检索真实的存货价格实际数据的替代,我们使用GWT内置的Random类来创建伪随机价格并改变其值。我们将用这些值填充StockPrice对象数组,之后传给它们另一个功能来更新watch listFlexTable。向我们的StockWatcher类增加如下import和函数:

importcom.google.gwt.user.client.Random;

private void refreshWatchList() {

 final double MAX_PRICE = 100.0; // $100.00

 final double MAX_PRICE_CHANGE = 0.02; // +/- 2%

 

 StockPrice[] prices = new StockPrice[stocks.size()];

 for (int i=0; i<stocks.size(); i++) {

   double price = Random.nextDouble() * MAX_PRICE;

   double change = price * MAX_PRICE_CHANGE * (Random.nextDouble() * 2.0 -1.0);

     

   prices = new StockPrice((String)stocks.get(i), price, change);

 }

 

 updateTable(prices);

}

更新watch list

最后的2个新函数会更新新价格的显示。在updateTable(StockPrice)方法中,你会发现例子中使用NumberFormat 来格式话数值为字符串。在我们的例子中,我们用它以货币形式来格式化价格,且价格变动之前显示一个指示符。相似的,注意在updateTable(StockPrice[])方法中的使用DateTimeFormat 类来格式化当前日期时间。接下来把这些功能加到StockWatcher中:

private voidupdateTable(StockPrice[] prices) {

 for (int i=0; i<prices.length; i++) {

   updateTable(prices);

 }

 

 // change the last update timestamp

 lastUpdatedLabel.setText("Last update : " +

     DateTimeFormat.getMediumDateTimeFormat().format(newDate()));

}

 

private void updateTable(StockPriceprice) {

 // make sure the stock is still in our watch list

 if (!stocks.contains(price.getSymbol())) {

   return;

  }

 

 int row = stocks.indexOf(price.getSymbol()) + 1;

 

 // apply nice formatting to price and change

 String priceText = NumberFormat.getFormat("#,##0.00").format(price.getPrice());

 NumberFormat changeFormat = NumberFormat.getFormat("+#,##0.00;-#,##0.00");

 String changeText = changeFormat.format(price.getChange());

 String changePercentText = changeFormat.format(price.getChangePercent());

 

 // update the watch list with the new values

 stocksFlexTable.setText(row, 1, priceText);

  stocksFlexTable.setText(row, 2, changeText +" (" + changePercentText + "%)");

}

DateTimeFormat 和 NumberFormat 类位于独立的包中,因此你需要为它们增加另外的import。就像一个java的标准Date类一样:

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

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

 

import java.util.Date;

你可能已经注意到DateTimeFormat 和 NumberFormat 位于com.google.gwt.i18的子包中,看来它们是用来以某种方式来处理国际化问题。事实上它们也确实这么做的。当你格式化数组和日期的时候,二个类都自动的使用你的应用程序的locale设定。随后我们会在Getting Started guide中讨论更多localizingand translating your GWT application(国际化和GWT应用程序的转换)

又到了测试我们的改变的时候了。运行或刷新应用程序在hosted mode,试着增加某种存货到watch list。现在,我们可以看到每个存货的当前价格和变动情况。如果你观察列表一段事件,你会发现那些值会随着底部的时间戳,每隔5秒中改变一次。

<!----><!----><img height="386" border="0" alt="" width="436" /><!---->

好吧,看起来像我们的StockWatcher 程序工作的很完美,不是吗?离你离开的时间越来越远,它证明了一个细微的bug。如果你找到它(hint: it's visible in the screenshot above).在下部分中,我们会使用我们的java调试技巧来调试它。

 
 
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表