Se algum dia você já se deparou com a seguinte situação: criar uma aplicação em web que possua diversas imagens estáticas (por exemplo ícones) e você utilizou css para selecionar e carregar as imagens… você já deve ter percebido que para cada imagem da aplicação uma nova conexão é aberta só para buscar essa imagem… e as demais só serão carregadas uma após a outra… pois é… para essa situação nada melhor que um ImageBundle! Para aqueles que ainda não conhecem essa funcionalidade vou dar uma pequena e rápida introdução. Confiram após o break
Um ImageBundle é um objeto que automaticamente pega todos os ícones mensionados anteriormente e os une em uma única imagem fazendo com que n requests ao servidor sejam condensadas em UMA ÚNICA!!! Além disso as imagens são “recortadas” depois tornando transparente ao usuário que se trata de uma mesma imagem. O procedimento de “recortar” novamente a figura depois de carregada é conhecido como “clipping” e é implementado através de CSS.
Parece complicado não é? Pois é… pode até parecer… mas utilizando GWT isso fica fácil fácil… e com algumas linhas de código tudo isso é rapidamente desenvolvido sem dores de cabeça e de maneira transparente ao programador!!!!! Isso é possível graças ao mecanismo batizado de Deferred Binding do GWT que fornece pontos de extensção ao framework. Em um próximo tópico explicarei como o Deferred Binding funciona e o que você pode fazer com essa funcionalidade.
Voltando ao ImageBundle….
Tudo que você precisará para a utlização de um ImageBundle é implementar uma interface que extende ImageBundle e criar métodos que retornam um object AbstractImagePrototype esse método deve conter anotações especificando quais recursos (leia-se imagens) devem ser carregados pelo compilador. O objeto AbstractImagePrototype possui um método muito útil que é o createImage() que retorna nada mais nada menos que a imagem que precisamos! Dito isso chega de conversa fiada e vamos ao código
Para exemplificar a técnica vamos construir um componente bastante usado em aplicações desktop, uma ToolBar. Como se sabe em uma ToolBar é muito comum o uso de Ãcones representando ferramentas ou funcionalidades do software. É nesse momento que o ImageBundle entra em cena. Para a criação do exemplo vou ilustrar uma ToolBar com e sem ImageBundle. Para verificar o número de conexões geradas para buscar a imagem utilizaremos o firebug, extensão do firefox que facilita e muito a vida dos desenvolvedores web.
As imagens utilizadas no exemplo bem como o código fonte estão disponÃveis no final do post em arquivos zip.
Inicialmente a classe que representa o componente ToolBar:
[java]
package br.com.gwt.client.toolbar;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.ButtonBase;
import com.google.gwt.user.client.ui.SimplePanel;
/**
* Uma ToolBar nada mais é senão um painel com botões que representam ações ou
* funcionalidades de um sistema. Geralmente os botões da toolbar utilizam Ãcones
* em vez de textos, entretanto esse detalhe não será tratado nessa classe.
*
* @author Marcelo Emanoel
*/
public class ToolBar extends Composite {
private FlexTable toolbarTable;
private int buttonCount;
public ToolBar(){
init();
setupStyles();
}
/**
* Inicializações
*/
private void init() {
toolbarTable = new FlexTable();
buttonCount = 0;
SimplePanel panel = new SimplePanel();
panel.add(toolbarTable);
initWidget(panel);
}
/**
* Adiciona um botão à ToolBar.
* @param button
*/
public void addButton(ButtonBase button){
toolbarTable.setWidget(0, buttonCount++, button);
}
/**
* Seta os estilos dos componentes internos e da ToolBar.
*/
private void setupStyles() {
setStylePrimaryName(”br_com_gwt_ToolBar”);
toolbarTable.setStylePrimaryName(”br_com_gwt_ToolBar”);
}
/**
* Retorna o número de botões existentes na ToolBar.
* @return
*/
public int getButtonCount() {
return buttonCount;
}
}
[/java]
Até aqui acredito que não temos muitas surpresas. A ToolBar é composta por uma FlexTable e botões adicionados a ela. Além disso é possÃvel contar quantos botões foram inseridos.
Agora vamos verificar como foi feito o ImageBundle.
[java]/**
*
*/
package br.com.gwt.client.toolbar.imagebundle;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.ImageBundle;
/**
* BlogBundle contém imagens relacionadas à atividades de um blog. Adicionar,
* remover, inserir videos bem como configurar alguma coisa no blog.
*
* As imagens foram retiradas do IconsPedia. Todos os direitos reservados.
* @author Marcelo Emanoel
*/
public interface BlogBundle extends ImageBundle {
/**
* Imagem de adicão.
* @return
*/
@Resource(”br/com/gwt/resources/add.png”)
public AbstractImagePrototype add();
/**
* Imagem de remoção.
* @return
*/
@Resource(”br/com/gwt/resources/remove.png”)
public AbstractImagePrototype remove();
/**
* Imagem de video.
* @return
*/
@Resource(”br/com/gwt/resources/video.png”)
public AbstractImagePrototype video();
/**
* Imagem de configuração.
* @return
*/
@Resource(”br/com/gwt/resources/settings.png”)
public AbstractImagePrototype settings();
/**
* Imagem de ok.
* @return
*/
@Resource(”br/com/gwt/resources/check.png”)
public AbstractImagePrototype check();
}[/java]
Finalmente como utilizar o ImageBundle e a ToolBar juntos.
[java]package br.com.gwt.client;
import br.com.gwt.client.toolbar.ToolBar;
import br.com.gwt.client.toolbar.imagebundle.BlogBundle;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define onModuleLoad().
*/
public class ImageBundleTest implements EntryPoint {
/**
* This is the entry point method.
* Instancia duas ToolBars uma com as imagens adquiridas via ImageBundle e a
* outra criada com imagens extraÃdas por css.
*
* O intuito é verificar o número de conexões extras causadas pela ausência
* do ImageBundle.
*/
public void onModuleLoad() {
/**
* Instancia-se o ImageBundle via Deferred Binding.
*/
BlogBundle blogBundle = GWT.create(BlogBundle.class);
ToolBar blogTools = new ToolBar();
ToolBar dbTools = new ToolBar();
DockPanel dock = new DockPanel();
RootPanel.get().add(dock);
dock.setStylePrimaryName(”dock”);
HTML center = new HTML();
dock.add(center, DockPanel.CENTER);
dock.setCellHeight(center, “100%”);
/*
* Instancia todas as imagens do ToolBar que usa ImageBundle.
*/
Image addImg = blogBundle.add().createImage();
Image removeImg = blogBundle.remove().createImage();
Image checkImg = blogBundle.check().createImage();
Image settingsImg = blogBundle.settings().createImage();
blogTools.addButton(createButton(addImg, blogTools.getButtonCount()));
blogTools.addButton(createButton(removeImg, blogTools.getButtonCount()));
blogTools.addButton(createButton(checkImg, blogTools.getButtonCount()));
blogTools.addButton(createButton(settingsImg, blogTools.getButtonCount()));
dbTools.addButton(createEmptyButton(dbTools.getButtonCount(),”feather”));
dbTools.addButton(createEmptyButton(dbTools.getButtonCount(), “db”));
dock.add(blogTools, DockPanel.NORTH);
dock.add(dbTools, DockPanel.SOUTH);
}
/**
* Método de fábrica. Cria botões a partir de uma posição e o nome do estilo
* que deverá ser atribuÃdo ao botão.
* @param pos
* @param id
* @return
*/
public Button createEmptyButton(int pos, String id){
Button simpleButton = new Button();
simpleButton.setTitle(pos+”");
simpleButton.setStylePrimaryName(id);
simpleButton.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
Window.alert(sender.getTitle());
}
});
return simpleButton;
}
/**
* Método de fábrica. Cria botões a partir de uma imagem e uma posição.
* @param icon
* @param pos
* @return
*/
public PushButton createButton(Image icon, int pos){
PushButton pushButton = new PushButton(icon);
pushButton.setTitle(pos+”");
pushButton.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
Window.alert(sender.getTitle());
}
});
return pushButton;
}
}
[/java]
Agora vejamos o que o firebug nos diz a respeito das toolbars criadas e suas imagens via css e imageBundle.
Como pode se observar com uma única requisição feita através do imageBundle, quatro imagens foram trazidas até o cliente, e podem ser colocadas em cache tranquilamente (O nome “maluco” do arquivo é um número hash). Enquanto isso, para cada imagem setada através de css é feita uma nova requisição ao servidor, consumindo tempo e banda do usuário.
As vantagens do uso de ImageBundle são claras em relação ao carregamento de imagens via CSS. Além disso, uma outra utilidade dos ImageBundle’s que não foi citada no texto é o uso de internacionalização de imagens. Mas esse é assunto para um próximo post. Espero que tenham gostado. A seguir um arquivo zip com o projeto desenvolvido.
One Response to “Utilizando um ImageBundle”
Leave a Reply
You must be logged in to post a comment.
Setembro 9th, 2008 at 06:36:15
Cara, os últimos trabalhos da galera do GWT para fazer com que o código construído seja cada vez menor e mais rápido são impressionantes.
Esse lance mesmo do ImageBundle ficou muito interessane, principalmente pela facilidade de utilizar.
Só a título de curiosidade, o widget que mostrava as medalhas dos países neste última olimpíada utilizou este recurso para mostrar as imagens das medalhas e das bandeiras dos países.