Modelo para arvore

19 respostas
D

Preciso criar um JTreeModel que diferencia as seguintes situiações:

- DiretórioPaiDeTodos [pode existir mais de um]

    - DiretórioFilho [pode existir varios]

         - DiretórioNeto [idem]

             - DiretórioFilhoNeto [idem]

                   +DiretórioFixo1
                   +DiretórioFixo2
                   +DiretórioFixo3
                   +DiretórioFixo4

onde cada DiretórioFilhoNeto possui fixamente os “DiretórioFixo” …

Eu vou ter que construir isto tudo a partir de uma classe… Veja:

public class DiretórioPaiDeTodos{ ArrayList<DiretórioFilho> filhos; }

[…]

public class DiretórioFilho{ ArrayList<DiretórioFilhoNeto> netos; }

e assim por diante, até chegar no DiretórioFilhoNeto, que seria mais ou menos assim:

public class DiretórioFilhoNeto{ ArrayList<DiretórioFixo1> fixo1; ArrayList<DiretórioFixo2> fixo2; ArrayList<DiretórioFixo3> fixo3; ArrayList<DiretórioFixo4> fixo4; }

alguem ajuda? Ja vi outros modelos, mas era um jTree muito simples, e cada pasta representa uma classe …
Estou perdido, alguem me ajuda?

19 Respostas

V

Por que você tem classes diferentes para cada filho?

O ideal pra esses casos é usar o padrão Composite. Pesquise sobre ele.

D

ViniGodoy:
Por que você tem classes diferentes para cada filho?

O ideal pra esses casos é usar o padrão Composite. Pesquise sobre ele.

por que é justamente essas classes que vão organizar a JTree.

É… vou fazer isso.
=/

V

Sim, mas essas classes tem características diferentes?

Pq um diretório com filhos dentro geralmente é apenas outro diretório. Não precisa de 2 classes para representa-lo.

D

ViniGodoy:
Sim, mas essas classes tem características diferentes?

Pq um diretório com filhos dentro geralmente é apenas outro diretório. Não precisa de 2 classes para representa-lo.

Cada classe tem um arrayList da outra classe…

Veja:

V

Pois é, e pq não pode ser?

public class Diretorio { private String nome; private List&lt;Diretorio&gt; filhos = new ArrayList&lt;Diretorio&gt;(); }

Se os filhos não tem nada de diferente dos pais em sua estrutura, então use uma classe só.

D

Estou confuso.

O modelo da aplicação são classes diferentes. Voce esta dizendo que na JTREE pode ser a mesma Classe?
É por que este assunto é sobre o meu TCC, e nao queria especificar muito… Por isso usei o exemplo ai dos “Diretório”

V

Ah tá, nesse caso vai parecer com o JTree do tópico:

D

então eu baixei o sampleTree e analisei, mas não consegui encaixar no meu problema…

Existe algum outro exemplo de uma JTree mais complexa?

V

Basicamente vc vai ter que modificar três métodos.

Veja para o exemplo que vc mesmo deu:

/** 
     * Com esse método, o Java quem é o objeto que está num determinado índice 
     * do pai. Cada nó de uma árvore pode ser encarado como uma lista. Sendo o 
     * pai a lista e o índice um dos filhos. 
     *  
     * @param parent 
     *            É o pai, que tem os filhos. 
     *            Índice do filho. 
     */  
    public Object getChild(Object parent, int index) {  
        if (parent == raiz) // É o nó principal?  
            return diretorios.get(index);
  
        if (parent instanceof Diretorio)
            return ((Diretorio) parent).getFilhos().get(index);  

        if (parent instanceof DiretorioFilho)
            return ((DiretorioFilho) parent).getNetos().get(index);  

        if (parent instanceof DiretorioNeto)
            return ((DiretorioNeto) parent).getFilhosNetos().get(index);  

        if (parent instanceof DiretorioFilhoNeto)
            return ((DiretorioFilhoNeto) parent).getFixos().get(index);  
  
        // Se o pai não é nenhum desses. Melhor dar erro.  
        throw new IllegalArgumentException("Invalid parent class"  
                + parent.getClass().getSimpleName());  
    }  
  
    /** 
     * Retornamos quantos filhos um pai tem. No caso de um livro, é a contagem 
     * de autores. No caso da lista de livros, é a quantidade de livros. 
     */  
    public int getChildCount(Object parent) {  
        if (parent == raiz) // É o nó principal?  
            return diretorios.size();
  
        if (parent instanceof Diretorio)
            return ((Diretorio) parent).getFilhos().size();

        if (parent instanceof DiretorioFilho)
            return ((DiretorioFilho) parent).getNetos().size();

        if (parent instanceof DiretorioNeto)
            return ((DiretorioNeto) parent).getFilhosNetos().size();

        if (parent instanceof DiretorioFilhoNeto)
            return ((DiretorioFilhoNeto) parent).getFixos().size();
  
        // Se o pai não é nenhum desses. Melhor dar erro.  
        throw new IllegalArgumentException("Invalid parent class"  
                + parent.getClass().getSimpleName());  
    }

