Foro de elhacker.net

Programación => Java => Mensaje iniciado por: Fran88 en 5 Agosto 2009, 17:33 pm



Título: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 5 Agosto 2009, 17:33 pm
Buenas,
estoy haciendo un proyecto para la uni en el que tengo una clase DibujarNodo que dibuja Nodos de un arbol que contienen: Nombre, texto y una lista de atributos.

Esta clase tiene un metodo paint que quiero reescribir con el objetivo de pintar en un Jpanel todos los nodos del arbol independientemente del tamaño que tenga el arbol, y que si el arbol es muy grande no se solapen en pantalla los nodos ala hora de dibujarlos.

Me comentaron que con un JTree se puede hacer esto, pero me prohiben usarlo, asique tengo que hacerlo yo a pelo dibujandolo sobre un JPanel.

De momento no he hecho mas que las cabeceras y un ejemplo inicial del Pintar:

Código:
public class DibujarNodo extends JPanel
{
    /** */
    private int CoordenadaX;
   
    /** */
    private int CoordenadaY;
   
    /** */
    private int SizeX;
   
    /** */
    private int SizeY;
   
    /** */
    public void Pintar(Graphics g)
    {
    g.drawString("Hola", 10, 10);
    g.drawString((this.getSize().getWidth() + ", " + this.getSize().getHeight()), 20, 20);
    g.drawRect(50, 50, 100, 100);
    g.drawLine(80, 100, 100, 200);
    }

}

el problema q tengo es q representar eso graficamente con un arbol q tenga, 40 hijos y q por ejemplo todos ellos tengan otros 40 hijos, a mano no se puede pintar pq se empezarian a solapar en el panel.
Busco un algoritmo que pueda representar graficamente un arbol donde cada nodo es un por ejemplo un cuadrado que contiene nombre y texto sobre el cuadrado.

Algo similar a esto:
http://www.programacion.com/cursos/jap_data_alg/images/jw-0613-java10113.gif
Digamos que el panel deberia redimensionarse si el arbol se va haciendo mas grande, y el algoritmo debe hacer q no se vayan solapando.

Muchas gracias!


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Danther en 5 Agosto 2009, 18:57 pm
La parte grafica de la programacion es siempre la que peor se me da T.T

En tu caso, ¿no seria mejor que redimensionaras los arboles en si, mas que el jpanel?
Digo, si tengo 1 arbol con 3 hijos, que ocupe todo el panel
Y si tengo 1 arbol con 40, que se hagan mas pequeños para que quepan en el mismo
Puedes hacer que tu aplicacion se ejecute a pantalla completa si quieres, o que empieza con un tamaño bastante grande

