HOME > 開発者向けBLOG > Sencha Blog >  データ処理を中心とするアプリケーションのための GXT グリッドのカスタマイズ

Technology Note 開発者向けBLOG

Sencha Blog

データ処理を中心とするアプリケーションのための GXT グリッドのカスタマイズ

こんにちは、ゼノフィseoです。

この記事は、US Sencha社ブログ Customizing GXT Grid for Data Centric Applications(2016年3月23日|David Chandler)を翻訳したものです

企業アプリのコンポーネントの中でも特に人気があるのが GXT Grid です。ビルトインで以下のような強力な機能を持っています:

  • ローカルもしくはリモートフィルタリング
  • ローカルもしくはリモートソーティング
  • カラムグルーピング
  • ツリービュー (TreeGrid)
  • ページング と 無限スクロール
  • 編集可能なセル
  • 伸張性のあるカラムヘッダーメニュー

GXT Grid

当記事では、Grid を企業での使用用途にあわせた、3つのカスタマイズ方法をご紹介します:

  • カスタムハイパーリンクセルの作成
  • 行、セル単位での編集を有効化
  • カラムヘッダーメニューの拡張

カスタムハイパーリンクセルの作成

GXT は GXT Grid で使用することができるセルの種類をいくつも提供しています。これらはどれも GWT AbstractCell クラス を拡張するものであり、GWT セルウィジェットと置き換えることもできます。つまり、GXT セルを GWT CellTable 内もしくは GWT セルを GXT Grid 内で使用することができるということです。

GWT と GXT に含まれていないセルの種類の1つが、シンプルハイパーリンクセルであり、水面下のレコードのアトリビュートを基礎としたクリック可能なリンクを表示するものです。この例では、そういったセルを作成します。GWT AbstractCell タイプを拡張し、リンクへのクリックをハンドルする AnchorListener インターフェースを定義づける AnchorLinkCell を作成します。結果は以下のようになります:

Custom Hyperlink Cell

Name カラムは新しい AnchorLinkCell を使用します。

package com.example.project.client.customcell;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.sencha.gxt.core.client.ValueProvider;
 
/**
 * Displays a hyperlink anchor in a cell and provides an interface
 * to handle onClick.
 */
public class AnchorLinkCell<T> extends AbstractCell<T> {
 
    public interface AnchorListener<T> {
        void onClick(T value);
    }
 
    private final ValueProvider<T, String> vp;
    private final AnchorListener<T> listener;
 
    public AnchorLinkCell(ValueProvider<T, String> vp, AnchorListener<T> listener) {
        // consume click event
        super("click");
        this.listener = listener;
        this.vp = vp;
    }
 
    @Override
    public void render(com.google.gwt.cell.client.Cell.Context context, T obj, SafeHtmlBuilder sb) {
        sb.appendHtmlConstant("<div style='color: -webkit-link; text-decoration: underline; cursor: pointer'><a>");
        sb.append(SafeHtmlUtils.fromString(this.vp.getValue(obj)));
        sb.appendHtmlConstant("</a></div>");    }
 
    @Override
    public void onBrowserEvent(com.google.gwt.cell.client.Cell.Context context, Element parent, T value, NativeEvent event, ValueUpdater<T> valueUpdater) {
        super.onBrowserEvent(context, parent, value, event, valueUpdater);
        if (parent.getFirstChildElement().isOrHasChild(Element.as(event.getEventTarget()))) {
            listener.onClick(value);
        }
    }
}

AnchorLinkCell コンストラクターは GXT ValueProvide をサプライし、ハイパーリンクテキストを取得するために使用されます。それに加え、クリックをハンドルするために AnchorListener をサプライします。render() メソッドは <a>エレメントを含んだ <div> を作成します。この例を簡単にするために、インラインスタイルを使用しています。デフォルトのハイパーリンクスタイルは GXT reset.css によってオーバーライドされるため、標準のスタンダードハイパーリンクの表示を再作成しなければなりません。 onBrowserEvent() は全てのコンシュームされたイベント (今回の場合はマウスクリックのみ)を ActionListener に委任するためにオーバーライドされます。

ここからはカラムにどの様に AnchorLinkCell を結び付けるかを見ていきましょう。まず、Grid内のモデルタイプのデータを代表する Employee クラスとそれに対応する PropertyAcess インターフェースがあるとします。セルを使用するには ColumnConfig を作成し、セルタイプをカスタム AnchorLinkCell に設定しましょう:

        EmployeePropertyAccess epa = GWT.create(EmployeePropertyAccess.class);
        ...
        ColumnConfig<Employee, Employee> nameCol = new ColumnConfig<Employee, Employee>(epa.identity(), 100, "name");
        nameCol.setCell(new AnchorLinkCell<Employee>(epa.name(), new AnchorListener<Employee>() {
            @Override
            public void onClick(Employee emp) {
                Info.display("onClick", "You selected employee # " + emp.getId());
            }
        }));
      ...