Os outros métodos do model seguem a mesma lógica.

D

mas e os métodos para adicionar os diretórios e subdiretórios ?

V

Você altera o model e lança um fireTreePathChanged.

Geralmente vc faz assim:

  1. O usuário clica no nó onde quer inserir o subdiretório;
  2. O usuário abre um menu popup e clica em adicionar. Nesse caso, vc já sabe qual é o nó que terá que ser o pai.
  3. O usuário clica em adicionar no seu menu. Vc adiciona o nó no diretório selecionado (na classe) e lança o evento informando que a JTreeMudou (a classe AbstractTreeModel do post que indiquei tem implementado o fire para o evento).

Se vc habilitar edição no seu JTree, você terá que implementar o método valueForPathChanged. Outra forma simples é o menu ter uma opção “editar” que abre um JOptionPane pedindo para alterar o texto do nó (isso evita de ter que lidar com esse método).

D

vc quase decifrou por completo a operação…
vai ser assim ó…

Quando o cara clicar com o botao direito emcima do diretorio pai, vai aparecer um popup falando:

Cadastrar diretório filho.

Quando clicar no diretório filho:

Cadastrar diretório neto

… e assim até chegar no “Miolo” da coisa, onde ele vai cadastrar “paginas” ou “documentos” (exemplo)

D

a cada pasta, adicionar nova pasta… Até chegar na ultima pasta que seria adiicionar arquivo…

e se clicar no arquivo abre o mesmo para edição.

É impossível (estou pensando) fazer isto sem um model proprio… Mas não estou conseguindo enxergar como fazer. Me ajuda por favor.

Tipo no seu exemplo só tem Livro… mas imagine o seguinte:

Biblioteca possui varias Estantes

Estantes possuem prateleiras,
prateleiras possuem livros

assim:

- biblioteca1
       -Estante11
             -Prateleira111
                   *Livro1
                    *Livro2
              -Prateleira112
                    *Livro3
        -Estante12
                +Prateleira121
                +Prateleira122

   +biblioteca2
   +biblioteca3

clicou em cima de uma Biblioteca, criar Estante…
Clicou em cima de esstante -> Criar prateleira
clicou em cima de prateleira -> criar Livro

tipo assim!
Me ajuda?

D

Por favor, veja se a lógica (seguindo o exemplo a cima) está correta:

private String raiz = "Biblioteca";

  //supondo que são tres tipos de objetos finais que o modelo irá exibir: são eles
  private List<Livro> livros;  
  private List<Caderno> cadernos;   
  private List<Agenda> agendas;  

 //agora o miolo aqui não sei, mas de acordo com o trecho de código que vc me mostrou ficaria algo do tipo assim:
  
public Object getChild(Object parent, int index) {  
        if (parent == raiz) // É o nó principal?  
            return diretorios.get(index);
  
        if (parent instanceof Estante)
            return ((Estante) parent).getFilhos().get(index);  

        if (parent instanceof Prateleira)
            return ((Prateleira) parent).getNetos().get(index);  

       /* Este resto não precisa neste exemplo 
        if (parent instanceof DiretorioNeto)
            return ((DiretorioNeto) parent).getFilhosNetos().get(index);  

        if (parent instanceof DiretorioFilhoNeto)
            return ((DiretorioFilhoNeto) parent).getFixos().get(index);  
  
        */

        // Se o pai não é nenhum desses. Melhor dar erro.  
        throw new IllegalArgumentException("Invalid parent class"  
                + parent.getClass().getSimpleName());  
    }  
  
 
