понедельник, 11 июня 2012 г.

Creating and handling GWT сustom events

     События в GWT используют модель обработки аналогично многим другим фреймворкам. Интерфейс обработчика определяет один или несколько методов, которые виджет вызывает при соответствующем событии. Класс, желающий получить событие определенного типа, реализует соответствующий интерфейс обработчика и передает ссылку на себя виджету, чтобы подписаться на множество событий.
   События всегда отправляют для сообщения чего-то (например, изменение состояния). Давайте представим, что есть игра, где пользователь может ходить, как человек в лабиринте. Каждый раз, когда пользователь сталкивается со стеной, он должен быть проинформирован об этом, чтобы правильно отреагировать (например, стена может отрисовать себя как разрушенную). Это может быть сделано путем отправки событий столкновения, каждый раз когда происходит столкновение со стеной. Это событие посылается человеку и каждому объекту в системе заинтересованному в получении события, чтобы соответ. образом отреагировать. Объекты, которые хотят получать события должны зарегистрировать себя как заинтересованные в событиях. 
       Такое поведение событий свойственно любой системе и фреймворку, а не только в GWT. Для отправки и получения событий в каждой системе должны быть определенны следующие шаги:
1) что отправлять (как должны выглядеть события)
2) кто получает события (получатели)
3) кто отправляет события (отправители)
        А потом можно:
1) зарегистрировать получателей событий, которые хотят получать события
2) отправить события
      Давайте рассмотрим создание и использование собственных событий в GWT. В примере будет показана система, которая отвечает за проверку пожеланий и информирует пользователя, если есть новые пожелания. Предположим, что в системе есть, как минимум два компонента: компонент проверки, который отвечает за проверку нового пожелания и компонент отображения отвечающий за отображение пожелания. Проверяющий компонент отправляет события, когда приходят новые пожелания, а компонент отображения получает эти события. 
     Напишем класс собственного события.
/**
* Class that represent an information of new smile
*/
public class SmileReceivedEvent extends GwtEvent<SmileReceivedEventHandler> {

  // just type of handler
  public static Type<SmileReceivedEventHandler> TYPE =
      new Type<SmileReceivedEventHandler>();

  // let's assume that it will be a wish
  public final String smile;

  public SmileReceivedEvent(String smile) {
    this.smile = smile;
  }

  @Override
  public Type<SmileReceivedEventHandler> getAssociatedType() {
    return TYPE;
  }

  @Override
  protected void dispatch(SmileReceivedEventHandler handler) {
    handler.onSmileReceived(this);
  }

  public String getSmile() {
    return smile;
  }
}


* This source code was highlighted with Source Code Highlighter.
     Класс хранит информацию о пожелании (передается в конструкторе). Получатель события может получить его через метод getSmile(). Каждый класс представляющий собой GWT событие должен наследоваться от класса GwtEvent. Этот класс содержит два абстрактных метода, которые должны быть реализованы: getAssociatedType() и dispatch(). В каждом классе событий они, как правило, реализуются очень похожим образом.
     Любой тип события в GWT связан с интерфейсом представляющим приемника этого типа события. В примере интерфейс получателя события для SmileReceivedEvent наз. SmileReceivedEventHandler.
/**
* Interface that represents event receivers
*/
public interface SmileReceivedEventHandler extends EventHandler {
  public void onSmileReceived(SmileReceivedEvent event);
}


* This source code was highlighted with Source Code Highlighter.
     Каждый обработчик должен наследоваться от EventHandler интерфейса. Следует также определить метод, как минимум с один параметром - событие, который будет вызываться при возникновении события. Каждый получатель может реагировать на событие, через реализацию этого метода.
     Класс SmileShowing является компонентом, который получает событие и отображает пожелания.
/**
* Class that listening an events and reacts on them.
*/
public class SmileShowing extends Label implements SmileReceivedEventHandler {
  @Override
  public void onSmileReceived(SmileReceivedEvent event) {
    this.setText(event.getSmile());
  }
}