Si no, tampoco debe ser muy dificil calcular si cabe en el panel, y si no aumentarle las dimensiones
Pero ni idea si se puede aumentar la dimension aun panel que ya esta creado
Todo es cuestion de que te mires la api, si eso tendra algo como setHeigh/setWidth


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 6 Agosto 2009, 09:36 am
La verdad esque era algo que no me habia planteado, y es una buena idea...aunque no me he puesto manos a la obra por no tener del todo claro la idea, y asi tambien es más dificil, pero seguire buscando ideas y me pondre a ello a ver si sale algo.


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 6 Agosto 2009, 12:19 pm
He encontrado un codigo en Google Code que he pensado quiza me ayude para lo que quiero hacer, agradeceria si alguien me dijera si voy por buen camino...
http://www.google.com/codesearch/p?hl=es&sa=N&cd=19&ct=rc#z6GKVQhaQrg/trunk/vozip/WebContent/applet/web/Nodo.java&q=dibujar%20arbol


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: juancho77 en 7 Agosto 2009, 03:55 am
mm yo calcularia la altura del arbol primero, y empezaria a dibujar desde abajo hacia arriba. Por ejemplo, si la altura(profundidad maxima entre todos los nodos) es 10, y el ultimo nivel tiene 50 hijos, entonces crearia un JPanel de 500 x 1000 ponele. Le asignas a cada nivel 500/10 pixeles y a cada cuadrado (nodo) 1000/50 pixeles.
Luego, vas tomando los nodos desde el ultimo nivel al primero, y dibujandolos de acuerdo a ese tamaño. No se tendrian que solapar de ninguna manera.
No se me ocurre una manera rapida de conectar hijos y padres, pero supongo que se podria hacer con un atributo en la clase Nodo.
Obviamente, el JPanel lo metes adentro de otro, y le pones un JScroll, para que ponele, si mide 1000 pixeles de ancho, te muestre solo 500 y el resto haya que desplazarse. Como en Writer para desplazarse hacia abajo en las paginas..


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: juancho77 en 7 Agosto 2009, 14:13 pm
Se me ocurrieron unas ideitas, mira. Se podría dibujar el árbol desde abajo hacia arriba así:
Dividir primero el panel en x*y, donde x es el número de nodos en el nivel con nodos=max (el nivel con mas nodos), y es la altura del arbol (nodo mas profundo).
Luego haces, para cada nodo del nivel i, dibujarNodo(nodo).
dibujarNodo busca la ubicación del padre en la lista de nodos del nivel i-1. Luego, si por ejemplo el padre esta en la posición 3, esto significa que hay dos nodos antes. Para dibujar el nodo del nivel i cuyo padre esta en i-1 en la posición 3 imaginamos que hay dos nodos antes, y hacemos las cuentas de posición como si estos existieran. Así, el nodo nos va a quedar ubicado debajo del padre. Pero antes de pintarlo, contamos la cantidad de hijos del padre y guardamos en un variable. Ponele que el padre tenga 3 hijos: la variable empieza en -60 y por cada nodo le sumas 60. Entonces, al primer hijo del padre lo pintas en Xpadre-60, al segundo en Xpadre, y al tercero Xpadre+60.
Cuando tenga un rato libre lo voy a tratar de hacer.
Agregame al Msn si te intersa discutirlo.


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 7 Agosto 2009, 18:10 pm
Acabo de leer tus comentarios!! jeje gracias.
Recuerdo que pense en lo de dibujarlo desde abajo pero no profundice pq tenia q dejar la practica para verano!! jejeje
Me pierdo un poco en lo de las posiciones del nodo padre, y como las calculas.
Mi clase recibe un árbol no una lista, supongo q sera cuestion de recorrer el arbol incluso lo mismo asi es mas sencillo pq utilizo un TAD q si no recuerdo mal tiene metodos q te dan el padre y el hijo y la profundidad del arbol, etc...

Ahora mismo ando un poco liado, en cuanto pueda te agrego y hablamos.

Muchas gracias!!


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: juancho77 en 8 Agosto 2009, 00:20 am
jeje bueno estuve pensando unas cosas y llegue a esto.

DESCARGAR (http://www.4shared.com/file/123635686/334393c3/tp_online.html)

nota: no acepto criticas relacionadas con el codigo porque lo escribi rapido y dando soluciones temporales jaja me atajo porque hay muchas variables, mucho despelote, castings donde no deberia, etc. prometo una versión final. ademas, todavia falta que el espacio en x entre nodos sea relativa. la distancia y si es relativa y varia si se agranda o achica la pantalla y cuando se agregan nodos que modifican la altura. Para modificar el arbol deben editar el constructor de la clase dibujo. las clases auxiliares son estructuras de datos que tengo en la pc y que use, todas hechas por mi. Espero sirva de algo jajaj


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: juancho77 en 8 Agosto 2009, 06:44 am
Para que la medida en X sea relativa hay que modificar la linea 86 mas o menos que dice algo asi:

Código
  1. int saved=((TreeNode<Integer>)arbolito.parent(p)).x+(difx*50*(Math.abs(mitad-hijosagregados)));

por esta otra

Código
  1. int saved=((TreeNode<Integer>)arbolito.parent(p)).x+(difx*((TreeNode<Integer>)arbolito.parent(p)).x*2/nodosNivel*(Math.abs(mitad-hijosagregados)));

un saludo  :-*


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 10 Agosto 2009, 17:21 pm
He estado mirando el codigo, la parte de pintar los niveles no la tengo muy clara, si pudieras comentarla seria de gran ayuda.
Gracias


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Amerikano|Cls en 12 Agosto 2009, 04:13 am
Yo tengo que hacer algo similar de tarea, para dibujar un arbol genalógico. Espero terminarla para postearlo obviamente  ;).

