Реализация функциональности клиентской стороны

Наш пример StockWatcher далек от красоты. Напомним, мы уже разработали дизайн - концепт и реализовали пользовательский интерфейс GWT с помощью виджетов и панелей, а так же подписали свои куски кода на события ввода. Теперь мы готовый написать клиентский код, который делал что нибудь с нашим приложением.

Проверка введенных данных

Когда пользователь первый раз запускает StockWatcher, ему придется добавить акции ведя их название в текстовое поле, что бы просматривать ее состояние. Прежде чем добавить название акции, мы должны убедиться в том, что такое название акции существует. Если нет, мы предупреждаем его через окно.

Прежде всего надо добавить код к addStock() для получения названия новой акции. Мы используем метод getText () класса TextBox для получения текста. GWT виджеты и панели содержат богатый набор свойств и методов, многие из которых обращаются непосредственно к методам 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 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 com.google.gwt.user.client.Window;

На данный момент, вы можете пойти дальше и перекомпилировать и запустить StockWatcher приложения для проверки пользовательского ввода.

Если у вас уже открыт хост браузер, то вам не надо перезагружать его. Просто нажмите кнопку "Обновить" на панели инструментов, чтобы перезагрузить ваш новый GWT код.

Управление списоком акций

Хотя приложение StockWatcher получило возможность проверить название акций, оно все равно не оправдает свое назначение: пользователь еще не может добавлять акции в свой список. Давайте двигаться вперед и работать над этой функциональностью сейчас. Как вы помните, наш интерфейс содержит виджет FlexTable с именем stocksFlexTable, который будет содержать список акций. Каждая строка в списке будут содержать название акции, ее текущую цену, значение на сколько изменилось цена, и кнопка для удаления этой акции из списка. Теперь, давайте просто сосредоточиться на добавление и удаление акции в/из списка, и не будем беспокоиться по поводу установления и изменение цен акций.

Во-первых, мы нуждаемся в структуре данных для хранения названий акций которые в текущий момент наблюдает пользователь. Давайте использовать стандартный список 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 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);


Новое дополнение должно быть относительно простым. Во-первых, мы добавить новую строку в наш виджет FlexTable, у нас настроено, что первая колонка отображает название акции (помните, что метод setText(int, int, String) будет автоматически создавать новые клетки по мере необходимости, поэтому нам не нужно конкретно указывать размер таблицы). Далее, мы создаем кнопку для удаления акции и помещаем ее в последнюю колонку таблицы используя метод setWidget (int, int, Widget) (но не перед установкой слушателя ClickListener, который удаляет акцию из таблицы и массива акций (ArrayList)).

А теперь момент истины: запустите (или обновите) хост браузер. Та-да! Вы должны иметь возможность добавлять и удалять символы акций сами. Осталось не реализованная функциональность изменения цен.


Обновление цен акций


Заключительный и наиболее важной особенностью StockWatcher является это достаточно поразительное обновление наблюдаемых цен акций. Если бы мы писали приложение, использующие традиционные методы веб-разработок мы бы рассчитывали на полную перезагрузку страницы каждый раз, когда хотели бы обновить цены. Это может быть достигнуто либо вручную (нажатием пользователей в своем браузере кнопки "Обновить") или автоматически (например, с использованием <META http-equiv="refresh" content="5"> тегов HTML в заголовке нашей страницы). Но в эту эпоху Web 2.0, это просто не прилично. В наше время торговцам (брокерам и т.д.) нужно автоматическое обновление цен... без всяких обновлений страницы.

К счастью для нас GWT позволяет легко обновить содержание "на лету" нашего приложения. Давайте добавим автоматическое обновление цен акций приложения StockWatcher с помощью класса таймера.

Автоматическое обновление с помощью таймера

Таймер является одно-поточным, браузерно-безопасным классом. Это позволяет нам планировать запуск кода в какой либо момент времени, либо один раз используя schedule(int), или неоднократно с scheduleRepeating(int). Мы будем использовать последний метод для автоматического обновления наших фондовых цен каждые пять секунд.

