GWT-GXT пример с ComboBoxБиблиотека GXT позволяет расширить интерфейсные возможности фреймворка GWT дополнительными визуальными компонентами, различными вариантами их размещения, возможностью работы с моделями данных и кэширующей их подсистемой. Интерфейс WEB-приложения с совместным использованием GWT-GXT можно оформить в виде традиционных десктопных приложений. Подробности инсталляции и демонстрационные возможности библиотеки Sencha GXT рассмотрены здесь. На данной странице рассматривается GWT-GXT в среде разработки IDE Eclipse. В примере используется визуальный компонент в виде выпадающего списка типа ComboBox. Возможности компонента не ограничиваются выбором значения из простого списка записей. Можно в раскрывающемся окне рядом с записью отобразить иконку, либо отобразить информацию о записи в нескольких колонках. В примере будет представлено 3 различных варианта использования компонента ComboBox. На следующем скриншоте представлен один из вариантов использования ComboBox с дополнительным размещением иконок (флаги стран) в записях :
Описание компонента с отображением иконок в выпадающем списке представлено здесь. Структура GWT-GXT примераПроцесс создания GWT-проекта в среде Eclipse здесь не рассматривается; он представлен на странице примера Welcome. При определении параметров данного проекта выбрано наименование gxt-combobox, определен корневой пакет для java-классов com.example, сняты флажки «Use Google App Engine» и «Generate project sample code». На следующем скриншоте представлена структура GWT-GXT проекта в среде разработки IDE Eclipse, включающая файл конфигурации Gxt_combobox.gwt.xml, главный модуль приложения Gxt_combobox.java, поддиректорию с файлами данных com.example.client.data, поддиректорию с widget'ом ComboboxStock, директорию war со стандартным набором файлов для WEB-приложения и графическими файлами поддиректории images/flags, используемые для отображения флагов стран. Формируемые GWT-компилятором коды скриптов (JavaScript) размещаются в поддиректории gwt-unitCache.
Фреймворк GWT был подключен к проекту на этапе его создания. Библиотека GXT была подключена как пользовательская (User Library). Более подробно об инсталляции и подключении библиотеки GXT к проекту GWT можно прочитать здесь. Хранилище объектов компонентов ComboBoxДля компонентов ComboBox необходимо создать хранилище типа ListStore<T>. Тип объектов хранилища должен совпадать с типом объектов ComboBox. В примере используются два типа объектов (Stock, Country), для которых создаются два хранилища. Ниже представлено описание хранилищ и объектов, интерфейсы свойств объектов, файлы с данными и описан процесс создания хранилищ ListStore<T>. Описание хранилищ и объектовВ следующем коде представлено определение хранилищ и описание объектов (методы get/set не включены) :
public static ListStore<Stock> STORE = null;
private ListStore<Country> COUNTIRES = null;
...
public class Stock
{
private int id;
private String name;
private String symbol;
private static int COUNTER = 0;
public Stock() {
this.id = COUNTER++;
}
public Stock(String name, String symbol) {
this();
this.name = name;
this.symbol = symbol;
}
}
public class Country
{
private String abbr ;
private String name ;
public Country() {}
public Country(String abbr, String name) {
setAbbr(abbr);
setName(name);
}
}
Поскольку хранилище STORE будет использоваться в двух компонентах ComboBox, то оно определено как статическое, чтобы можно было бы получить к нему удаленный доступ без передачи ссылки. Листинги интерфейсов свойств объектовДля создания хранилища необходимо определить интерфейсы свойств объектов (StockProperties, CountryProperties) типа PropertyAccess<T>.
import com.google.gwt.editor.client.Editor.Path;
import com.sencha.gxt.data.shared.LabelProvider;
import com.sencha.gxt.data.shared.ModelKeyProvider;
import com.sencha.gxt.data.shared.PropertyAccess;
import com.sencha.gxt.core.client.ValueProvider;
public interface StockProperties extends PropertyAccess<Stock>
{
@Path("id")
ModelKeyProvider<Stock> key();
@Path("symbol")
LabelProvider<Stock> symbolLabel();
ValueProvider<Stock, String> name ();
ValueProvider<Stock, String> symbol();
}
public interface CountryProperties extends PropertyAccess<Country>
{
@Path("abbr")
ModelKeyProvider<Country> abbr();
@Path("name")
LabelProvider<Country> name();
}
Файл данных StockData.java
import java.util.List;
import java.util.ArrayList;
public class StockData
{
public static List<Stock> getStocks()
{
List<Stock> stocks = new ArrayList<Stock>();
stocks.add(new Stock("Apple Inc." , "Apple" ));
stocks.add(new Stock("Cisco Systems, Inc." , "Cisco" ));
stocks.add(new Stock("Google Inc." , "Google" ));
stocks.add(new Stock("Intel Corporation" , "Intel" ));
stocks.add(new Stock("Microsoft Corporation", "Microsoft"));
stocks.add(new Stock("Nokia Corporation" , "Nokia" ));
stocks.add(new Stock("Oracle Corporation" , "Oracle" ));
stocks.add(new Stock("eBay Inc." , "Ebay" ));
stocks.add(new Stock("Avaya Inc." , "Avaya" ));
return stocks;
}
}
Файл данных CountryData.java
import java.util.List;
import java.util.ArrayList;
public class CountryData
{
public static List<Country> getCountries()
{
List<Country> countries = new ArrayList<Country>();
countries.add(new Country("ad", "Andora" ));
countries.add(new Country("ae", "Arab Emirates" ));
countries.add(new Country("ag", "Antigua And Barbuda"));
countries.add(new Country("ai", "Anguilla" ));
countries.add(new Country("al", "Albania" ));
countries.add(new Country("am", "Armenia" ));
countries.add(new Country("an", "Neth. Antilles" ));
countries.add(new Country("ao", "Angola" ));
countries.add(new Country("ar", "Argentina" ));
return countries;
}
}
Листинг метода создания хранилищПри создании хранилищ сначала определяются интерфейсы свойств объектов (sprops, cprops). После этого создаются хранилища, в конструкторы которых передаются объекты типа ModelKeyProvider, определяющие уникальность записей. После создания хранилищ в них загружаются данные списком методом addAll.
private StockProperties sprops = null;
private CountryProperties cprops = null;
private void createStores()
{
sprops = GWT.create(StockProperties .class);
cprops = GWT.create(CountryProperties.class);
STORE = new ListStore<Stock> (sprops.key());
STORE.addAll(StockData.getStocks());
COUNTIRES = new ListStore<Country>(cprops.abbr());
COUNTIRES.addAll(CountryData.getCountries());
}
Создание простого ComboBoxСоздание простого объекта combo1 выполняется в методе createCombobox1. При создании выпадающего списка combo1 в конструктор передается хранилище STORE и объект типа LabelProvider<? super Stock>, определяющий отображаемое в компоненте поле объекта.
private ComboBox<Stock> combo1 = null;
private void createCombobox1()
{
combo1 = new ComboBox<Stock>(STORE, sprops.symbolLabel());
combo1.setEmptyText("Select a company...");
combo1.setName("сombo1");
combo1.setTypeAhead(true);
combo1.setTriggerAction(TriggerAction.ALL);
combo1.setWidth(180);
combo1.addSelectionHandler(selectStock);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SelectionHandler<Stock> selectStock = new SelectionHandler<Stock>()
{
@Override
public void onSelection(SelectionEvent<Stock> selectionEvent){
/*
* Очистка фильтра, устанавливаемого вводом символов с клавиатуры
*/
if ((STORE != null) && (STORE.getFilters() != null) &&
(STORE.getFilters().size() > 0))
STORE.removeFilters();
}
};
Свойство EmptyText позволяет отображать в компоненте текст, если не выбрано ни одной записи из списка. Метод setTypeAhead при истинном значении (true) помогает пользователю выбрать запись из списка при наборе начальных символов с клавиатуры - оставшаяся часть наименования записи «дописывается». Метод setTriggerAction позволяет исключить или установить взаимосвязь двух и более компонентов. Для этого можно использовать одно из значений :
Важно отметить, что выбор записи из списка по начальным символам с использованием клавиатуры сопровождается установкой соответствующего фильтра в хранилище данных. Если хранилище данных используется совместно с другим компонентом, то непроизвольная фильтрация данных также отражается и на другом компоненте. Что исключить влияние одного компонента на другой к компоненту combo1 подключается обработчик событий selectStock, который, после выбора значения, очищает фильтр записей, устанавливаемый при работе с клавиатуры. Можно заблокировать выбор записи по первым символам с использованием клавиатуры. Для этого необходимо использовать метод setEditable(boolean) со значением false. На следующем скриншоте представлен раскрытый список combo1. Если ни одной записи не выбрано, то в компоненте отображается подстановочная запись EmptyText («Select a company...»).
Создание ComboBox с иконками в выпадающем спискеДля создания выпадающего списка ComboBox с отображением иконок необходимо использовать конструктор, которому в качестве параметров передается renderer типа SafeHtmlRenderer<T> для отображения значения в виде HTML строки :
ComboBox<T>(ListStore<T> store,
LabelProvider<? super Country> label,
SafeHtmlRenderer<T> renderer);
Необходимо подготовить renderer. Для этого создается интерфейс ISafeHtml, расширяющий свойства класса XTemplates библиотеки GXT и включающий функцию SafeHtml country(SafeUri imageUri, String name). В качестве параметров в функцию необходимо передать адрес изображения URL и наименование соответствующей записи. Аннотация к методу @XTemplate позволяет определить формат представления записей в выпадающем списке.
import com.google.gwt.safehtml.shared.SafeHtml;
import com.sencha.gxt.core.client.XTemplates;
. . .
interface ISafeHtml extends XTemplates
{
@XTemplate("<img width=\"16\" src=\"{imageUri}\"> {name}")
SafeHtml country(SafeUri imageUri, String name);
}
Для создания выпадающего списка combobox2 с иконками используется метод createCombobox2. Первоначально создается рендерер iSafeHtml стандартным для GWT методом create. После этого создается combo2. В методе render формируется URL изображения флага для каждой страны и вызывается метод country объекта iSafeHtml. При определении URL изображения используется GXT форматирование (Format.substitute), подробно описанное здесь. Методы setTypeAhead и setTriggerAction описаны выше.
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.sencha.gxt.core.client.XTemplates;
. . .
private ISafeHtml iSafeHtml = null;
private ComboBox<Country> combo2 = null;
private final String URL_TEMPL = "{0}images/flags/{1}.png";
. . .
private void createCombobox2()
{
iSafeHtml = GWT.create(ISafeHtml.class);
combo2 = new ComboBox<Country>(COUNTIRES, cprops.name(),
new AbstractSafeHtmlRenderer<Country>() {
@Override
public SafeHtml render(Country item){
String url = Format.substitute(URL_TEMPL,
GWT.getHostPageBaseURL(),
item.getAbbr());
SafeUri imageUri = UriUtils.fromString(url);
return iSafeHtml.country(imageUri, item.getName());
}
});
combo2.setWidth(180);
combo2.setTypeAhead(true);
combo2.setTriggerAction(TriggerAction.ALL);
}
Скриншот компонента ComboBox с иконками в выпадающем списке представлен наверху. Создание ComboBox с двумя колонками в выпадающем спискеДля создания выпадающего списка из двух и более колонок со значениями, определенными в модели данных, необходимо предварительно :
Формат представления данных опишем в файле stock.html. Класс StockCell.java будет формировать данные для представления в выпадающем списке. Листинг stock.htmlВ файле stock.html определены 2 колонки, размеры которых составляют 20% и 80% соответственно. В первой колонке будет представлено значение stock.id, во второй stock.name.
<!-- stock.html -->
<div style="width: 100%; overflow: hidden; white-space: nowrap;">
<div style="width: 20%; display: inline-block; overflow: hidden;
vertical-align: middle;">{stock.id}</div>
<div style="width: 80%; display: inline-block; overflow: hidden;
vertical-align: middle;">{stock.name}</div>
</div>
Листинг StockCell.javaКласс StockCell наследует свойства AbstractCell и используется для описания представления ячейки выпадающего списка. Формирование записей для отображения выполнятся методом render. Интерфейс StockXTemplates, как и в предыдущем компоненте combo2, наследует свойства класса XTemplates. Аннотация метода renderCell определяет представление значения в интерфейсе раскрывающегося списка.
import com.example.client.data.Stock;
import com.google.gwt.core.client.GWT;
import com.sencha.gxt.core.client.XTemplates;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
public class StockCell extends AbstractCell<Stock>
{
private StockXTemplates tpl = GWT.create(StockXTemplates.class);
public interface StockXTemplates extends XTemplates {
@XTemplate(source = "stock.html")
SafeHtml renderCell(Stock stock);
}
@Override
public void render(Context context, Stock stock,SafeHtmlBuilder sb){
sb.append(tpl.renderCell(stock));
}
}
Листинг ComboboxStock.javaТретий компонент выпадающего списка выполнен в виде отдельного widget'а. Конструктор компонента в качестве параметра получает ссылку на обработчик события, возникающего при выборе записи в компоненте; обработка выполняется «родителем».
public class ComboboxStock implements IsWidget
{
private ComboBox <Stock> comboBox = null;
private StockProperties properties = null;
public ComboboxStock (SelectionHandler<Stock> handler)
{
properties = GWT.create(StockProperties.class);
createComboBox(handler);
}
ComboBox<Stock> createComboBox(SelectionHandler<Stock> handler)
{
ListView<Stock, Stock> listView = null;
IdentityValueProvider<Stock> identity = null;
StockCell stockCell = null;
ComboBoxCell<Stock> comboCell = null;
identity = new IdentityValueProvider<Stock>();
stockCell = new StockCell();
listView = new ListView<Stock, Stock>(Gxt_combobox.STORE,
identity, stockCell);
comboCell = new ComboBoxCell<Stock> (Gxt_combobox.STORE,
properties.symbolLabel(),
listView);
comboBox = new ComboBox<Stock>(comboCell);
comboBox.setEditable(false);
comboBox.setTriggerAction(TriggerAction.ALL);
comboBox.setWidth(80);
comboBox.addSelectionHandler(handler);
return comboBox;
}
@Override
public Widget asWidget()
{
return comboBox;
}
}
В методе createComboBox создается третий компонент с выпадающим списком. Сначала подготавливается объект представления listView, после этого создается ячейка представления записи comboCell. Конструктор ComboBox получает в качестве единственного параметра объект comboCell. Настройка свойств объекта (setTriggerAction, setEditable) описана выше. Важно знать, что метод asWidget вызывается при размещении компонента в интерфейсе. Если widget используется неоднократно, то нежелательно в этом методе создавать объект. В примере объект создается в конструкторе компонента. Интерфейс компонента с раскрытым списком из двух колонок представлен на следующем скриншоте.
Главный модуль проектаГлавный модуль Gxt_combobox.java реализует интерфейсы IsWidget и EntryPoint, включающие методы asWidget (widget интерфейса) и onModuleLoad (точка входа). Листинг главного модуля приложения представлен в усеченном виде. Все остальное представлено выше и не составит особого труда «слепить весь код воедино», либо скачать исходный код.
public class Gxt_combobox implements IsWidget, EntryPoint
{
SelectionHandler<Stock> handler = new SelectionHandler<Stock>() {
@Override
public void onSelection(SelectionEvent<Stock> selectionEvent) {
Stock stock = selectionEvent.getSelectedItem();
Info.display("SelectionHandler", stock.getName());
}
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public Widget asWidget()
{
ContentPanel panel = new ContentPanel();
panel.setHeadingText("GXT ComboBox");
panel.setPixelSize(240, 180);
panel.addStyleName("margin-5");
createStores ();
createCombobox1();
createCombobox2();
ComboboxStock combo3 = new ComboboxStock(handler);
Margins margins = new Margins(10, 6, 0, 6);
VerticalLayoutContainer vlc = new VerticalLayoutContainer();
vlc.add(combo1, new VerticalLayoutData(-1, -1, margins));
vlc.add(combo2, new VerticalLayoutData(-1, -1, margins));
vlc.add(combo3, new VerticalLayoutData( 1, -1, margins));
panel.add(vlc);
return panel;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void onModuleLoad()
{
RootPanel.get("wrapper").add(asWidget());
}
}
Обработчик событий handler будет вызываться при выборе одной из записи выпадающего списка combo3 для отображения наименования в кратковременно всплывающем окне Info . В методе asWidget создается панель типа ContentPanel - определяется размер панели и стиль "margin-5". Чтобы компоненты равномерно разместить в интерфейсе используется контейнер вертикального размещения VerticalLayoutContainer. Интерфейс главной панели создается как widget и размещается в секции «wrapper» (Gxt_toolbar.html). При формирование интерфейса страницы были использованы компоненты VerticalLayoutContainer и Margins, подробно описанные здесь. Листинг Gxt_combobox.htmlТело страницы содержит секцию wrapper, в которую помещается создаваемая главным модулем панель с компонентами.
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="Gxt_combobox.css">
<title>GXT ComboBox</title>
<script type="text/javascript"
src="gxt_combobox/gxt_combobox.nocache.js" ></script>
</head>
<body>
<div id="wrapper"></div>
</body>
</html>
Конфигурационный файл проекта Gxt_combobox.gwt.xml<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd"> <module rename-to='gxt_combobox'> <inherits name='com.google.gwt.user.User' /> <!-- Other module inherits --> <inherits name="com.sencha.gxt.ui.GXT" /> <inherits name="com.sencha.gxt.theme.gray.Gray" /> <!-- inherits name="com.sencha.gxt.theme.blue.Blue" --> <!-- inherits name='com.google.gwt.user.theme.standard.Standard'--> <!-- inherits name='com.google.gwt.user.theme.dark.Dark' --> <!-- inherits name='com.google.gwt.user.theme.chrome.Chrome' --> <!-- Entry point class --> <entry-point class='com.example.client.Gxt_combobox' /> <!-- Specify the paths for translatable code --> <source path='client'/> <source path='shared'/> </module> В конфигурационном файле Gxt_combobox.gwt.xml определяем библиотеку GXT, выбираем тему (стиль интерфейса) Gray бибилиотеки GXT (Gray, Blue). Можно выбрать тему и из набора GWT (Standard, Dark, Chrome). В качестве главного модуля приложения, включающего точку входа в приложение (метод onModuleLoad), определен com.example.client.Gxt_combobox. Скачать исходный код примераИсходный код рассмотренного GWT-GXT примера с использованием ComboBox в виде проекта Eclipse можно скачать здесь (7.85 Мб). В архив примера включен библиотечный файл gwt-servlet.jar, GXT библиотека gxt-3.1.1.jar не включена. После инcталляции примера в IDE Eclipse необходимо настроить GWT SDK самостоятельно («Build Path/Configure Build Path»). Примечание : библиотека gxt-3.1.1.jar входит в дистрибутив GWT-GXT-примера с использованием табличного компонента Grid |