/* E esses métodos? getFilhos ? getNetos ? getFilhosNetos? De onde surgiram? Da minha própria classe?
  Se for então o correto deveria ser:
     ((Estante) parente).getPrateleiras()
     
*/

    public int getChildCount(Object parent) {  
        if (parent == raiz) // É o nó principal?  
            return diretorios.size();
  
        if (parent instanceof Estante)
            return ((Estante) parent).getFilhos().size();

        if (parent instanceof Prateleira)
            return ((Prateleira) parent).getNetos().size();


       /* Nao precisa [...]
        if (parent instanceof DiretorioNeto)
            return ((DiretorioNeto) parent).getFilhosNetos().size();

        if (parent instanceof DiretorioFilhoNeto)
            return ((DiretorioFilhoNeto) parent).getFixos().size();
       */

        throw new IllegalArgumentException("Invalid parent class"  
                + parent.getClass().getSimpleName());  
    }  

    public int getIndexOfChild(Object parent, Object child) {
		if (parent == raiz)
			return livros.indexOf(child);
		if (parent instanceof Estante)
			return ((Estante) parent).getPrateleiras().indexOf(child);
		if (parent instanceof Prateleira)
                        //isto não faz sentida caso possa ter livros, agendas e cadernos...
                        //então estou pensando que cada tipo de "filho" deve estar em um diretório que identifca seu tipo?
                        //exemplo: todos os livros ficam dentro de outro dir "Livros" e o mesmo para "Cadernos" e "Agendas" ?
			return ((Prateleira) parent).getLivros().indexOf(child);
		return 0;
	}


	public Object getRoot() {
		return raiz;
	}


	public boolean isLeaf(Object node) {
		return node instanceof Autor;
                //quem que ficaria aqui? livro caderno ou agenda?
	}

	public void valueForPathChanged(TreePath path, Object newValue) {
		// Com esse método, a tree avisa que um objeto mudou.
		// Editem se quiserem que um nó seja editável
	}

	// Esses dois métodos abaixo poderiam ir para classe abstrata
	public void removeTreeModelListener(TreeModelListener l) {
		listeners.remove(l);
	}

	public void addTreeModelListener(TreeModelListener l) {
		listeners.add(l);
	}

       /*aqui nao deveria ter métodos do tipo:
           addBiblioteca(String nome){}
           addEstante(String nome,Biblioteca tal){}
           addPrateleira(String nome,Estante tal){}
           addLivro(Livro l);
           addCaderno(Caderno n);
           addAgenda(Agenda l);
       */
V

Poste suas classes de negócio, como estão organizadas. Não são elas que tem as listas das classes que vc deixou aí no model?

D

As classes estão compactadas neste arquivo.
http://dl.dropbox.com/u/15625458/logica.rar

Abraços!

V

O caminho é mais ou menos esse mesmo. Só o nome dos “gets” das listas nas suas classes deve mudar um pouco:
Provavelmente o “getFilhos” da estante será substituido por um “getPrateleiras”.

A prateleira possivelmente terá apenas 3 nós. E você deverá retornar Caderno, Agenda ou Livro, dependendo do tipo. Esses sim, terão os nós dos cadernos, agendas ou livros.

E o exemplo que passei foi com 4 ou 5 níveis, baseado naquela estrutura que vc postou no início do tópico.
Cada instanceof daqueles representa um nível diferente.

Pense no que os métodos estão retornando.

No getChild a tree te passa um objeto pai, e pede o filho do índice correspondente (é o que o seu model deve retornar).
No getChildCount a tree te passa um objeto pai, e pergunta para o model quantos filhos quele pai tem.
No getIndexOfChild, a tree te passa um pai e um filho, e pede para vc retornar o índice daquele filho naquele pai.
No isLeaf, a tree te passa um objeto, e vc precisa retornar true se ele for uma folha (sem filhos).

D

Ok, então estava no caminho certo… Achei que estava errado, pois vc pediu pra ver as classes da lógica :stuck_out_tongue:
Vou continuar fazendo, depois posto o resultado.

Obrigado pela sua ajuda.
Estaria perdido sem vc.

Obrigado mesmo.

D

Pode olhar para mim?

http://dl.dropbox.com/u/15625458/TryTree.rar

Obrigado e Abraços

Criado 3 de maio de 2011
Ultima resposta 8 de mai. de 2011
Respostas 19
Participantes 2