/*
En este codigo se muestra el uso basico de nodos.
*/
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
/**
*
* @author Rafael Angel Montero Fernández.
*/
public class Nodos_y_listas
{
public static void main(String args[])
{
Panel_de_control frmPanel=new Panel_de_control();
frmPanel.show();
}//Main
}
class ListaEnlazada
{
//permite crear un arbol de nodos o red de nodos.
public Nodo_Rafa nodos=null, nodo_recorrido=null;//Son publicas para poderse heredar.
public String getTodos_los_nodos()
{
//Forma de recorrer todos los nodos y devolver los datos.
nodo_recorrido=nodos;
String respuesta="";
while(nodo_recorrido!=null)
{
respuesta+=nodo_recorrido.getSiguiente().getNombre() + "\n";
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
nodo_recorrido=null;
return respuesta;
}//get
@SuppressWarnings("unchecked")
public DefaultListModel<String> getLista_de_items()
{
//Forma de recorrer todos los nodos y devolver los datos.
nodo_recorrido=nodos;
DefaultListModel<String> respuesta=new DefaultListModel();
while(nodo_recorrido!=null)
{
respuesta.addElement( nodo_recorrido.getNombre());//Forma correcta.
//Asi da errores graves porque en while(nodo_recorrido!=null) se comprueva que nodo_recorrido no sea nulo, mientras que aqui pasa de una vez al siguiente sin comprobarlo nodo_recorrido.getSiguiente().getNombre().
//respuesta.addElement( nodo_recorrido.getSiguiente().getNombre());
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
return respuesta;
}//get
//El metodo buscar para evitar crear codigo extra en otra parte del programa es mejor que devuelva el objeto entero si se encuentra. Y si no entonces, un null.
//A mi criterio no es correcto unsar un booleano.
public Nodo_Rafa buscar_nodo(String nombre_a_buscar)
{
//boolean si_esta=false;
nodo_recorrido=nodos;
String respuesta="";
while(nodo_recorrido!=null)
{
if(nodo_recorrido.getNombre().equalsIgnoreCase(nombre_a_buscar)==true)
{
//System.out.println(nodo_recorrido.getNombre());
//Se puede usar equals para diferenciar entre mayusculas y minusculas.
//si_esta=true;
//break;//Una vez que se ha encontrado entonces se rompe el ciclo.
return nodo_recorrido;
}//if
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
return null;//si_esta;
}//buscar_nodo
///////////////////////////////////////////////////////////////////////////////
//Funciones de una lista enlazada.
public void agregar_al_final(String nuevo_nombre, int numero)
{
//No se esta usando nuevo_nombre
Nodo_Rafa nuevo_nodo_local=new Nodo_Rafa(nuevo_nombre,numero, null);
if(nodos==null)
{
nodos=nuevo_nodo_local;
}//if
else
{
nodo_recorrido= nodos;
while(nodo_recorrido.getSiguiente()!=null)
{
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
nodo_recorrido.setSiguiente(nuevo_nodo_local);//Si no es asi entonces, va dentro del while.
}//else
}//agregar_al_final
public void imprimir_contenido(String nuevo_nombre)
{
JOptionPane.showMessageDialog(null, this.getTodos_los_nodos());
}//imprimir_contenido
public boolean eliminar(String nombre_a_buscar)
{
if(nodos!=null)
{
if(nodo_recorrido.getNombre().equalsIgnoreCase(nombre_a_buscar)==true)
{
nodos=nodos.getSiguiente();
return true;//Ha sido eliminado.
}//if
else
{
nodo_recorrido= nodos;
while(nodo_recorrido.getSiguiente()!=null)
{
if(nodo_recorrido.getSiguiente().getNombre().equalsIgnoreCase(nombre_a_buscar)==true)
{
nodo_recorrido.setSiguiente(nodo_recorrido.getSiguiente().getSiguiente());
return true;//se ha eliminado un nodo.
}//if
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
}//else
}//if
return false;//No se ha encontrado ningun nodo con el numero buscado.
}//agregar_al_final
}//end class ListaEnlazada
///////////////////////////////////////////////////////////////////////////////
class Nodo_Rafa
{
//Permite crear nodos. Desde la clase de Lista enlazada.
private int data=0;
private String nombre="";
public void setNombre(String nuevo_nombre)
{
this.nombre=nuevo_nombre;
}//set
public String getNombre()
{
return this.nombre;
}//get
private Nodo_Rafa siguiente_nodo=null;
public Nodo_Rafa(String nuevo_nombre,int numero, Nodo_Rafa nuevo_nodo)
{
this.data=numero;
this.siguiente_nodo=nuevo_nodo;
setNombre(nuevo_nombre);
}//Constructor
public Nodo_Rafa getSiguiente()
{
return this.siguiente_nodo;
}//get nodo
public void setSiguiente(Nodo_Rafa nuevo_nodo)
{
this.siguiente_nodo=nuevo_nodo;
}//set
public int getNumero()
{
return this.data;
}//get
}//Nodo_Rafa
////////////////////////////////////////////////////////////////////////////////
//Este nuevo class es un desendiente del class ListaEnlazada.
//Permite administrar mejor los nodos por medio de un nodo fantasma.
class Lista_enlazada_con_un_nodo_fantasma extends ListaEnlazada
{
//La declaracion de variables del objeto o class que corresponde al nodo (Nodo_Rafa) no es necesaria porque se hereda, para ello se hacen las variables del padre publicas.
public Lista_enlazada_con_un_nodo_fantasma()
{
nodos=new Nodo_Rafa("",0,null);//Se ha creado el nodo fantasma.
}//Constructor
@Override
public String getTodos_los_nodos()
{
//Forma de recorrer todos los nodos y devolver los datos.
nodo_recorrido=nodos;
String respuesta="";
while(nodo_recorrido!=null)
{
respuesta+=nodo_recorrido.getSiguiente().getNombre() + "\n";
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
return respuesta;
}//get
@Override
public DefaultListModel<String> getLista_de_items()
{
//Forma de recorrer todos los nodos y devolver los datos.
nodo_recorrido=nodos;
int x=0;
@SuppressWarnings("unchecked")
DefaultListModel<String> respuesta=new DefaultListModel();
while(nodo_recorrido!=null)
{
respuesta.addElement(nodo_recorrido.getNombre() );
nodo_recorrido=nodo_recorrido.getSiguiente();
System.out.println(respuesta.getElementAt(x));
x++;
}//while
return respuesta;
}//get
@Override
public Nodo_Rafa buscar_nodo(String nombre_a_buscar)
{
//boolean si_esta=false;
nodo_recorrido=nodos;
String respuesta="";
while(nodo_recorrido!=null)
{
if(nodo_recorrido.getNombre().equalsIgnoreCase(nombre_a_buscar)==true)
{
//Se puede usar equals para diferenciar entre mayusculas y minusculas.
//si_esta=true;
//break;//Una vez que se ha encontrado entonces se rompe el ciclo.
return nodo_recorrido;
}//if
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
return null;//si_esta;
}//buscar_nodo
//Funciones de una lista enlazada.
@Override
public void agregar_al_final(String nuevo_nombre, int numero)
{
//No se esta usando nuevo_nombre
Nodo_Rafa nuevo_nodo_local=new Nodo_Rafa(nuevo_nombre,numero, null);
nodo_recorrido=nodos;
while(nodo_recorrido.getSiguiente()!=null)
{
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
nodo_recorrido.setSiguiente(nuevo_nodo_local);//Si no es asi entonces, va dentro del while.
nodos=nodo_recorrido;
//Tambien se puede usar una variable del objeto para mantener la informacion del ultimo elemento agregado y asi no usar un bucle. Pero yo mejor me quedo aqui porque eso no esta muy claro para mi.
}//agregar_al_final
@Override
public void imprimir_contenido(String nuevo_nombre)
{
JOptionPane.showMessageDialog(null, this.getTodos_los_nodos());
}//imprimir_contenido
@Override
public boolean eliminar(String nombre_a_buscar)
{
nodo_recorrido= nodos;
while(nodo_recorrido.getSiguiente()!=null)
{
if(nodo_recorrido.getSiguiente().getNombre().equalsIgnoreCase(nombre_a_buscar)==true)
{
nodo_recorrido.setSiguiente(nodo_recorrido.getSiguiente().getSiguiente());
return true;//se ha eliminado un nodo.
}//if
nodo_recorrido=nodo_recorrido.getSiguiente();
}//while
return false;//No se ha encontrado ningun nodo con el numero buscado.
}//agregar_al_final
}//class Lista_enlazada_con_un_nodo_fantasma
////////////////////////////////////////////////////////////////////////////////
//Y ahora voy a crear el form de la lista enlazada normal.
class Form_Enlazada_normal extends JFrame implements ActionListener, ListSelectionListener
{
private Control_personalizado control=new Control_personalizado(this,this);//Se pasa el mismo class como controlador de ambos tipos de eventos.
private ListaEnlazada Lista_de_nodos=null;//Se usará para cargarse con su misma instancia y con su desendiente para ahorrar lineas de codigo.
private JMenuBar jmbBarra=new JMenuBar();
private JMenu jmAcciones=new JMenu("Acciones");
private JMenuItem jmiActualizar_lista=new JMenuItem("Actualizar lista");
public Form_Enlazada_normal(String caption, ListaEnlazada nueva_lista_de_nodos)
{
super(caption);
this.setSize(450,250);
this.setResizable(false);
this.setLayout(null);
this.setLocationRelativeTo(this);//Hace que el form aparesca en el centro o cercano al centro.
this.setJMenuBar(jmbBarra);
jmbBarra.add(jmAcciones);
jmAcciones.add(jmiActualizar_lista);
jmiActualizar_lista.addActionListener(this);
control.setBounds(0,0,450,450);
this.getContentPane().add(control);
Lista_de_nodos=nueva_lista_de_nodos;//nueva_lista_de_nodos puede pasarse como parametro Lista_de_nodos o su desendiente Lista_enlazada_con_un_nodo_fantasma.
}//Constructor
//Implementa el click del item en el JList. Es el metodo buscar.
public void click_item(ListSelectionEvent evt)
{
//System.out.println(this.Lista_de_nodos.buscar_nodo(this.control.getItem()).getNombre());
this.control.setNodo( this.Lista_de_nodos.buscar_nodo(this.control.getItem()) );
}//valueChanged
@Override
public void valueChanged(ListSelectionEvent evt)
{
click_item(evt);
}//valueChanged
//Click del mouse en cualquier control que acepte click, no funciona con los items de JList, para eso esta valueChanged(ListSelectionEvent evt).
@Override
public void actionPerformed(ActionEvent evt)
{
click_salir(evt);
click_eliminar(evt);
click_agregar_al_final(evt);
click_actualizar_lista(evt);
}//actionPerformed
public void click_salir(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Salir")==true)
{
this.hide();
}//if
}//click_salir
public void click_actualizar_lista(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Actualizar lista")==true)
{
this.control.addDefaultListModel(this.Lista_de_nodos.getLista_de_items());
}//if
}//click_agregar_al_final
public void click_agregar_al_final(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Agregar al final")==true)
{
this.Lista_de_nodos.agregar_al_final(this.control.getNombre(), this.control.getNumero());
//this.control.addDefaultListModel(this.Lista_de_nodos.getLista_de_items());
this.control.limpiar_controles();
}//if
}//click_agregar_al_final
public void click_eliminar(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Eliminar")==true)
{
this.Lista_de_nodos.eliminar(this.control.getItem());
//this.control.addDefaultListModel(this.Lista_de_nodos.getLista_de_items());
}//if
}//click_eliminar
}//class Form_Enlazada_normal
///////////////////////////////////////////////////////////////////////////////
//Antes de continuar con los forms, tengo que crear un control personalizado, el cual será usado en ambos forms.
class Control_personalizado extends JPanel
{
private JTextField jtNombre=new JTextField(), jtNumero=new JTextField();
private JLabel jlNombre=new JLabel("Nombre"), jlNumero=new JLabel("Numero");
private JList jlNodos=null;//Nul porque hay que ponerle el JModele;
private JScrollPane jspBarra_desplazadora=null;
@SuppressWarnings("unchecked")
private DefaultListModel<String> dlmListador=new DefaultListModel();//Permite agregar items al JList.
private JButton jbAgregar_al_final=new JButton("Agregar al final"), jbSalir=new JButton("Salir"), jbEliminar=new JButton("Eliminar");
//private Nodo_Rafa nodo_encontrado_en_la_busqueda=null;
//Los dos parametros permiten crear eventos en otras clases como por ejemplo en el mismo class form y pasarse como parametro. Esto permite personalizar los datos y los eventos.
@SuppressWarnings("unchecked")
public Control_personalizado(ActionListener controlador_de_eventos_click, ListSelectionListener controlador_de_eventos_click_item)
{
this.setLayout(null);
this.setSize(450,250);
this.setLayout(null);
jlNombre.setBounds(5,0,200,25);
this.add(jlNombre);
jtNombre.setBounds(5,30,200,25);
this.add(jtNombre);
jlNumero.setBounds(5,65,200,25);
this.add(jlNumero);
jtNumero.setBounds(5,90,200,25);
this.add(jtNumero);
jlNodos=new JList(dlmListador);
jlNodos.addListSelectionListener(controlador_de_eventos_click_item);
jlNodos.setToolTipText("Lista de nodos, haga click en un item para mostrar los datos.");
jlNodos.setBounds(210,0,200,145);//Solo se le ponen las coordenadas porque este control va dentro del JScrollPane.
jspBarra_desplazadora=new JScrollPane(jlNodos);//El JList queda contenido en el JScrollPane.
jspBarra_desplazadora.setBounds(210,0,200,145);//Se le ponen las mismas coordenadas que el JList.
this.add(jspBarra_desplazadora);//Finalmente, se agrega el ScrollPane al JPanel.
jbAgregar_al_final.setBounds(5,150,150,25);
jbAgregar_al_final.addActionListener(controlador_de_eventos_click);
jbEliminar.setBounds(190,150,80,25);
jbEliminar.addActionListener(controlador_de_eventos_click);
jbSalir.setBounds(330,150,80,25);
jbSalir.addActionListener(controlador_de_eventos_click);
this.add(jbAgregar_al_final);
this.add(jbEliminar);
this.add(jbSalir);
}//Constructor
public void limpiar_controles()
{
this.setNombre("");
this.setNumero(0);
}//limpiar_controles
public void setNodo(Nodo_Rafa nuevo_nodo_encontrado_en_la_busqueda)
{
//this.nodo_encontrado_en_la_busqueda=nuevo_nodo_encontrado_en_la_busqueda;
//System.out.println(nuevo_nodo_encontrado_en_la_busqueda.getNombre());
if(nuevo_nodo_encontrado_en_la_busqueda!=null)//La solucion al error null o fuera del id del DefaultListModel es este condicional.
{
this.setNombre(nuevo_nodo_encontrado_en_la_busqueda.getNombre());
this.setNumero(nuevo_nodo_encontrado_en_la_busqueda.getNumero());
}//if
}//setNodo
//Este get permite obtener el texto seleccionado por medio de algun evento implementado en otra parte del programa.
public String getItem()
{
try
{
return dlmListador.getElementAt(jlNodos.getSelectedIndex());
}catch(Exception ex)
{
System.out.println("Causa " + ex.getMessage());
}//catch
return "";
}//*/
public void addDefaultListModel(DefaultListModel nuevoDefaultListModel)
{
//Esta es la forma más eficiente que he encontrado para cargar los datos en el JList.
//Evita bacios null y otra clase de fonomenos extraños con el programa.
dlmListador.clear();
dlmListador.clear();
for(int i=0; i<=nuevoDefaultListModel.getSize()-1; i++)
{
dlmListador.addElement( nuevoDefaultListModel.elementAt(i).toString());
}//for
}//addDefaultListModel
public void setNombre(String nuevo_nombre)
{
this.jtNombre.setText(nuevo_nombre);
}//setNombre
public String getNombre()
{
return this.jtNombre.getText();
}//getNombre
public void setNumero(int nuevo_numero)
{
this.jtNumero.setText("" + nuevo_numero);
}//setNumero
public int getNumero()
{
return Integer.parseInt(this.jtNumero.getText() );
}//getNumero
public void limpiar_lista()
{
dlmListador.clear();
}//limpiar_lista
@SuppressWarnings("unchecked")//Esto es para evitar un Warning a la hora de compilar.
public void addItem(String nuevo_item)
{
dlmListador.addElement(nuevo_item);
}//addItem
}//class Control_personalizado
class Panel_de_control extends JFrame implements ActionListener
{
private JButton jbNodos_normales=new JButton("Nodos normales"), jbNodos_con_uno_fantasma=new JButton("Nodos con uno fantasma");
private JMenuBar jmbBarra=new JMenuBar();
private JMenu jmArchivo=new JMenu("Archivo");
private JMenuItem jmiSalir=new JMenuItem("Salir");
private Form_Enlazada_normal frmLista_de_nodos_normal=new Form_Enlazada_normal("Normal", new ListaEnlazada());
private Form_Enlazada_normal frmLista_de_nodos_con_uno_fantasma=new Form_Enlazada_normal("Lista con un nodo fantasma", new Lista_enlazada_con_un_nodo_fantasma());
public Panel_de_control()
{
super("Panel de control");
this.setLayout(null);
this.setSize(360, 100);
this.setLocation(100, 200);
this.setResizable(false);
jbNodos_normales.setBounds(5, 10, 150, 25);
jbNodos_con_uno_fantasma.setBounds(170, 10, 180, 25);
this.getContentPane().add(jbNodos_normales);
this.getContentPane().add(jbNodos_con_uno_fantasma);
this.setJMenuBar(jmbBarra);
jmbBarra.add(jmArchivo);
jmArchivo.add(jmiSalir);
this.jmiSalir.addActionListener(this);
this.jbNodos_con_uno_fantasma.addActionListener(this);
this.jbNodos_normales.addActionListener(this);
}//Constructor
@Override
public void actionPerformed(ActionEvent evt)
{
click_salir(evt);
click_nodos_normales(evt);
click_nodos_con_uno_fantasma(evt);
}//actionPerformed
public void click_salir(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Salir")==true)
{
System.exit(0);
}//if
}//click_salir
public void click_nodos_normales(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Nodos normales")==true)
{
frmLista_de_nodos_normal.show();
}//if
}//click_nodos_normales
public void click_nodos_con_uno_fantasma(ActionEvent evt)
{
if(evt.getActionCommand().equalsIgnoreCase("Nodos con uno fantasma")==true)
{
frmLista_de_nodos_con_uno_fantasma.show();
}//if
}//click_nodos_con_uno_fantasma
}//Panel_de_control