Como impressionar seus amigos com Java

Olá, 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.

Veja abaixo o código para criar uma aplicação mostrando visualmente o relacionamento das fronteiras dos estados do Brasil.

/**
 * @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?

Tags:

20 Comentários

  1. Alberto Luiz 05/12/2006 at 05:31 #

    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

  2. Luiz Aguiar 05/12/2006 at 10:39 #

    Caramba, muito legal isso ai hein… 🙂
    bacana, parabéns.

  3. ASOBrasil 06/12/2006 at 09:02 #

    Não conhecia essa API, muito legal esse post. Parabéns!

  4. Fernando Boaglio 12/12/2006 at 05:58 #

    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

  5. Ivan 12/12/2006 at 10:24 #

    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!

  6. Thadeu Russo 12/12/2006 at 11:03 #

    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.

  7. José Henrique 13/12/2006 at 10:07 #

    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 🙁

  8. Jean 21/06/2007 at 13:02 #

    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?

  9. Thadeu 21/06/2007 at 13:09 #

    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 🙂

  10. Wilma 08/07/2007 at 15:03 #

    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.

  11. Daniela 21/09/2007 at 10:06 #

    Olá
    Gostaria de receber o XML do exemplo acima.
    []’s

  12. Fernando 07/10/2007 at 13:35 #

    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?

  13. Oswaldo Castro 21/10/2007 at 06:29 #

    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

  14. Thadeu 22/10/2007 at 07:47 #

    Ola Oswaldo, teria como me pedir isso por email? thadeu.russo at caelum.com.br ?

  15. Antonio Lazaro 30/04/2008 at 13:37 #

    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..?

  16. Filipe Kovalski 18/02/2009 at 09:22 #

    Link para o JNLP está quebrado =(

  17. Thadeu 20/02/2009 at 04:19 #

    Oi Filipe, corrigido.. Obrigado pelo aviso!

  18. alberto 12/07/2009 at 03:44 #

    Quero testar, mas preciso do arquivo XML, tem como postar?

  19. Well Fernandes 10/08/2015 at 19:46 #

    Olá Thadeu.
    Tudo certo?

    Gostaria de saber se você ainda tem
    o arquivo XML utilizado nesse exemplo?

    Poderia me enviar por email, se possível?
    Desde já, muito obrigado.

  20. Karina 14/04/2016 at 16:03 #

    Olá Thadeu,

    Seria possível me enviar o arquivo brasil.xml utilizado nesse exemplo?

    Obrigada (=

Deixe uma resposta