Para quem não conhece existe um projeto do qual participei na elaboração e acho bastante útil pra todo mundo. É o GWT Window Manager o projeto consiste basicamente em usar um gerenciador de janelas para a sua aplicação aumentando ainda mais a sensação de se estar usando um desktop em vez do browser. Nesse post vou explicar o básico de como se usar o GWM como é conhecido no seu projeto.
Primeiramente crie um projeto usando o Project Creator e o Application Creator como explicado em posts anteriores. Em seguida acrescente o gwm.jar ao seu classpath e copie o diretório themes para a pasta public do seu projeto, é nela que se encontram todos os arquivos css e de imagem do gwm. Feito isso, o próximo passo é efetuar a ligação entre a página e esses arquivos. Acrescente as seguintes linhas no head do html da página:
-
<link href="themes/alphacube.css" rel="stylesheet" />
-
<link />
-
<link href="themes/alphacube-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/citrus.css" rel="stylesheet" />
-
<link />
-
<link href="themes/citrus-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/cloudy.css" rel="stylesheet" />
-
<link />
-
<link href="themes/cloudy-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/darkX.css" rel="stylesheet" />
-
<link />
-
<link href="themes/darkX-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/mac.css" rel="stylesheet" />
-
<link />
-
<link href="themes/mac-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/sky.css" rel="stylesheet" />
-
<link />
-
<link href="themes/sky-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/spread.css" rel="stylesheet" />
-
<link />
-
<link href="themes/spread-off.css" rel="stylesheet" />
-
<link />
-
<link href="themes/theme1.css" rel="stylesheet" />
-
<link />
-
<link href="themes/theme1-off.css" rel="stylesheet" />
-
<link />
Agora falta pouco para poder usar o framework :)O seu arquivo de módulo do projeto deve ficar parecido com este:
-
<module>
-
<inherits name="com.google.gwt.user.User"></inherits>
-
<inherits name="org.gwm.GwtWindowManager"></inherits>
-
<entry class="<br.com.gwt.client.GWM"></entry>
-
</module>
Modificando o código que foi gerado pelo application creator ficamos com o entry point da seguinte forma:
-
package br.com.gwt.client;
-
-
import org.gwm.client.GDesktopPane;
-
import org.gwm.client.GInternalFrame;
-
import org.gwm.client.impl.DefaultGDesktopPane;
-
-
import com.google.gwt.core.client.EntryPoint;
-
import com.google.gwt.user.client.ui.RootPanel;
-
import com.google.gwt.user.client.ui.Widget;
-
-
/**
-
* Entry point classes define <code>onModuleLoad()</code>.
-
*/
-
public class GWM implements EntryPoint {
-
-
private GDesktopPane desktop;
-
private static GWM instance;
-
/**
-
* This is the entry point method.
-
*/
-
public void onModuleLoad() {
-
instance = this;
-
desktop = new DefaultGDesktopPane();
-
-
RootPanel.get().add((Widget) desktop);
-
}
-
-
/**
-
* Singleton
-
* @return
-
*/
-
public static GWM getInstance() {
-
return instance;
-
}
-
-
/**
-
* Adicione os seus GInternalFrames ao desktop
-
* @param iframe
-
*/
-
public void addWindow(GInternalFrame iframe) {
-
desktop.addFrame(iframe);
-
iframe.setVisible(true);
-
}
-
}
Agora vejamos alguns detalhes do código:
Primeiramente declaramos que iria ser usado um Desktop, o desktop nada mais é do que um objeto capaz de receber janelas e gerenciá-las. Além disso, implementamos um dos mais usados e simples padrões de projeto um singleton. O Singleton garante que somente uma instancia de um determinado objeto será criado. Como o método onModuleLoad é o primeiro a ser chamado pelo gwt, e somente é executado uma única vez, é bastante adequado inicializar o singleton nesse ponto. No caso de se adicionar construtores ao entryPoint eles devem ser construtores padrão sem argumentos, podendo até mesmo ser privados caso contrário o compilador irá reclamar. Após a execução do onModuleLoad a qualquer momento será possível se obter uma instancia do entryPoint através do método getInstance().
Observem que a inicialização do desktop se dá através da classe DefaultGDesktop o que indica que a classe GDesktop na verdade é uma interface, isso configura um dos vários pontos de extensão do framework. Caso seja necessário implementar um desktop com comportamentos diferentes do original tudo que se tem que fazer após a implementação é alterar esta linha.
Por ultimo, no método onModuleLoad é adicionado esse objeto desktop ao RootPanel, que como já explicado anteriormente, é a página html. Repare aqui que a referência ao desktop não é de um widget, embora a implementação o seja, daí a necessidade do cast.
Agora analisemos o método addWindow(GInternalFrame iframe) ele faz duas coisas:
1. Adiciona o GInternalFrame ao desktop, porém isso não a torna visível;
2. Mostra a janela finalmente. Uma chamada ao método setVisible sem que a janela esteja previamente adicionada a um desktop provocaria uma Exceção em tempo de execução por isso ela só é feita nesse ponto.
Até agora temos uma aplicação com um desktop. Nada além disso, entretanto visualmente já pode-se observado o seguinte:
Entretanto isso não é nem de longe o suficiente para uma aplicação ![]()
Vamos criar pelo menos uma janela e brincar um pouco com ela
Para se criar uma janela que possa ser usada em conjunto com o GDesktop devemos criar uma classe que extenda de DefaultGInternalFrame ou então uma que a implemente, embora eu não recomende a implementação do início por que a DefaultGInternalFrame já possui bastante funcionalidades e sem contar que você pode extendê-la facilmente.
Assim, vejamos, vamos criar uma janela que possa utilizar o método singleton que criamos anteriormente e que tenha alguma utilidade também
ai vai o código:
-
package br.com.gwt.client;
-
-
import org.gwm.client.impl.DefaultGInternalFrame;
-
-
import com.google.gwt.user.client.ui.ChangeListener;
-
import com.google.gwt.user.client.ui.ListBox;
-
import com.google.gwt.user.client.ui.Widget;
-
-
/**
-
* Cria uma janela com um combo box com os temas disponíveis. Ao selecionar um
-
* tema diferente altera o desktop completo.
-
* @author Marcelo Emanoel
-
*
-
*/
-
public class ThemeChanger extends DefaultGInternalFrame {
-
-
private ListBox combo;
-
-
public ThemeChanger() {
-
init();
-
initLayout();
-
attachListeners();
-
}
-
-
/**
-
*Inicializa os componentes da janela
-
*/
-
private void init() {
-
combo = new ListBox();
-
combo.addItem("default");
-
combo.addItem("alphacube");
-
combo.addItem("citrus");
-
combo.addItem("cloudy");
-
combo.addItem("darkX");
-
combo.addItem("mac");
-
combo.addItem("sky");
-
combo.addItem("spread");
-
combo.addItem("theme1");
-
}
-
/**
-
*Inicializa o layout da Janela
-
*/
-
private void initLayout() {
-
setCaption("Seletor de temas");
-
setContent(combo);
-
}
-
/**
-
*Adiciona algum possível listener da janela
-
*/
-
private void attachListeners() {
-
public void onChange(Widget sender) {
-
int selecao = combo.getSelectedIndex();
-
GWM.getInstance().changeTheme(tema);
-
}
-
});
-
}
-
}
Repare que a janela é a mais simples possível, contém apenas um combobox com o nome dos estilos css que foram adicionados no início. No método attachListeners acrescentei um ChangeListener ao combobox de maneira que sempre que ouvesse a mudança de valor fosse possível interceptar essa mudança e reagir de alguma maneira, no caso chamei o método getInstance() que retorna a instancia do singleton de GWM e em seguida o método changeTheme passando o valor do combobox. abaixo segue o código que realiza a mudança de tema:
-
desktop.setTheme(newTheme);
-
}
Simples e direto. No método initLayout() foi alterada a propriedade Caption que nada mais é senão o Título da janela e em seguida o conteudo da janela foi setado para ser o combo box. O método utilizado para isso, setContent() foi sobrecarregado de 3 maneiras:
1. Receber um widget, a que provavelmente será a mais usada nas suas aplicações.
2. Receber uma String, supondo que seja de interesse do usuário adicionar somente texto à janela.
3. Receber uma url, também bastante usada para carregar uma página html dentro da janela em si.
Existem também outros métodos que facilitam bastante a vida, como por exemplo, o bloqueio ou não de propriedades como Maximizable, Minimizable, Draggable, Closable. Permitindo ou bloqueando respectivamente, maximizar, minimizar, arrastar e fechar a janela. Além disso, é possível acrescentar ouvintes à janela de maneira a interceptar os eventos anteriores além de outros permitindo uma reação a cada um deles.
Vamos revisitar agora a classe GWM já que vamos adicionar uma janela ao desktop. O código segue abaixo:
-
package br.com.gwt.client;
-
-
import org.gwm.client.GDesktopPane;
-
import org.gwm.client.GInternalFrame;
-
import org.gwm.client.impl.DefaultGDesktopPane;
-
-
import com.google.gwt.core.client.EntryPoint;
-
import com.google.gwt.user.client.ui.RootPanel;
-
import com.google.gwt.user.client.ui.Widget;
-
-
/**
-
* Entry point classes define <code>onModuleLoad()</code>.
-
*/
-
public class GWM implements EntryPoint {
-
-
private GDesktopPane desktop;
-
private ThemeChanger themeChanger;
-
private static GWM instance;
-
-
/**
-
* This is the entry point method.
-
*/
-
public void onModuleLoad() {
-
-
instance = this;
-
desktop = new DefaultGDesktopPane();
-
-
themeChanger = new ThemeChanger();
-
-
changeTheme("default");
-
addWindow(themeChanger);
-
-
RootPanel.get().add((Widget) desktop);
-
}
-
-
/**
-
* Singleton
-
* @return
-
*/
-
public static GWM getInstance() {
-
return instance;
-
}
-
-
/**
-
* Adicione os seus GInternalFrames ao desktop
-
* @param iframe
-
*/
-
public void addWindow(GInternalFrame iframe) {
-
desktop.addFrame(iframe);
-
iframe.setVisible(true);
-
}
-
-
desktop.setTheme(newTheme);
-
}
-
}
Veja que criamos uma instancia da janela ThemeChanger e a adicionamos ao desktop. Feito isso é só atualizar a página do projeto e finalmente ver a janela em ação.
A janela por default pode ser maximizada, minimizada, fechada e ser arrastada. Aproveitem e brinquem um pouco.
Segue o código implementado no post. Aguardo comentários!
