Como impressionar seus amigos com Java
Por Thadeu Russo em 05/12/06Olá, já estou a algum tempo na Caelum mas só agora estreando no blog e, para compensar a demora, resolvi fazer um pouco diferente. O título deve estar chamando a atenção e antes de colocar o assunto de verdade (está bem, sei que estou valorizando um pouco), vou apenas lembrar da pessoa que me mostrou o assunto e da que me sugeriu colocar no blog. Ricardo e Paulo. Pronto, direto ao assunto.
Certamente muitos desenvolvedores Java já passaram pelo problema de ter de mostrar alguns recursos interessantes da plataforma. Certamente o HelloWorld não é um grande atrativo. Talvez demonstrar como é fácil fazer relacionamentos com tabelas associativas e chaves compostas através do Hibernate ajude bastante, mas ainda falta certo apelo visual.
Existe uma API feita em Java de livre uso, chamada Prefuse que utiliza-se do Java 2D para tornar simples tarefas complicadas visualmente, como por exemplo, renderizar grafos de maneira visualmente agradável e ainda por cima animada, permitindo inclusive uma interação do usuário através de drag-and-drop.
Uma aplicação mais prática e um tanto quanto útil, é a representação do relacionamento de tabelas ou mesmo de objetos, quando você precisa navegar entre uma grande quantidade de informações e quer uma maneira mais rápida em vez de pular de página em página. A idéia deste post é apenas fazer a introdução ao prefuse, sem entrar em muitos detalhes da API.
A prova de que a prefuse é algo extremamente interessante e que seus amigos ficarão impressionados está aqui. Esse link vai iniciar uma aplicação java web start com uma pequena demonstração que escrevi, mostrando visualmente o relacionamento das fronteiras dos estados do Brasil.
O código que foi necessário para gerar este exemplo segue abaixo:
/**
* @author Thadeu Russo
*
*/
public class Visualizacao {
/** Display onde será desenhada a visualização */
private Display display;
/** Lista de actions relacionadas ao layout */
private ActionList layout;
/** Lista de actions relacionada as cores */
private ActionList color;
/** renderizador dos labels */
private LabelRenderer labelRenderer;
/**
* Carrega as informações que estao no
* arquivo sourceFile para um novo grafo
* @param sourceFile
* @return graph
* @throws DataIOException no caso de
* problemas com a leitura dos dados
* */
private Graph loadGraph(String sourceFile) throws DataIOException{
return new GraphMLReader().readGraph(sourceFile);
}
/**
* Este método retorna o display para a visualization informada
* @return display
* @throws DataIOException
* */
private Display getDisplay() throws DataIOException {
Visualization visualization = this.buildVisualization(
this.loadGraph("data/brasil.xml")
);
/* troquei a visualização? */
if (this.display == null || !this.display.getVisualization().equals(visualization)) {
this.display = new Display(visualization);
this.display.setSize(720, 500);
this.display.addControlListener(new DragControl());
this.display.addControlListener(new PanControl());
this.display.addControlListener(new ZoomControl());
this.display.addControlListener(new WheelZoomControl());
this.display.pan(200, 350);
this.display.setForeground(Color.GRAY);
this.display.setBackground(Color.WHITE);
}
return this.display;
}
/**
* Recupera as actions relacionadas ao layout
* @return ActionList relacionados ao layout
* */
private ActionList getLayout() {
if (this.layout == null) {
this.layout = new ActionList(Activity.INFINITY);
this.layout.add(new ForceDirectedLayout("graph"));
this.layout.add(new RepaintAction());
}
return this.layout;
}
/**
* Recupera a configuração de cores e actions relacionadas a esta
* @return action list
* */
private ActionList getColor(){
if (this.color == null) {
DataColorAction fill = new DataColorAction("graph.nodes", "region",
Constants.NOMINAL, VisualItem.FILLCOLOR, this
.getColorPalette());
ColorAction text = new ColorAction("graph.nodes",
VisualItem.TEXTCOLOR, ColorLib.gray(0));
ColorAction edges = new ColorAction("graph.edges",
VisualItem.STROKECOLOR, ColorLib.gray(200));
this.color = new ActionList();
color.add(fill);
color.add(text);
color.add(edges);
}
return this.color;
}
/**
* Monta a visualização a ser mostrada no display
* @param graph O grafo a ser renderizado
* @return visualization
* */
private Visualization buildVisualization(Graph graph){
Visualization visualization = new Visualization();
visualization.add("graph", graph);
visualization.setRendererFactory(
new DefaultRendererFactory(this.getLabelRenderer())
);
visualization.putAction("color", this.getColor());
visualization.putAction("layout", this.getLayout());
visualization.run("color");
visualization.run("layout");
return visualization;
}
/**
* Recupera o renderizador de rótulos (labels)
* @return label renderer
* */
private LabelRenderer getLabelRenderer() {
if (this.labelRenderer == null) {
this.labelRenderer = new LabelRenderer("state");
this.labelRenderer.setRoundedCorner(8, 8);
}
return this.labelRenderer;
}
/**
* Recupera a paleta de cores a ser usada na renderização
* @return paleta de cores
* */
private int [] getColorPalette(){
return new int[] { ColorLib.rgb(255, 128, 128),
ColorLib.rgb(255, 128, 64), ColorLib.rgb(176, 176, 100),
ColorLib.rgb(100, 255, 64), ColorLib.rgb(128, 255, 255) };
}
public static void main(String[] args) throws DataIOException {
Visualizacao visualizacao = new Visualizacao();
JFrame frame = new JFrame("Grafo do Mapa do Brasil por Regiões");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(visualizacao.getDisplay());
frame.pack();
frame.setVisible(true);
}
}
Aqui, a informação para gerar o grafo apresentado é lida de um XML. Poderia ser muito bem carregada a partir de um banco de dados (interessante ler o metadata do banco para gerar relacionamento entre tabelas, não?). O código acima serve de boa base para você fazer sua própria aplicação. Creio que o prefuse seja uma opção bastante interessante em vez de usar tecnologias de visualização como Flash, onde você ainda teria o trabalho de fazer toda a integração, em vez de diretamente implementar listeners java.
E vocês, que APIs consideram interessantes para demonstrar o poder e em especial a simplicidade do Java?
Essa API é realmente muito boa, participo de um projeto no qual montamos a hierarquia de uma rede de computadores com o prefuse. No proprio vem com uns exemplos muito bons.
Alberto
Comment by Alberto Luiz — December 5, 2006 @ 5:31 am
Caramba, muito legal isso ai hein…
bacana, parabéns.
Comment by Luiz Aguiar — December 5, 2006 @ 10:39 am
Não conhecia essa API, muito legal esse post. Parabéns!
Comment by ASOBrasil — December 6, 2006 @ 9:02 am
Legal, muito bom.
Para mostrar o poder do Java Desktop eu falo pra pessoa rodar o demo “SwingSet2″ que está dentro do diretório “demo” do JDK.
cd C:\jdk\demo\jfc\SwingSet2
java -jar SwingSet2.jar
Comment by Fernando Boaglio — December 12, 2006 @ 5:58 am
Citei este seu texto no meu blog, mas não sei se o trackback funcionou como o esperado.
De qualquer maneira, parabéns pelo post!
Comment by Ivan — December 12, 2006 @ 10:24 am
Fico contente que gostaram do post
Espero estar mais tranquilo no ano que vem para escrever, pois me surgiram idéias muito legais e gostaria de compartilhas.
[]’s a todos.
Comment by Thadeu Russo — December 12, 2006 @ 11:03 am
Você poderia postar o seu XML que você usou no seu exemplo? Estou tentando reproduzir seu exemplo aqui, mas não tenho o XML para testar
Comment by José Henrique — December 13, 2006 @ 10:07 am
Estou tentando rodar o exemplo postado acima, mas não estou conseguindo, o que é necessário para rodar? Tb peguei o codigo do prefuse no site http://www.prefuse.org e não consigo abrir no netbeans como faço?
Comment by Jean — June 21, 2007 @ 1:02 pm
Quando vc faz o download do site do prefuse, precisa compilar e gerar o jar. Coloque o jar no classpath e depois, eh so alegria
Comment by Thadeu — June 21, 2007 @ 1:09 pm
Também estou fazendo algumas pesquisas sobre o Prefuse mas estou com dificuldades em compílá-lo no NetBeans 5.5. Poderia me dar alguma dica?
Se possível, gostaria de receber também o arquivo XML do teste acima.
Agradeço.
Comment by Wilma — July 8, 2007 @ 3:03 pm
Olá
Gostaria de receber o XML do exemplo acima.
[]’s
Comment by Daniela — September 21, 2007 @ 10:06 am
Olá, vc é massa mesmo heim….
gostaria de uma dica, sobre grafo!!!!
Não consigo validar um código que faça um grafo de arvore geradora
de percurso minímo, pode me ajudar?
Comment by Fernando — October 7, 2007 @ 1:35 pm
Belo trabalho Thadeu
Já estou com um monte de idéias para a utilização do prefuse (no site existe muita coisa também.
Parabéns mais uma vez
(Se possível também gostaria de obter o arquivo xml que Você usou. Pode ser?)
Abraços
Comment by Oswaldo Castro — October 21, 2007 @ 6:29 am
Ola Oswaldo, teria como me pedir isso por email? thadeu.russo at caelum.com.br ?
Comment by Thadeu — October 22, 2007 @ 7:47 am
Belo post Tadheu, entretando hoje o site do prefuse não dispõe seus arquivos para download.
Você poderia me passar eles?
Hoje, você usaria prefuse ou flex para construções desses componentes complexos como árvores,grafos..?
Comment by Antonio Lazaro — April 30, 2008 @ 1:37 pm
Link para o JNLP está quebrado =(
Comment by Filipe Kovalski — February 18, 2009 @ 9:22 am
Oi Filipe, corrigido.. Obrigado pelo aviso!
Comment by Thadeu — February 20, 2009 @ 4:19 am
Quero testar, mas preciso do arquivo XML, tem como postar?
Comment by alberto — July 12, 2009 @ 3:44 am