* This source code was highlighted with Source Code Highlighter.
     Класс SmileChecker отвечает за проверку пожеланий:
/**
* Class responsible for checking wishes
*/
public class SmileChecker implements HasHandlers {

  private HandlerManager handlerManager;

  public SmileChecker() {
    handlerManager = new HandlerManager(this);
  }

  /**
   * method responsible for sending events
   */
  @Override
  public void fireEvent(GwtEvent<?> event) {
    handlerManager.fireEvent(event);
  }

  /**
   * used by event receivers to register themselves as interested in receiving events.
   */
  public HandlerRegistration addSmileReceivedEventHandler(SmileReceivedEventHandler eventHandler) {
    return handlerManager.addHandler(SmileReceivedEvent.TYPE, eventHandler);
  }

  public void newSmileReceived() {
    fireEvent(new SmileReceivedEvent("This SMILE is just for you :-)"));
  }
}


* This source code was highlighted with Source Code Highlighter.
     Любой класс отправитель событий должен реализовать интерфейс HasHandlers. В этом классе HandlerManager отвечает за управление обработчиками событий. Как было сказано ранее, любой получатель событий, который хочет получать события должен зарегистрировать себя в качестве заинтересованного. Он позволяет регистрировать обработчики событий, а они могут отправлять конкретные события для каждого зарегистрированного обработчика. Когда создается HandlerManager, он принимает один аргумент в конструкторе. Каждое событие имеет источник происхождения и этот параметр будет использоваться в качестве источника для всех событий отправляемых через этот handlerManager.
     Давайте рассмотрим несколько иной способ создания собственных событий. Построим еще одну реализацию событий с использованием GWT EventBus из пакета com.google.web.bindery.event.shared. Пример, как построить собственное событие с использованием GWT 2.4:
/**
* Smile event. This event extends the Event from com.google.web.bindery.event.shared package.
*/
public class SmileReceivedEvent extends Event<SmileReceivedEvent.Handler> {
  /**
   * Implemented by methods that handle SmileReceivedEvent events.
   */
  public interface Handler {
    public void onSmileReceived(SmileReceivedEvent event);
  }

  private static final Type<SmileReceivedEvent.Handler> TYPE =
      new Type<SmileReceivedEvent.Handler>();

  private final String smile;

  public SmileReceivedEvent(String smile) {
    this.smile = smile;
  }

  @Override
  public Type<Handler> getAssociatedType() {
    return TYPE;
  }

  @Override
  protected void dispatch(Handler handler) {
    handler.onSmileReceived(this);
  }

  /**
   * Register a handler for SmileReceivedEvent events on the eventBus
   */
  public static HandlerRegistration register(EventBus eventBus, SmileReceivedEvent.Handler handler) {
    return eventBus.addHandler(TYPE, handler);
  }

  public String getSmile() {
    return smile;
  }
}


* This source code was highlighted with Source Code Highlighter.
     Чтобы зарегистрировать обработчик для этого события с eventBus, нужно вызвать статический метод HandlerRegistration#register(EventBus eventBus, SmileReceivedEvent.Handler handler).
     Класс SmileReceiver является компонентом, который получает событие и отображает пожелание.
/**
* Class that listening an events and reacts on them.
*/
public class SmileReceiver extends Label {
  public SmileReceiver(SimpleEventBus eventBus) {
    SmileReceivedEvent.register(eventBus, new SmileReceivedEvent.Handler() {
      @Override
      public void onSmileReceived(SmileReceivedEvent event) {
        SmileReceiver.this.setText(event.getSmile());
      }
    });
  }
}


* This source code was highlighted with Source Code Highlighter.
     Для инициирования события на eventBus следует вызвать метод fireEvent и передать в качестве аргумента событие.
eventBus.fireEvent(new SmileReceivedEvent("Smile today and everyday! ^__^"));

* This source code was highlighted with Source Code Highlighter.
     Вот как выглядит главный класс для запуска примера:
