Java es un lenguaje de programación de propósito general. Desde hace muchos años encabeza el ranking Tiobe de lenguajes de programación, con lo que tiene una buena acojida y podemos encontrarlo en numerosos sistemas. Su sintaxis deriva de C y C++, está fuertemente orientado a objetos (todo en Java son objetos), y su principal característica es ser multiplataforma.
Es decir, Java se caracteriza porque sus códigos fuentes son compilados a un código intermedio entre el fuente y el código máquina llamado bytecode. Dicho bytecode se ejecuta sobre la Máquina Virtual de Java (JVM), que está disponible en la gran mayoría de plataformas, con lo que conseguimos construir una vez y ejecutar en todos lados.
Dispone de librerías de todo tipo para programación de alto nivel. Y dado que corre sobre la capa de la JVM carece de librerías de bajo nivel. Esta capa intermedia que proporciona la multiplaforma merma su velocidad comparádose con otros lenguajes pero las últimas versiones de la máquina virtual ha mejorado mucho en rendimiento. Hay frameworks de Java que van desde la programación de entornos gráficos, pasando por microservicios, a desarrollo de grandes aplicaciones web.
Con Java puedes hacer casi de todo y para casi todo tipo de proyectos.
Pequeño howto o codekata para empezar rápido con Spring Boot en local. En este post vemos el SDK Man! que facilita mucho el trabajo. Es la herramienta que se recomienda desde la documentación oficial de Spring, es para entornos basados en UNIX, como GNU/Linux, Mac.. Se puede instalar siguiendo las instrucciones desde https://sdkman.io/. Podemos ejecutar el instalador con:
Para el que lo pueda necesitar, este es un codekata, howto o apunte para implementar la comunicación bidireccional entre Clientes y Servidores usando RMI, lo que se llama implementar callbacks hacia los clientes. Es una vuelta de tuerca al post anterior sobre la implementación del RMI de Java, Remote Method Invocation.
Este post es una ampliación para usar clientes y servidores con RMI de Java, de forma que tanto el servidor como el cliente actúan invocando métodos remotos en el cliente y servidor.
Esto es un codekata, apunte o resumen sobre esta funcionalidad de Java. Resumiendo, Java RMI es una funcionalidad que viene implementada de casa, mediante la cual podemos conectar servicios distribuidos, de forma que las funciones programadas se pueden ejecutar desde cualquier programa en cualquier servidor.
Es decir, RMI significa Remote Method Invocation, entonces tenemos que mediante estos mecanismos podemos declarar funciones en objetos de Java, y exponerlos a la Red para ser utilizados por procesos remotos. Se consigue de esta forma transparente para el programador, que se lancen acciones en servidores remotos. Así se puede escalar los procesos entre varios servidores, distribuyendo la carga y funcionalidades.
Es más fácil leer el fuente que explicarlo, al grano..
Sencillo codekata, apunte, resumen, o como queramos llamarlo, sobre cómo funciona la organización del código fuente en paquetes de Java. Esto se hace a base de nombres de directorios y ficheros. Es decir, un directorio es un package. Dentro de cada directorio, cada clase puede tener visibilidad de su mismo directorio o subdirectorios. Se organizan a base de la concatenación de nombres de directorio con subdirectorios y ficheros. Aparte de esto, dentro de cada fichero .java, debe haber una clase con el mismo nombre.
Sin más teoría, vamos al grano.. que es más fácil verlo con código.
Este es un codekata, apunte, de copia y pega con algo de código fuente sobre el uso de ArrayList y HashMap. Esto son dos tipos de datos básicos que nos provee Java, que será el siguiente punto de partida cuando tengamos que manejar colecciones de datos de información.
En Java tenemos que definir el tipo de dato y la forma de funcionamiento que queremos que tenga internamente, para obtener un comportamiento mejor de una forma o de otra. Tenemos que a partir de los vectores básicos, el siguiente paso será usar tipos de datos como los ArrayList, HashMap, LinkedList, HashSet, Iterator.. cada uno internamente está construido de una forma.
Desenpolvando un poco temas de Java, hoy traigo un pequeño howto para guardar datos que tenemos representados en clases, en ficheros, sin complicarnos demasiado la vida. Es decir, a veces, necesitamos algo rápido para guardar en ficheros o para transmitir información por la red.
La clase Java, el objeto, debe implementar la interfaz Serializable, y así será fácilmente guardable como fichero de texto. Al hacer un objeto serializable, de forma automática se podrá convertir en una cadena de texto, con lo que podremos guardar este contenido fácilmente en un fichero, transmitirlo por la red, en una BD, etc.. ¡vamos a grano!
Parece ser que están dando guerra las tablas xD A continuación les dejo un post con un ejemplo de tabla con cajas seleccionables y otros valores que son en éste caso enteros. Luego tenemos un botón con el que podemos recorrer la tabla (el modelo que representa los valores de la tabla) e ir borrando las filas que tienen la caja seleccionable seleccionada, valga la redundancia…
private static final long serialVersionUID = 1L; private JPanel contentPane; private JTable table;
/** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { TablaSeleccionable frame = new TablaSeleccionable(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
/** * Create the frame. */ public TablaSeleccionable() { setTitle("Tabla seleccionable by jnj"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 604, 347); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null);
JScrollPane scrollPane = new JScrollPane(); scrollPane.setBounds(10, 11, 560, 227); getContentPane().add(scrollPane);
String[] columnas = { "Los checkbox", "Un dato", "Otro dato" }; final DefaultTableModel modelo; modelo = new DefaultTableModel(null, columnas);
// hay que programar nuestra propia función getColumnClass para // poder poner controles como por ejemplo el checkbox con los datos // booleanos table = new JTable(modelo) { private static final long serialVersionUID = 1L;
@Override public Class getColumnClass(int column) { switch (column) { case 0: return Boolean.class; case 1: return Integer.class; case 2: return Integer.class; default: return Boolean.class; } } };
// INSERTA UNOS DATOS EN LA TABLA for (int i = 0; i < 10; i++) { Object[] nuevafila = { false, i, i }; modelo.addRow(nuevafila); }
// BOTON QUE ELIMINA FILAS, // Recorre de atrás hacia adelante las filas eliminando las // seleccionadas. JButton btnEliminarFilas = new JButton("Eliminar filas"); btnEliminarFilas.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { for (int i = 9; i >= 0; i--) { // si la fila i, columna 0 es true, es porque está // seleccionado el checkbox, entonces borra if (((Boolean) modelo.getValueAt(i, 0)) == true) { modelo.removeRow(i); } }
En el ejemplo he puesto un DefaultTableModel por su simplicidad. Hay otras formas de hacer lo mismo, como viene siendo habitual en programación. Espero que sirva.
Siguiendo los minitutoriales de la serie Swing, he desarrollado éste post sobre tablas para aprender a usar un poco más las tablas. Vamos al grano. Introducción
Es necesario:
Entorno de Desarrollo.
El JDK o JRE, yo he usado el JDK 1.7, pero ya Swing no sigue en desarrollo así que no tiene mucha importancia la versión que uses.
Trato de explicar cómo poner cajas seleccionables (checkbox), listas desplegables (combobox) y cajas de texto formateado, en una tabla. En el ejemplo he puesto una caja que sólo admite un número de 3 dígitos. Más adelante lo vemos.
Para manejar los datos puedes usar directamente el modelo de datos que autogenera un JTable, puedes usar un AbstractTableModel como aparece en muchos de los tutoriales que he encontrado por Internet, o puedes usar una implementación de DefaultTableModel, que internamente usa un vector con el que te permite añadir o borrar filas de forma dinámica. Yo he usado un DefaultTableModel que me ha parecido más interesante porque muchas veces necesitamos añadir o borrar datos de una tabla.
getContentPane().setLayout(null); JScrollPane scrollPane = new JScrollPane(); scrollPane.setBounds(10, 11, 810, 271);
getContentPane().add(scrollPane);
// usa mi modelo de datos modelo = new MiModelo(); // crea la tabla con mi modelo tabla = new JTable(modelo);
// scrollPane.setViewportView(tabla);
// EDITORES PERSONALIZADOS EN LA TABLA // la caja seleccionable, el checkbox lo pone sólo // con la función getColumnClass TableCellEditor editor;
// configura el combo JComboBox comboBox = new JComboBox(); comboBox.addItem("Opción A"); comboBox.addItem("Opción B"); comboBox.addItem("Opción C");
// configura el campo de texto JFormattedTextField campoTexto = null; try { // sólo admite 3 números campoTexto = new JFormattedTextField(new MaskFormatter("###")); } catch (Exception e) { System.out.println(e.getMessage()); }
// combo a la columna 3 editor = new DefaultCellEditor(comboBox); tabla.getColumnModel().getColumn(3).setCellEditor(editor);
editor = new DefaultCellEditor(campoTexto); tabla.getColumnModel().getColumn(4).setCellEditor(editor);
// capturador de eventos del ratón en la tabla // autogenerado con Eclipse tabla.addMouseListener(new MouseListener() {
@Override public void mouseReleased(MouseEvent e) { // TODO Auto-generated method stub
}
@Override public void mousePressed(MouseEvent e) { // TODO Auto-generated method stub
}
@Override public void mouseExited(MouseEvent e) { // TODO Auto-generated method stub
}
@Override public void mouseEntered(MouseEvent e) { // TODO Auto-generated method stub
}
@Override public void mouseClicked(MouseEvent e) { // TODO Auto-generated method stub
int fila = tabla.rowAtPoint(e.getPoint()); int columna = tabla.columnAtPoint(e.getPoint());
JOptionPane.showMessageDialog(null, "Valor de la celda: " + tabla.getValueAt(fila, columna).toString()); } });
}
// modelo de datos, usa DefaultTableModel que internamente // tiene un vector que nos permite por ejemplo añadir una fila // fácilmente con addRow... private static class MiModelo extends DefaultTableModel {
// constructor de la clase, simplemente pone unos datos en el vector de // datos. public MiModelo() { super(nombresColumna, 0);
// carga unos datos iniciales... for (int i = 0; i < 10; i++) {
Object[] aux = { i, Math.random(), i % 2 == 0, "Opción A", "123" };
addRow(aux);
} }
@Override public Class getColumnClass(int columnIndex) { // necesario para que dibuje la tabla con los tipos de columna return tiposColumna[columnIndex]; }
}
}
También he añadido la captura de eventos del ratón. Al escribir tabla.addMouseListener(new Mouse… podemos usar la combinación de teclas Ctrl + espacio y Eclipse nos intentará autogenerar el código. Ésto mismo se puede usar en cualquier momento, si Eclipse detecta que estás escribiendo algo que conoce te lo pone en un listado o si sabe seguro lo que vas a escribir lo autogenera. Es un comportamiento muy útil.
Explicaciones
He usado un DefaultTableModel que internamente tiene un vector de filas, para poder usar la función addRow() y así simplificar todo un poco que para eso está la clase DefaultTableModel.
La historia de configurar la tabla está en la clase MiModelo, espero haber dejado lo bastante comentado el código como para no explicar de nuevo aquí lo que hace. De todas formas si queda duda, mensaje aquí abajo que lo contesto en cuanto pueda.
Podemos obtener el vector de datos de la forma:
Vector data = modelo.getDataVector();
Hay muchas funciones interesantes que nos permitirán hacer lo que necesitemos. Para hacerse una idea, en mi Eclipse pongo modelo. y se me despliega el listado de funciones que tengo disponibles:
Tenemos la que ya he dicho addRow para añadir una fila, getRowCount que devuelve el número de filas, y muchas más. Algunas funciones necesitan un post entero para explicarlas así que lo dejaré aquí.
Donde pone tabla.addMouseListener(… está todo lo relacionado con el ratón. Podemos programar acciones para cuando se hace click, cuando se aprieta el botón, cuando se libera, etcétera…
Sobre los editores personalizados en una tabla hay que decir que admite cajas chequeables, listas desplegables y campos de texto. Además se pueden crear nuevos editores, como por ejemplo el que cita en la documentación oficial de un editor de celda que nos permite elegir entre una tabla de colores.
Más información
Me remito como siempre a la documentación oficial:
De todas formas hay muy buena información en otras páginas web, espero que si has leido éste tutorial por lo menos te haya aclarado algo, o te sirva el código fuente.
Siguiendo con los minitutoriales de Swing, ha llegado la madre del cordero del manejo de datos. Tarde o temprano necesitamos visualizar, modificar, borrar o guardar datos. Podemos hacer formularios, recorrer tablas guardadas en variables ocultas, usar listas, al final la manera más simple de mostrar muchos de éstos datos es una tabla, que en Swing se llama JTable.
Para seguir éste tutorial hace falta, un entorno de desarrollo (por ejemplo Eclipse), el JDK o el JRE, y un poco de paciencia xD
Si eres un máquina entonces descárgate directamente el código y no te olvides de visitarme de vez en cuando, a ver si aumentan las visitas =)
A saber
Antes de empezar hay que saber que un JTable es un componente Swing, que va a visualizar unos datos que se almacenan internamente en una variable de tipo TableModel. No se recomienda usar directamente pero si no lo necesitamos para qué vamos a complicarnos más la vida en usar otros métodos. Lo he usado para no complicar el ejemplo.
En el ejemplo se va a usar un DefaultTableModel el cual va a guardar referencia del TableModel que tiene la tabla. Entonces cuando se modifica, en éste caso añadiendo más filas, automáticamente la tabla se redibuja y muestra los datos actualizados. Se recomienda usar un AbstractTableModel para manejar los datos pero eso es otro tema.
Comenzando
Gran parte del código se puede generar con Eclipse. Así que los pasos a seguir para emepezar son:
Crear un nuevo proyecto Java.
Añadir un JFrame que genere todo el esqueleto de la ventana.
En el Swing Designer en vista de diseño poner un Absolute Layer que nos permitirá posicionar los elementos donde queramos.
Poner un JScrollPane y dentro de él el JTable, de esta manera si la tabla crece más que lo que vemos apareceran barras de scroll como las de la imagen anterior.
El botón de abajo que meterá contenido en la tabla.
Hecho ésto hago doble click en el botón y me muestra todo el código recién generado listo para seguir implementando.
El código
A continuación el código lo más legible que he podido poner:
// versión private static final long serialVersionUID = 1L;
// la tabla private JTable table;
// el modelo de tabla, aquí van a estar los datos. private DefaultTableModel model;
// función principal public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { JavaSwing9JTable frame = new JavaSwing9JTable(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
// constructor del frame que contruye toda la ventana... public JavaSwing9JTable() { //título setTitle("Java Swing 9 El JTable"); // cuando cerramos la ventana se cierra la aplicación por completo setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // dimensiones y posición setBounds(100, 100, 596, 331); // establece una capa absoluta para posicionar los elementos donde queramos getContentPane().setLayout(null);
// el panel con barras de scroll automáticas JScrollPane scrollPane = new JScrollPane(); // dimensiones y posición del panel de scroll scrollPane.setBounds(10, 11, 560, 227);
// se añade el panel de scroll a la ventana getContentPane().add(scrollPane);
// nombre de las columnas String[] columnNames = { "ID", "Un dato", "Otro dato" };
// creo un modelo de datos, sin datos por eso 'null' y establezco los // nombres de columna model = new DefaultTableModel(null, columnNames); // creo la tabla con el modelo de datos creado table = new JTable(model);
// se pone la tabla en el scroll scrollPane.setViewportView(table);
// código del botón JButton btnAadirLnea = new JButton("Meter contenido"); btnAadirLnea.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) {
// aquí se añaden datos a la tabla for (int i = 0; i < 100; i++) {
// creo un vector con una fila Object[] aux = { i, i * 34, Math.random() };
// añado la fila al modelo model.addRow(aux);
}
} }); // dimensiones y posición del botón btnAadirLnea.setBounds(10, 249, 267, 23); // pongo el botón en la ventana getContentPane().add(btnAadirLnea);
Ésta es la forma más simple que he encontrado de usar una tabla de Swing. El paso siguiente es usar un AbstractTableModel, crearnos una clase que la implemente, con la que podemos entonces hacer cosas como meter cajas seleccionables o cuadros desplegables en las filas.
Más información
Hay mucha información en Internet, me remito primero a la documentación oficial, está en inglés y es muy extensa:
Espero que sirva. En próximos posts espero ver cómo controlar los clicks del ratón, esos temas que citaba de la clase AbstractTableModel, formularios maestro-detalle, etcétera…
Podemos ver por todos lados la palabra Bean, significa vaina en inglés. Se puede leer en los lugares más variopintos: desde el NetBeans, los Java Beans, los Beans en Visual Studio, Eclipse, los Enterprise Java Beans, los Beans que usamos para acceder y guardar datos de nuestros programas.. pero ¿qué es un Bean de Java?
Volviendo de nuevo con un nuevo post sobre Swing, esta vez os dejo un componente un poco más complicado de entender, el JTree. Su uso con el Swing Designer es bien simple de ponerlo en un frame y dibujar su interfaz, pero cuando entremos en su estructura que tenemos para manejarlo necesitaremos tener conocimientos de lo que es un Tipo Abstracto de Datos (TAD para los amigos), y en concreto lo que es un árbol. Lo que se puede hacer y cómo se estructura internamente lo supongo por entendido. Si no es el caso mejor empezar por ver ésto, sino lo de a continuación puede convertirse en un jeroglífico.
Para éste tutorial he utilizado Eclipse Juno y la versión 7 update 9 del JDK. Lo primero es crear, dentro de Eclipse, en la ventana del explorador de proyectos, un nuevo proyecto de Java. Luego crear un nuevo JFrame con el asistente de Eclipse y ya tenemos el esqueleto del programa listo para empezar. Yendo al diseñador de formularios del Swing Designer le añades un Absolute layout al formulario para poder posicionar los componentes donde quieras del formulario, y entonces para éste ejemplo le he añadido dos botón y un componente JTree. El componente JTree está a su vez dentro de un JScrollPane para que se muestren las barras de scroll si el contenido es más grande que lo que se puede ver.
Antes de continuar te debe de haber quedado una ventana parecida a la de la imagen de inicio.
En la versión que tengo, cuando añado el JTree al Frame, se crea con un contenido sobre colores, deportes y comida. Éstos datos están en la propiedad model. De igual manera que algunos otros componentes, tenemos un modelo de árbol para usar el JTree. Por ejemplo, cuando usamos las listas tenemos modelos de listas, pues ahora son modelos de árbol. Si no establecemos el modelo, por defecto se construye con los elementos dichos. Vamos ahora con el TreeModel.
Creando el árbol
Vamos a usar dos tipos de datos para crear la estructura y ponerla en el JTree: el DefaultTreeModel y el DefaultMutableTreeNode.
El botón para cargar el árbol lo he puesto para leer el árbol de directorios de tu disco duro. El tipo de datos TreeModel es el objeto que tiene internamente el JTree para manejar su estructura en árbol, nosotros vamos a usar una clase derivada de ésta porque se trata de una interfaz que no podemos usar directamente. Entonces tenemos el DefaultTreeModel que va a ser el tipo que usaremos.
Por otro lado tenemos que en cada elemento de un DefaultTreeModel es un DefaultMutableTreeNode. De forma que cada nodo de éstos puede tener a su vez hijos, formando así un árbol según tenga hijos o no. Para entenderlo ésto he pensado usar el árbol de directorio que todos conocemos.
Antes de seguir, explicando las dos funciones del JTree, si queremos crear una estructura de tipo árbol como por ejemplo:
…lo que tenemos que hacer es que cada nodo es un elemento de tipo DefaultMutableTreeNode, y cada elemento se puede hacer hijo de otro. Es decir, lo único que hay que decirle al programa es de cada nodo cuál es su padre con la función insertNodeInto(nodo, padre, índice). Por ejemplo para la estructura anterior programaríamos:
DefaultMutableTreeNode nodoroot, nodo1, nodo11, nodo12, nodo2, nodo21, nodo22; nodoroot = new DefaultMutableTreeNode("Éste es el nodo principal."); nodo1 = new DefaultMutableTreeNode("nodo1"); nodo11 = new DefaultMutableTreeNode("nodo11"); nodo12 = new DefaultMutableTreeNode("nodo12"); nodo2 = new DefaultMutableTreeNode("nodo2"); nodo21 = new DefaultMutableTreeNode("nodo21"); nodo22 = new DefaultMutableTreeNode("nodo22"); arbol.setRoot(nodoroot); arbol.insertNodeInto(nodo1, nodoroot, 0); arbol.insertNodeInto(nodo2, nodoroot, 1); arbol.insertNodeInto(nodo11, nodo1, 0); arbol.insertNodeInto(nodo12, nodo1, 1); arbol.insertNodeInto(nodo21, nodo2, 0); arbol.insertNodeInto(nodo22, nodo2, 1);
En el ejemplo os he dejado algo más complicado, con una función recursiva que carga toda la estructura de directorios desde el directorio raiz «/». Es decir, cuando le damos al botón tenemos el código siguiente:
btnCargarrbolDe.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) {
DefaultTreeModel arbol = (DefaultTreeModel) tree.getModel(); DefaultMutableTreeNode nroot = new DefaultMutableTreeNode("Árbol de directorios");
… una vez dicho cual es el nodo principal (nroot), la función CargaEstructuraDirectorios lo hace todo. Puede tardar bastante, depende lo que tengas en tu ordenador o lo rápido que sea, déjalo ejecutarse hasta el final si lo quieres ver el resultado.
No voy a entrar en detalle sobre funciones recursivas o lectura de directorios. Lo que hay que saber es que lista un directorio, añadiendo todo lo que encuentra al árbol en su lugar adecuado, de maner que si encuentra un directorio lo añade también. Y acto seguido entra al directorio y lo lista, de manera que si algo de dentro también es un directorio vuelve a hacer lo mismo, es decir, vuelve a entrar en éste segundo directorio y lo lista también añadiendo de nuevo los elementos en el lugar adecuado. Así sucesivamente hasta listar todos los directorios y subdirectorios.
Todo ésto queda simple con una función recursiva que os dejo aquí:
Igual que se añaden nodos, también se pueden borrar. Usando la función removeNodeFromParent que se usa en el ejemplo. Con un botón simple. No sólo podemos borrar un nodo, también podemos borrarlo de un sitio y ponerlo en otro, reordenando nuestro árbol, modificándolo, o lo que necesitemos. Pero con añadir o borrar tenemos lo básico para empezar…
Click, empieza el juego
Ahora se complica, pero empieza el juego xD ¿cómo hacer algo cuando hacemos click en un elemento del árbol? Haciendo click derecho con el ratón en el JTree añadimos el capturador de eventos que vamos a usar para hacer álgo cuando el usuario hace click en el JTree:
Eclipse, de nuevo nos genera el código esqueleto siguiente:
final JTree tree = new JTree(); tree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { DefaultMutableTreeNode nseleccionado = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); JOptionPane.showMessageDialog(frame, nseleccionado.getPath()); } });
Se pueden capturar otros eventos. Y bueno, ya la imaginación o lo que necesitemos entra en juego para desarrollar lo que necesitemos. Con las funciones principales que nos proporcina el DefaultMutableTreeNode pordemos hacer lo que queramos. Podemos tener varios árboles y ponerlos en el JTree cuando queramos uno u otro, podemos recorrer los nodos por los índices, podemos saber cuál es el nodo principal con la función .getRoot, saber cuántos hijos tiene un nodo con .getChildCount, etcétera…
No hay más que curiosear para qué sirven las funciones proporcionadas, como podemos ver en la imagen siguiente del Eclipse:
Hay que saber que cuando hacemos cambios en la estructura de árbol, éstos automáticamente se visualizan en el JTree, con lo que sólo tenemos que centrarnos en el árbol.
Para más información me remito de nuevo a la documentación oficial:
En el ejemplo he comentado algunas cosas más. Aquí están en descarga directa los códigos fuentes. Hay un .jar, para ejecutarlo necesitas el JRE instalado, si quieres modificarlo, sólo necesitas un editor de texto ya que sólo hay un fichero .java y recompilarlo.
Todo el código comentado es el siguiente para el que no quiera descargarlo:
// La clase principal public class Principal extends JFrame {
// el panel contenedor private JPanel contentPane; // el JFrame static Principal frame;
/** * esta es la función que primero se ejecuta creando el JFRame y visualizándolo */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { frame = new Principal(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
/** * la creación del JFrame principal donde está programado todo lo de éste ejemplo */ public Principal() { // título de ventana setTitle("Java Swing 8 El JTree by Jnj"); // operación al cerra el JFrame setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // dimensiones y posición en el escritorio setBounds(100, 100, 450, 306); // se crea el panel contentPane = new JPanel(); // los bordes contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); // se establece setContentPane(contentPane); contentPane.setLayout(null);
// se pone el botón en la ventana JButton btnCargarrbolDe = new JButton( "Cargar u00E1rbol de directorios"); btnCargarrbolDe.setBounds(10, 11, 200, 23); contentPane.add(btnCargarrbolDe);
// las barras de escroll para el JTree JScrollPane scrollPane = new JScrollPane(); scrollPane.setBounds(10, 45, 414, 206); contentPane.add(scrollPane);
// el JTree final JTree tree = new JTree(); // que captura el evento click tree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { // se obtiene el nodo seleccionado DefaultMutableTreeNode nseleccionado = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); // visualiza el path del nodo JOptionPane.showMessageDialog(frame, nseleccionado.getPath()); } }); // se pone el árbol en el panel de las barras de scroll scrollPane.setViewportView(tree);
// aquí el botón que borra el último elemento de los primeros hijos // es decir, desde el nodo root, borra sólo el último hijo JButton btnBorrarltimoNodo = new JButton("Borrar u00FAltimo nodo"); btnBorrarltimoNodo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) {
DefaultTreeModel arbol = (DefaultTreeModel) tree.getModel(); DefaultMutableTreeNode padre = (DefaultMutableTreeNode) arbol.getRoot(); int numeroDeHijos = arbol.getChildCount(padre);
// borra el último hijo del padre arbol.removeNodeFromParent((MutableTreeNode) arbol.getChild( padre, numeroDeHijos - 1)); } }); btnBorrarltimoNodo.setBounds(220, 11, 204, 23); contentPane.add(btnBorrarltimoNodo);
// evento click del botón de carga del árbol // simplemente añade el nodo root y llama a la función de carga // para añadir todos los nodos hijos al nodo root btnCargarrbolDe.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) {
DefaultTreeModel arbol = (DefaultTreeModel) tree.getModel(); DefaultMutableTreeNode nroot = new DefaultMutableTreeNode( "Árbol de directorios");
arbol.setRoot(nroot);
CargaEstructuraDirectorios(arbol, nroot, "/");
} });
}
// función recursiva que lista todos los directorios y subdirectorios // a partir de una ruta, añadiéndolos a la estructura en árbol private void CargaEstructuraDirectorios(DefaultTreeModel arbol, DefaultMutableTreeNode padre, String ruta) { DefaultMutableTreeNode aux = null;
File archivo = new File(ruta); // puntero al directorio de la ruta File[] archivos = archivo.listFiles(); // lista todos los archivos de la ruta
// recorre lo que hay en la ruta if (archivos != null) { for (int i = 0; i < archivos.length; i++) {
// creando un nodo con cada cosa del directorio aux = new DefaultMutableTreeNode(archivos[i].getName()); // inserta el nodo hijo arbol.insertNodeInto(aux, padre, i);
// si encontramos un directorio volvemos a hacer lo mismo con sus hijos if (archivos[i].isDirectory()) { try {
// llamando recursivamente de nuevo a ésta misma función CargaEstructuraDirectorios(arbol, aux, archivos[i].getAbsolutePath() + "/");
} catch (Exception e) { System.out.println(e.getMessage()); // por si acaso le he puesto un try xD } }
El tiempo pasa y no vuelve, el valor más preciado que tenemos, cuando a uno le falta es cuando lo tiene en cuenta. Estoy sacando tiempo de debajo de las piedras para seguir escribiéndoles. Vienen días de tormenta, hace mucho viento, parece que llueve pero no llueve, la prima de riesgo sube y baja, los políticos siguen con sus historias, y yo sigo con lo mío, así que aquí hoy os dejo algo más sobre Swing. En concreto sobre componentes para dar formato a textos y algo más.
En éste minitutorial, voy a dar un repaso a los componentes que sólo admiten cierto tipo de valores como los JFormattedTextField. Otro componente interesante, el JEditorPane, que admite por defecto tres tipos de contenido: el texto plano normal y corriente de siempre (text/plain), texto enriquecido (text/rtf), o un documento en HTML (text/html). Y otra caja de texto, el JTextPane, que admite incluso otros componentes Swing como etiquetas, botones, etcétera…
Para éste post he utilizado la versión JDK 7 update 9, y Eclipse Juno EE con el plugin Swing Designer.
JFormattedTextField
Éste componente hereda del JTextField, con lo que tiene los mismos métodos y se usa de manera parecida. La diferencia que tiene con respecto a los demás componentes de texto es que permite establecer una máscara de entrada para los datos que el usuario escribe. Por ejemplo si queremos poner un código postal, un número de teléfono, etcétera..
Éste componente es uno de los más prácticos porque bien programado nos aseguramos de que el usuario va a poner lo que queremos que ponga. La carencia que tiene es que no admite expresiones regulares directamente, pero se puede sortear éste problema.
Al constructor de JFormattedTextField, se le pasa un objeto nuevo de tipo MaskFormatter, y éste se encarga de usar la máscara de entrada para admitir o no los valores de entrada.
Podemos usar en la máscara los siguientes caracteres para contruir nuestra máscara:
# cualquier número. ‘ carácter especial. U carácter, que lo modifica a mayúsculas. L carácter, que lo modifica a minúsculas. A carácter o número. ? cualquier carácter. * cualquier cosa. H cualquier caracter hexadecimal, es decir, del 0 al 9 y de la ‘a’ a la ‘f’ o de la ‘A’ a la ‘F’.
También podemos comprobar con una expresión regular si el valor introducido es correcto. Tenemos un ejemplo programado, creando un objeto nuevo de tipo RegexFormatter aquí:
Si quieres construir el tuyo propio lo que debes hacer es siguiendo el siguiente código reprogramar el método stringToValue, comprobando que el texto de entrada es válido:
JFormattedTextField formattedTextField = new JFormattedTextField(new AbstractFormatter() { @Override public String valueToString(Object value) throws ParseException { // TODO Auto-generated method stub return null; }
Si quieres generar con Eclipse el código esqueleto, cuando llegues a donde pone new Abstract… le das a Ctrl + Espacio y te saldrán las opciones que tienes, ésto lo puedes hacer mientras que escribes en cualquier parte del programa para ir más rápido, entonces eliges dándole a Enter y te genera el código de aquí arriba. Ya con ésto puedes usar una expresión regular usando un ‘matcher’. Pero ésto ya sería para otro post.
Éste componente admite tres tipos de textos formateados por defecto: texto plano, documento enriquecido RTF y HTML. Un ejemplo de uso es el siguiente:
JEditorPane editorPane = new JEditorPane(); editorPane.setContentType("text/html"); editorPane.setText("<h1>Título</h1>" + "<p>Ésto <b>es</b> un <i>párrafo</i>.</p>"); editorPane.setBounds(10, 92, 481, 134); contentPane.add(editorPane);
Con la función setContentType se establece el tipo de texto, que permite: text/plain para texto normal y corriente, con text/rtf podemos poner texto enriquecido siguiendo su especificación, y el text/html para páginas web.
Éste es un subcomponente de JEditorPane, podemos usarlo exactamente igual pero además añade que podemos insertar dentro otros componentes con la función insertComponent(nombreComponente).
JTextPane textPane = new JTextPane(); textPane.setContentType("text/html"); textPane.setText("<h1>Título</h1>" + "<p>Ésto <b>es</b> un <i>párrafo</i>.</p>"); JButton boton = new JButton("Ésto es un botón"); textPane.insertComponent(boton); textPane.setBounds(10, 262, 481, 125); contentPane.add(textPane);
Se pueden añadir todo tipo de componentes, o por lo menos la declaración de insertComponent recibe un parámetro de tipo Component, con lo que habría que probar a ver si los admite todos.
Terminando
Es interesante la función setPage(URL) que admite tanto el JTextPane como el JEditorPane, con la que podemos poner una página de Internet o de la red local dentro del componente. En el ejemplo adjunto abajo se utiliza la función setPage para cargar contenido HTML. Haciendo un navegador casero.
Es interesante que también admite editar el contenido el JTextPane y el JEditorPane, con lo que hay posibilidades para hacer un editor de páginas web, por ejemplo, o de texto enriquecido. Se le pueden añadir unos botones alrededor de la ventana para cambiar los formatos.. etcétera.. ya cada uno que imagine y que haga, hay mucho juego.
Bueno con ésto ya hay para hecharle un buen vistazo a éstos componentes, espero que sirva. A continuación les dejo todo el código de ejemplo. También adjunto un fichero comprimido con todo, hay un .jar ejecutable dentro para verlo en marcha. Para ejecutarlo sólo necesitas el JRE instalado. Aquí va el código:
// éste es el panel principal que todo lo contiene private JPanel contentPane;
// función que primero se ejecuta creando el JFrame public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Principal frame = new Principal(); // visualiza el frame frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); }
// constructor de la clase, // se usa para crear todos los componentes y programar // todo el funcionamiento public Principal() throws ParseException {
// se configura la ventana... setTitle("Java Swing 7 Textos y otros by Jnj"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 517, 438); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null);
// la primera etiqueta JLabel lblJformattedtext = new JLabel("JFormattedTextField"); lblJformattedtext.setBounds(10, 11, 133, 14); contentPane.add(lblJformattedtext);
// la etiqueta del JEditorPane JLabel lblJeditorpane = new JLabel( "JEditorPane que accede a http://localhost/"); lblJeditorpane.setBounds(10, 67, 250, 14); contentPane.add(lblJeditorpane);
// la etiqueta del JTextPane JLabel lblJtextpane = new JLabel("JTextPane"); lblJtextpane.setBounds(10, 237, 109, 14); contentPane.add(lblJtextpane);
// la caja de texto formateado // con una máscara de formato JFormattedTextField formattedTextField = new JFormattedTextField( new MaskFormatter("(####)#########")); formattedTextField.setBounds(10, 36, 481, 20); contentPane.add(formattedTextField);
// el JEditorPane que usa una página web // accediendo al servidor web de nuestra // máquina local JEditorPane editorPane = new JEditorPane(); // es obligatorio usar el try catch para capturar errores try { // establece la página editorPane.setPage("http://localhost/"); } catch (IOException e) { e.printStackTrace(); } editorPane.setBounds(10, 92, 481, 134); contentPane.add(editorPane);
// y el JTextPane JTextPane textPane = new JTextPane(); // se establece el tipo textPane.setContentType("text/html"); // con un texto en HTML textPane.setText("<h1>Título</h1>" + "<p>Ésto <b>es</b> un <i>párrafo</i>.</p>"); // se crea un botón JButton boton = new JButton("Ésto es un botón"); // se inserta el botón dentro de la caja de texto textPane.insertComponent(boton); textPane.setBounds(10, 262, 481, 125); contentPane.add(textPane); } }