エンタープライズギークス (Enterprise Geeks)

企業システムの企画・開発に携わる技術者集団のブログです。開発言語やフレームワークなどアプリケーション開発に関する各種情報を発信しています。ウルシステムズのエンジニア有志が運営しています。

GWTの拡張(2) - ローディングパネル

GWTGoogle Web Toolkit)はサーバ間通信を非同期で行う。
このため、入力したコード値に対応する名称をサーバから非同期で取得して画面に表示する際に、リクエスト処理中であることを表示するためにはアプリケーション側で制御する必要がある。
特に、こうした非同期処理を複数項目に対して適用したい場合には、複数の非同期通信が裏で行われることになるため、制御が難しくなる。

そこで、LoadingPanel(ローディングパネル)を作成した。ブラウザの特定の位置に、ぐるぐる回るアニメーション画像を表示するパネルで、非同期でサーバ通信中であることを表すために利用する。

パネルの仕様

1つの画面で複数の非同期通信を行う場合を考慮して、非同期通信が行われている間はパネルを表示し続け、非同期通信が全て終わった時にパネルが消えるようにする。

クラス概要

f:id:enterprisegeeks:20140522115632p:plain

処理概要

  1. 非同期通信処理時にshow()を呼ぶ。
  2. Panelは、内部のカウンタが0ならパネルを表示する。[Loading...]状態となる。
  3. Panelは、内部でカウンタを持っていて、カウントアップする。
  4. 非同期通信処理終了時にhide()を呼ぶ。
  5. Panelは、カウントダウンする。カウントが0なら、パネルを消す。

hideAll()は、カウントを0にし、パネルを消す。
このhideAll()は、非同期通信処理中にメニューなどへ画面遷移した場合に、非同期通信処理をキャンセルし、パネルを消す場合に利用する。

import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;

public class LoadingPanel extends Composite implements ResizeHandler {

    interface PanelPositionSetter {
        void setPosition(Element element);
    }

    private SimplePanel panel = new SimplePanel();

    private PanelPositionSetter positionSetter;

    private int loadCount = 0;

    public LoadingPanel() {
        this(createWidget());
    }

    public LoadingPanel(final Widget widget) {
        this(widget, createPositionSetter());
    }

    LoadingPanel(final Widget widget, 
                 final PanelPositionSetter positionSetter) {
        initialize(widget, positionSetter);
    }

    @Override
    public void onResize(final ResizeEvent event) {
        positionSetter.setPosition(this.getElement());
    }

    public void show() {
        setVisible(true);
        if (loadCount == 0) {
            DOM.setStyleAttribute(RootPanel.get().getElement(), "cursor",
                    "progress");
            RootPanel.get().add(this);
            panel.getElement().getStyle().setPosition(Position.ABSOLUTE);
            panel.getElement().getStyle().setZIndex(999999);
            positionSetter.setPosition(panel.getElement());
        }
        loadCount++;
    }

    public void hide() {
        loadCount--;
        if (loadCount <= 0) {
            RootPanel.get().remove(this);
            DOM.setStyleAttribute(RootPanel.get().getElement(), "cursor", "");
        }
    }

    public void hideAll() {
        loadCount = 0;
        hide();
    }

    public void setPositionSetter(final PanelPositionSetter positionSetter) {
        this.positionSetter = positionSetter;
    }

    protected void initialize(final Widget widget,
                              final PanelPositionSetter position) {
        initWidget(panel);
        panel.setWidget(widget);
        panel.getElement().setAttribute("name", "loadingPanel");
        panel.getElement().setClassName("loadingPanel");
        setVisible(false);
        this.positionSetter = position;
    }

    protected Widget createWidget() {
        return new Image("./loading.gif");
    }

    protected PanelPositionSetter createPositionSetter() {
        // 右上に表示
        return new PanelPositionSetter() {
            @Override
            public void setPosition(final Element element) {
                final int WINDOWS_IE_SCROLL_BAR_SIZE = 17;
                int top = DOM.getElementPropertyInt(RootPanel.getBodyElement(),
                        "scrollTop");
                int left = Window.getClientWidth()
                        - element.getOffsetWidth()
                        - WINDOWS_IE_SCROLL_BAR_SIZE
                        - DOM.getElementPropertyInt(RootPanel.getBodyElement(),
                                "scrollLeft");
                element.getStyle().setTop(top, Unit.PX);
                element.getStyle().setLeft(left, Unit.PX);
            }
        };
    }
}

なお、このローディングパネルのアイディアは、以下の書籍の「第8章 ブログエディタアプリケーション」で紹介されているLoadingPanelを参考にした。

Google Web Toolkit アプリケーション

Google Web Toolkit アプリケーション

  • 作者: ライアン・デュースバリー,Ryan Dewsbury,松田晃一,由谷哲夫
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2008/12/22
  • メディア: 単行本(ソフトカバー)
  • 購入: 4人 クリック: 32回
  • この商品を含むブログ (14件) を見る

[高橋 友樹]