ColumnConfig のタイプパラメータを覚えておきましょう。カラムタイプパラメータとセルタイプパラメータは両方モデルタイプ、Employee であります。これは Employee レコードが AnchorListener までパスされることを保証しています。これをうまくいかせるには、ColumnConfig コンストラクター内の ValueProvider タイプは Employee クラスの IdentityProvider でなければなりません。もし AnchorLinkCell クラスによりたくさんの情報を提供しようと思った場合(たとえばハイパーリンク URL 内で使用される Employee ID など)、AnchorLinkCell コンストラクターを改変し、単一の ValueProvider だけでなく、PropertyAccess インターフェース全てを受け取れるようにすることができます。

行での編集を有効化

インライン編集グリッドは GXT の強力な機能の1つであり、セルをクリックもしくはダブルクリックすることでその場所にある値を編集することができます。編集を有効化するには、GridInLineEditing のインスタンスを作成し、有効化したい特定のカラムのために Editor を追加します。

        ColumnConfig<Employee, String> notesCol = new ColumnConfig<Employee, String>(epa.notes(), 100, "notes");
        final Grid<Employee> grid = new Grid<Employee>(listStore, columnModel);
        GridEditing<Employee> editing = new GridInlineEditing<Employee>(grid);
        editing.addEditor(notesCol, new TextField());
Editing by Row

その場で編集するには notes カラムをクリックしましょう。

上記のコードは notes カラムの全てのセルをインラインでの編集を有効化します。しかし、もし選択した行だけを編集可にしたい場合はどうしたらよいでしょうか? これは GridEditing クラスのメソッドをオーバーライドすることで可能となります。

        ColumnConfig<Employee, String> notesCol = new ColumnConfig<Employee, String>(epa.notes(), 100, "notes");
        final Grid<Employee> grid = new Grid<Employee>(listStore, columnModel);
        GridEditing<Employee> editing = new GridInlineEditing<Employee>(grid) {
            // disable editing on select rows
            public void startEditing(Grid.GridCell cell) {
                editEmployee = getEditableGrid().getStore().get(cell.getRow());
                // Only names that start with S are editable
                if (editEmployee.getName().startsWith("S")) {
                    super.startEditing(cell);
                }
            };
        };
        editing.addEditor(notesCol, new TextField());

startEditring() メソッドはユーザーが編集可能なカラムをクリックした時にいつでも呼び出されます。 しかし、super.startEditing() をコールしなければセルを編集し始めることはできません。この機能を利用すれば特定の行の編集を無効化させることができます。この場合、従業員の名前が S で始まる時のみ、どの行でも編集が可能となっております。また、cell.getCol() プロパティを使用して、カラム記述子を取得し、特定の行や列を編集可能にするか判断することも可能です。

カラムヘッダーの拡張

3つ目のカスタマイズは、カラムヘッダードロップダウンメニューにアイテムを追加する方法です。一般的には GXT は Grid 機能(例えば有効化したソーティングなど)に合わせてメニューをビルドします。

GXT-generated Column Header Menu

GXTで生成されたカラムヘッダーメニューはソートとカラム選択が可能です。

カラムヘッダーコンテキストメニューにカスタムメニューを追加するには、GridView クラス 内のcreateContexMenu() メソッドをオーバーライドします。 この例では、カスタムアクションを全てのカラムのヘッダーメニューに追加します:

        // Custom header menu items
        final Grid<Employee> grid = new Grid<Employee>(listStore, columnModel, new GridView<Employee>() {
            @Override
            protected Menu createContextMenu(int colIndex) {
                Menu menu = super.createContextMenu(colIndex);
                menu.add(new MenuItem("custom1", new SelectionHandler<MenuItem>() {
                    @Override
                    public void onSelection(SelectionEvent<MenuItem> event) {
                        Info.display("test", "You clicked custom1");
                    }
                }));
                return menu;
            }
        });

結果は以下となります:

New Custom Menu Item

新しいカスタムメニューアイテムはビルトインのメニューアイテムの後に表示されます。

さらに、カスタムコンテキストメニューの中身を完全に入れ替えたい場合は、コールを super.createContextMenu()と入れ替えてしまえば問題ありません:

In addition, if we want to completely replace the contents of the custom context menu, we can do this by simply replacing the call to super.createContextMenu():

            ...
            protected Menu createContextMenu(int colIndex) {
                Menu menu = new Menu();
                menu.add(new MenuItem("custom1", new SelectionHandler<MenuItem>() {

結果は以下のようになるはずです:

Custom Menu Replaces Built-in Menu

カスタムメニューはビルトインメニューと完全に入れ替えることが可能です。

結果

Grid は強力で拡張性豊かな GXT のコンポーネントであり、企業用のアプリケーションでは非常に人気があります。強力な GridEditing と GridView クラスを拡張することで、強力な UI を持った機能性豊かなウェブアプリケーションの機能をよりカスタマイズすることができます。

PAGETOP