salu2


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 27 Agosto 2009, 20:41 pm
Tengo un problema ahora, he seguido la estructura del codigo de juancho77, pero en su lugar estoy pintando sobre un JPanel, el problema es que el usaba el metodo de JFrame "Pack()" para ajustar automaticamente la pantalla ala necesidad del arbol, es decir, si el arbol era mas grande se redimensionaba sola la pantalla gracias a este metodo.

Mi problema es que JPanel q yo sepa no puede usar el metodo Pack() y no conozco de la existencia de uno similar q ajuste al panel.
Sobre todo porque para dibujar en el panel he tenido q poner SetLayout(null) y el metodo "getPreferedSize" no me sirve teoricamente...
Si no pongo ese metodo SetLayout a null teoricamente podria redimensionarse, pero si no me equivoco perderia las coordenadas x e y donde pinto cada nodo...

Hasta ahora lo q he hecho ha sido añadir al final del paintComponent esta linea:
//Altura es la profundidad del arbol, el numero de niveles q tiene...
Código:
panel.setPreferredSize(new Dimension(maxNodos*130,altura*170));

el problema es que la coordenada X se inicializa al principio de cada iteracion asi:
Código:
x=(this.getWidth()/nodosNivel);
//la altura Y se obtiene multiplicando el espacio asignado a cada nivel (alto total de la pantalla dividido numero de niveles)
//por el nivel actual menos 1, para que la raiz nos quede bien arriba.
y=(i-1)*(this.getHeight()/altura);

Al hacer esto ya hay casos en los que no me pinta bien el arbol porque el calculo de la coordenada x depende del tamaño del panel, y como podeis ver en mi codigo, el tamaño del panel depende de maxNodos(nivel del arbol con mas nodos).

Creo que me muerooo, ayudaa!!!! xDDD


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 27 Agosto 2009, 21:02 pm
He actualizado esa linea por esta otra:
//nodosNivel al ejecutar esta linea tiene el valor de los nodos del ultimo nivel...
Código:
panel.setPreferredSize(new Dimension((maxNodos+nodosNivel)*130,(altura+1)*170));

Parece ser q asi funciona, al menos con las 3 pruebas q he hecho, tengo q hacer mas, metiendo mas niveles al arbol pero lo pongo por si alguien me corrige.


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 8 Septiembre 2009, 18:37 pm
Parece ser q el algoritmo inicial falla..no funciona para todos los casos, en cuanto metes 3 niveles el ultimo con muxos hijos se empiezan a solapar...e incluso hay veces q un nodo se sale del panel y no se ve en pantalla.

Alguna idea??

gracias


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Amerikano|Cls en 9 Septiembre 2009, 04:22 am
De aqui al domingo publico el que hice para una tarea... ruegen porque me acuerde que ahora no puedo y quisa todo el trabajo que tengo me haga olvidar, pondre una alarma que me avise  ;D, el metodo en si es recursiivo que recibe la raiz del arbol n-ario y va graficando todos los demas nodos  ;).

salu2


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Fran88 en 13 Septiembre 2009, 17:39 pm
Estamos a domingo y estoy ansioso por ver tu metodo!!  ;D xD


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Amerikano|Cls en 14 Septiembre 2009, 20:16 pm
Bueno lamento la demora pues como todavia ando un poco acosado de tareas solo subire el el src para que lo vean porque no me queda tiempo de explicarlo detelladamente, pero basicamente los dos metodos mas importantes se encuentran en el paquete JTGraph de la misma clase JTGraph.java dibujarArbol() y dibujarNodo().