public class CustomGwtEvent implements EntryPoint {
  public void onModuleLoad() {
    SmileChecker checker = new SmileChecker();
    SmileShowing showingSmile = new SmileShowing();
    // define event receivers and register themselves in event senders
    checker.addSmileReceivedEventHandler(showingSmile);
    checker.newSmileReceived();

    SimpleEventBus eventBus = new SimpleEventBus();
    SmileReceiver receiverSmile = new SmileReceiver(eventBus);
    eventBus.fireEvent(new SmileReceivedEvent("Smile today and everyday! ^__^"));

    RootPanel.get().add(showingSmile);
    RootPanel.get().add(receiverSmile);
  }
}


* This source code was highlighted with Source Code Highlighter.
Eclipse проект можно скачать по следующей ссылке.

суббота, 9 июня 2012 г.

GWT carousel widget

     Рассмотрим создание виджета "карусель" с помощью JQuery и JCoverflip.
JCoverflip является плагином на JQuery, который позволяет организовать виджет типа карусель и отлично подойдет для презентаций различных материалов. Плагин достаточно стабилен и гибкий, позволяет настраивать цвета, шрифты, стили, скорость анимации, количество элементов и др. Взгляните сюда, чтобы увидеть карусель в действии. 
     Подключаем jcoverflip напрямую из папки, а jquery и jquery ui из серверов Google:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.js"></script>
<script type="text/javascript" language="javascript" src="jquery.jcoverflip.js"></script>


* This source code was highlighted with Source Code Highlighter.
данный способ является рекомендуемым Google и наиболее оптимален. Подробную информацию о списке доступных для подключения библиотек и их адресах на серверах можно получить на странице Google Libraries API. Также следует добавить блок стилей в хостовую стораницу Carousel.html, как в инструкции на сайте. Осталось добавить div с изображениями в тело страницы, над которыми будем делать манипуляции.
<div id="carouselWrapper">
 <p id="coverflip">
    <a href="img/prev.gif" rel="previous"><img alt="prev image" src="img/prev.gif" /> </a>            
    <a href="img/play.gif" rel="play"><img alt="play image" src="img/play.gif" /> </a>         
    <a href="img/pause.gif" rel="pause"><img alt="pause image" src="img/pause.gif"/> </a>
    <a href="img/stop.gif" rel="stop"><img alt="stop image" src="img/stop.gif"/> </a>
    <a href="img/next.gif" rel="next"><img alt="next image" src="img/next.gif" /> </a>
 </p>
</div>


* This source code was highlighted with Source Code Highlighter.
     При загрузке приложения следует вызвать JSNI метод showCarousel(), который вызывает jquery методы.
public class Carousel implements EntryPoint {
    public void onModuleLoad() {
        showCarousel();
    }
 
    /**
     * JSNI code that calls on the jquery methods
     * create div element with an anchor and span inside
     */
    public static native void showCarousel() /*-{
         // create the title element
         function createTitle(itemElem) {
             var title = $wnd.jQuery('<div class="title"></div>')
             .append(itemElem.find('img').attr('alt'))
             .append(' <a href="'+itemElem.attr('href')+'">(click here to view image)</a>')
             .append(' <span class="tags">'+itemElem.attr('rel')+'</span>');
             return title;
         }
        
         // delete the title element
         function destroyTitle(titleElem) {
             titleElem.remove();
         }
         
         $wnd.jQuery('#coverflip').jcoverflip({
             time: 800, //animation transition period
             titles: {
                create: createTitle,
              destroy: destroyTitle
            }
         });
    }-*/;
}


* This source code was highlighted with Source Code Highlighter.
     Из готовых GWT решений на просторах интернета есть еще такие варианты: gwt-yui-carouselspiral-carousel-gwt и gwt-carousel. Вот и все, gwt карусель выглядит вот так, анимация и поведение совпадает с демкой на сайте. Eclipse проект можно скачать по следующей ссылке.