Для использования таймера, мы создаем новый экземпляр Timer в нашем методе onModuleLoad () и переопределияем метод Run() в таймере. Метод Run () будет вызываться, когда таймер сработает. В нашем случае, мы вызовем метод refreshWatchList(), который будет фактически выполнять обновление. Добавим инструкцию импорта Timer, а затем изменим код onModuleLoad()Ю добавим в его конец следующие строки:

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


В дополнение к изменениям кода onModuleLoad(), вам также необходимо определить константу, которая определяет частоту обновления. Добавим, что в верхней части класса StockWatcher.

private static final int REFRESH_INTERVAL = 5000; // ms

Прежде чем мы продолжим, нам необходимо добавить еще один вызов метода refreshWatchList(). Мы вызовем его в addStock () сразу после добавления новой акции в FlexTable (Так при появлении новой акции, сразу будут видны изменения в ценах):

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 AJAX это возможность нам писать наши приложения на языке Java. Из-за этого, мы можем воспользоваться статичной проверкой компилятора и проверкой во времени, задействовать шаблоны объектно-ориентированного программирования, которые в сочетании с современными функциями IDE, такие как завершения кода и автоматизированный рефакторинг, все это дает ее проще, чем когда-либо писать надежные AJAX приложения с хорошо организованной базой кода.

Мы будем использовать этот потенциал для StockWatcher. Для данных о ценах акция и их изменении мы создадим собственный класс. Создадим новый Java класс с именем StockPrice в пакете com.google.gwt.sample.stockwatcher.client (в 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 для акций включая данные о ценах, давайте использовать его для обновления таблицы акций. Во-первых, мы должны создать реальные данные. Вместо фактически получения в реальном времени цен на акции от источника данных в сети, давайте просто использовать встроенный GWT генератор псевдо-случайных чисел для цен их изменений. Мы будем заполнять массив объектов StockPrice с этими значениями, а затем передавать их в другую функцию для обновления списка FlexTable. Добавим инструкцию импорта функции импорта и код в класс StockWatcher:


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


Обновление списка

Последние две новых функций будут обновлять дисплей новыми ценами. В updateTable(StockPrice) вы можете увидеть пример использования класса NumberFormat для форматирования числовых значений в строку. В нашем случае мы используем его для вывода числа в формате цены (разделитель с двумя знаками после запятой), и для отображения индикатора перемены цены. Кроме того, обратите внимание на использование класса DateTimeFormat в методе updateTable(StockPrice[]) на формат текущей даты и времени. Идем дальше и включим обе эти функции в 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 классы находятся в отдельном пакете следовательно вам необходимо добавить еще инструкции импорта, а также одну инструкцию для стандартного класса времени (java.util.Date) Java стандартные:

import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import java.util.Date;


Возможно, вы заметили, что DateTimeFormat и NumberFormat находяться в пакете из com.google.gwt.i18, которые свидетельствуют о том, что они имеют дело с интернационализацией в той или иной мере. И действительно они ... оба класса будут автоматически использовать настройки локали для форматирования чисел и дат. Мы будем говорить о локализации и переводе ваших приложений GWT позднее.

Настало время для тестирования наших изменений. Запустите или обновите приложение в режиме хоста и попробуйте добавить некоторые акции в список. Теперь мы можем видеть текущий список акций и их изменений. Если вы посмотрите за работой приложения, то вы уведите как меняются цены акций и дата обновления внизу.


Так, полюбовавшись нашим приложением StockWatcher — оно работает прекрасно. Или это не так? Как выясняется, есть одна тонкая ошибка. Вы можете заметить ее (подсказка: это заметно в скриншоте выше). В следующем разделе мы будем использовать Java для приобретения навыков для отладки.

Комментариев нет:

Отправить комментарий