El primero recibe la raiz del arbol n-ario y va creando BufferedImages como sea necesario segun los hijos que tenga dicho nodo, los cuales son creados en el metodo dibujarNodo, y finalmente estos BufferedImages son unidos en un BufferedImage final que sera el que se pegara en el panel.

Código
  1. public BufferedImage dibujarArbol(nodo raiz,int x,int y)
  2.    {
  3.        if (raiz.esHoja()) return dibujarNodo(raiz);
  4.  
  5.        ArrayList<BufferedImage> imagenes=new ArrayList<BufferedImage>();
  6.        BufferedImage imagenFinal;
  7.        int ancho=0,alto=0;
  8.        for (Object hijo : raiz.getHijos())
  9.        {
  10.            nodo son=(nodo)hijo;
  11.            BufferedImage im=dibujarArbol(son,0,0);
  12.            imagenes.add(im);
  13.            ancho+=im.getWidth()+GAP_X;
  14.  
  15.            if(im.getHeight()>alto) alto=im.getHeight();
  16.        }
  17.        alto+=ALTO_NODO+2*GAP_Y;
  18.        BufferedImage imagenRaiz=dibujarNodo(raiz);
  19.  
  20.        if(ancho<imagenRaiz.getHeight())ancho=imagenRaiz.getHeight();
  21.  
  22.        imagenFinal=new BufferedImage(ancho, alto, BufferedImage.TYPE_INT_RGB);
  23.        imagenFinal.getGraphics().setColor(Color.white);
  24.        imagenFinal.getGraphics().fillRect(0, 0, getWidth(), getHeight());
  25.        Graphics2D g2d=imagenFinal.createGraphics();
  26.  
  27.        g2d.drawImage(imagenRaiz, ancho/2-ANCHO_NODO/2, 0, null);
  28.        int posx=GAP_X;
  29.  
  30.        for (BufferedImage bNodo : imagenes) {
  31.  
  32.            g2d.setColor(Color.RED);
  33.            g2d.setStroke(new BasicStroke(2));
  34.            g2d.drawLine(ancho/2, ALTO_NODO+0, posx+bNodo.getWidth()/2, ALTO_NODO+GAP_Y*2);
  35.            g2d.drawImage(bNodo, posx, ALTO_NODO+2*GAP_Y, this);
  36.            posx+=bNodo.getWidth()+GAP_X;
  37.  
  38.        }
  39.  
  40.        imagenFinal.getGraphics().setColor(Color.black);
  41.        imagenFinal.getGraphics().drawRect(0, 0, getWidth(), getHeight());
  42.        return imagenFinal;
  43.    }
  44.  
  45.    /**
  46.      * netodo para dibujar un solo nodo
  47.      * @param n el nodo a dibujar
  48.      * @return una imagen con le nodo dibujado
  49.      */
  50.    private BufferedImage dibujarNodo(nodo n)
  51.    {
  52.        BufferedImage imagenNodo=new BufferedImage(ANCHO_NODO, ALTO_NODO, BufferedImage.TYPE_INT_RGB);
  53.        Graphics2D g=imagenNodo.createGraphics();
  54.  
  55.  
  56.        g.setColor(Color.CYAN);
  57.        g.fillRect(0, 0, ANCHO_NODO, ALTO_NODO);
  58.  
  59.        BasicStroke bs=new BasicStroke(3);
  60.        g.setStroke(bs);
  61.        g.setColor(Color.BLACK);
  62.        g.drawRect(0, 0, ANCHO_NODO-1, ALTO_NODO-1);
  63.  
  64.        g.setColor(Color.BLUE);
  65.        g.setFont(new Font("Arial", Font.BOLD,20));
  66.        g.drawString(n.toString(), 10, ALTO_NODO/2);
  67.  
  68.        return imagenNodo;
  69.    }
  70.  

