Gwt 教程之实现客户端功能

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

 

实现客户端功能

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

验证用户输入

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

 

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

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

private void addStock() {

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

  newSymbolTextBox.setFocus(true);

 

  // symbol must be between 1 and 10 chars that are 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:

import com.google.gwt.user.client.Window;

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

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

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

操纵watch list

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

 

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

public class StockWatcher implements EntryPoint {

 

  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 = new ArrayList<String>();

别忘记了新增的import:

import java.util.ArrayList;

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

// don't add the stock if it's already 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 stock from the list

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);

 

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

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

at will 意为随意

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

刷新存货价格

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  and then modify the end of the end of the onModuleLoad() method as follows:

import com.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'll also need to define the constant that specifies the refresh rate. Add that to the top of the StockWatcher class.

private static final int REFRESH_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 ).

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

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

package com.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 list FlexTable 。向我们的StockWatcher 类增加如下import 和函数:

import com.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[i] = new StockPrice((String)stocks.get(i), price, change);

  }

 

  updateTable(prices);

}

更新watch list

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

private void updateTable(StockPrice[] prices) {

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

    updateTable(prices[i]);

  }

 

  // change the last update timestamp

  lastUpdatedLabel.setText("Last update : " +

       DateTimeFormat.getMediumDateTimeFormat().format(new Date()));

}

 

private void updateTable(StockPrice price) {

  // 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 中讨论更多localizing and translating your GWT application (国际化和GWT 应用程序的转换)

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

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

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

 

 

你可能感兴趣的:(Ajax,正则表达式,浏览器,Google,gwt)