Link: http://www.zshare.net/download/65561955ef26ba1f/ (http://www.zshare.net/download/65561955ef26ba1f/)

Salu2 y espero les sirva de algo ;)


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: Amerikano|Cls en 18 Septiembre 2009, 16:30 pm
Alguien lo ha mirado o sigue en las penas???  :-\


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: juancho77 en 18 Septiembre 2009, 22:30 pm
jaja yo lo acabo de ver y me da verguenza la solución que di yo antes.
un abrazo viejo, buen código.


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: kuruchus en 9 Diciembre 2009, 13:46 pm
Tengo yo que hacer algo parecido.

Agradezco el aporte de juancho77 (aunque el link está caído) y de AmeRiK@nO.

Fran88, ¿al final qué código utilizaste?

Gracias


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: efx en 11 Diciembre 2009, 23:23 pm
pues yo entregue un proyecto similar...solo que lo deje a medias
por que los nodos se me enciman...pero los programo en un  Applet...
habia creado un tema para pedir ayuda de como dibujarlo pero al final encontre esta solucion... :rolleyes:

Código
  1. /*Metodo recursivo que dibuja el arbol empezando de la raiz hasta la ultima hoja*/
  2. public void dibujaNodo(Graphics g,int x,int y,NodoA raiz)
  3. {
  4. NodoA aux=raiz;
  5.  
  6. //si la raiz no esta vacia--tiene al menos un elemento
  7. if(aux!=null)
  8. {
  9. g.setColor(new Color(255,228,196));
  10. g.fillOval(x,y,25,25);
  11. g.drawOval(x,y,25,25);//solo dibujamos el nodo raiz en X Y
  12.  
  13. g.setColor(new Color(165,42,42));
  14. g.drawString(aux.getinfo()+"",x+9,y+16);//dibujamos la info de raiz en medio del circulo
  15.  
  16. /*si hay algo en la izquierda*/
  17. if(aux.getizq()!=null)
  18. {
  19. //Imprimir linea de x,y a x-TAM, y+TAM
  20.  
  21. g.drawLine(x+5,y+22,x-35,y+50);
  22. /*se llama el metodo pero ahora con nuevas coordenadas y otro nodo*/
  23. dibujaNodo(g,x-50,y+50,aux.getizq());
  24.  
  25. }
  26.  
  27. /*si hay algo en la derecha*/
  28. if(aux.getder()!=null)
  29. {
  30. //Imprimir linea de x,y a x+TAM, y+TAM
  31. g.drawLine(x+20,y+22,x+55,y+50);
  32. /*se llama el metodo pero ahora con nuevas coordenadas y otro nodo*/
  33. dibujaNodo(g,x+50,y+50,aux.getder());
  34.  
  35. }
  36. }
  37.  
  38. }

ya solo en el metodo paint

Código
  1. public void paint(Graphics g) {
  2.  
  3. g.drawImage(titulo,120,0,242,93,this);
  4. /*Solo acomodamos los componentes*/
  5. txtDato.setBounds(420,30,30,20);
  6. insertar.setBounds(440,60,60,20);
  7. eliminar.setBounds(370,60,60,20);
  8.  
  9. rEn.setBounds(20,95,120,20);
  10. rPos.setBounds(160,95,120,20);
  11. rPre.setBounds(310,95,120,20);
  12.  
  13. h.setBounds(168,125,100,20);
  14.  
  15. dibujaNodo(g,200,150,A.getraiz());
  16.  
  17.  
  18. }

bueno pues salu2 a todos  ;D


Título: Re: Dibujar un árbol en Java sin usar JTree
Publicado por: kuruchus en 6 Enero 2010, 14:32 pm
Gracias por la ayuda. Terminé el proyecto y cuando se acabe el curso subiré el código aquí.
Un saludo