Tema_4_Objetos_JDialog_JTree_y_JFormattedTextField.pdf

Share Embed Donate


Short Description

Download Tema_4_Objetos_JDialog_JTree_y_JFormattedTextField.pdf...

Description

Universidad Católica Los Ángeles de Chimbote – Programación Visual II

OBJETOS JDIALOG, JTREE Y JFORMATTEDTEXTFIELD

Objeto JDialog

En una una apli aplica caci ción ón jav java con con venta entana nas s deb debería ería habe haberr un únic único o

JFrame,

correspo correspondie ndiente nte a la ventana ventana principal principal de la aplicac aplicación. ión. El resto resto de ventana ventanas s secundarias deberían ser  JDialog. Por supuesto, podemos usar JInternalFrame, si lo desea deseamo mos s sin ningún ningún prob problem lema, a, pero pero en ésta ésta sesió sesión n nos nos refer referimo imos s sólo sólo a ventanas "reales", a las que el sistema operativo trata como tales.

Ing. Martín Salcedo Quiñones

Página 1

Universidad Católica Los Ángeles de Chimbote – Programación Visual II Un JFrame en una ventana que en Windows crea, en la barra de herramientas, donde está el menú de "inicio" y las aplicaciones que tenemos abiertas, un nuevo botón de aplicación abierta. En una aplicación lo normal es que sólo haya un botón ahí. Si creamos varios JFrame en nuestra aplicación, aparecerán varios botones, uno por cada JFrame. El JDialog no muestra este botón. Por ello, el resto de las ventanas de nuestra aplicación deberías ser  JDialog. Hay otro motivo más. Un JFrame no admite a ninguna otra ventana como padre. El JDialog sí admite como padres un JFrame u otros JDialog. Esto es importante porque una ventana hija siempre quedará por encima de su ventana padre. Si al crear los JDialog les pasamos el JFrame como padre, los JDialog siempre estarán visibles por encima del JFrame. No se podrán ir "detrás" de él. Si además, en el constructor del JDialog ponemos a true el flag que indica que es modal, además de pasarle una ventana padre, entonces el JDialog impedirá el acceso a las otras ventanas hasta que se cierre. Otra ventaja de admitir un padre es que heredan el icono de él. Si hemos cambiado el icono del JFrame con el método setIconImage(), entonces todos los JDialog que hagamos como hijos de este JFrame heredarán el icono. Todas las ventanas de nuestra aplicación tendrán el

mismo icono en lugar de la taza de café por defecto. Un JDialog puede ser modal, pasándole un true en el constructor en el sitio adecuado o haciéndolo modal con el método setModal(). Si hacemos un JDialog modal, todas las demás ventanas se deshabilitarán hasta que el usuario de nuestro programa cierre el JDialog. Esto está estupendo para pedir un dato al usuario y evitar que toque otras cosas hasta que haya introducido el dato. Sin embargo, tiene un peligro. Supongamos un JDialog que lo hacemos modal para pedir unos datos al usuario. Este JDialog tiene un botón de "Aceptar" para que el usuario lo pulse cuando haya terminado de introducir los datos. Supongamos que en el código de ese botón "Aceptar" comprobamos los datos que ha metido el usuario y vemos que son incorrectos. Le sacamos un segundo JDialog modal para indicarle el error y no cerramos el primero.

Ing. Martín Salcedo Quiñones

Página 2

Universidad Católica Los Ángeles de Chimbote – Programación Visual II ¿Quién debe ser el padre de ese segundo JDialog modal?. Si hacemos que el padre sea el JFrame tendremos dos JDialog modales hijos del JFrame, es decir, dos JDialog modales hermanos. Esto nos dará problemas, como que ambas ventanas queden deshabilitadas, que al cerrar una de ellas se nos oculten todas, que parte de la ventana quede deshabilitada mientras que otra parte no, etc. Entonces, ¿cómo hacemos?. Para que java no haga cosas raras, el padre del segundo JDialog modal debe ser el primer  JDialog modal. De esta forma, el segundo tiene "prioridad" sobre el primero. Todo queda deshabilitado excepto este segundo JDialog. Cuando lo cerremos, será el primero el que mande. Resumiendo, si queremos varias ventanas modales simultáneamente en pantalla, cada ventana que se muestre debe ser padre de la siguiente, de forma que la cadena de ventanas modales sean padre, hijo, nieto, etc. Tener dos ventanas modales simultaneas que sean hermanas o primas o cualquier otra relación que no sea directa, nos dará problemas

Veamos a continuación un ejemplo sencillo usando JDialog import java.awt.event.*; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.WindowConstants; public class DosVentanas { private JFrame ventanaPrincipal; private JDialog ventanaSecundaria; public static void main(String[] args) { new DosVentanas(); } public DosVentanas() { // Construcción de ventana principal ventanaPrincipal = new JFrame("Ventana principal"); JButton boton = new JButton("Abre secundaria"); ventanaPrincipal.getContentPane().add(boton);

Ing. Martín Salcedo Quiñones

Página 3

Universidad Católica Los Ángeles de Chimbote – Programación Visual II ventanaPrincipal.pack(); // Construcción de ventana secundaria ventanaSecundaria = new JDialog(ventanaPrincipal,"Ventana secundaria"); JLabel etiqueta = new JLabel("Hola"); ventanaSecundaria.getContentPane().add(etiqueta); ventanaSecundaria.pack(); // Hacer que el botón abra la ventana secundaria y cierre la principal boton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ventanaPrincipal.setVisible(false); ventanaSecundaria.setVisible(true); } }); // Hacer que al cerrarse la secundaria con la x de arriba a la // derecha, se muestre la primaria ventanaSecundaria.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { ventanaPrincipal.setVisible(true); ventanaSecundaria.setVisible(false); } public void windowClosed(WindowEvent e) { ventanaPrincipal.setVisible(true); ventanaSecundaria.setVisible(false); } }); // Mostrar la ventana principal ventanaPrincipal.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); ventanaPrincipal.setVisible(true); } }

 Al momento de ejecutar el código antes indicado, se visualiza:

 Al dar clic en el botón de comando “Abre secundaria” se muestra:

Ing. Martín Salcedo Quiñones

Página 4

Universidad Católica Los Ángeles de Chimbote – Programación Visual II

Objeto JTree

El JTree es el componente java visual (como los botoncitos, listas, menús, etc) que nos permite visualizar un árbol. En él podemos ver el típico árbol de datos en el que podemos abrir cada uno de los nodos para ver qué tiene dentro, cerrarlos, etc. Similar al árbol de directorios que nos muestran algunas aplicaciones para elegir un fichero. Como en casi todos los componentes visuales de java, hay dos clases importantes implicadas. Por un lado tenemos "la vista", que es la clase java que se ve. Esta clase es el JTree y es lo que se ve en la pantalla, en nuestra ventana. Por otro lado tenemos el "modelo de datos". Esta clase de java puede ser cualquier clase que implemente la interface TreeModel, pero java nos ofrece ya implementada la clase DefaultTreeModel. Esta clase es la que contiene los datos que queremos visualizar en "la vista". Contiene los datos que visualizaremos en el JTree. Puesto que vamos a hacer un árbol, admite datos que se puedan asociar entre sí como padres e hijos. No valen datos cualesquiera. Esos datos deben implementar  la interface TreeNode. Cualquier clase que implemente esta interface, tendrá métodos para interrogarle sobre quién es su padre, si tiene hijos, etc. Estos métodos será los que acabe usando JTree para saber qué debe pintar, quién es hijo de quién y quién es padre de quién. Existe otro tipo de dato también importante, el MutableTreeNode. Este es igual que el anterior, pero además tiene métodos para modificar las asociaciones entre padres e hijos. Permite añadir  nuevos hiijos a los padres, cambiar el padre de los hijos y cualquier otro tipo de indecencia que se nos ocurra. Si nuestro árbol va a cambiar sobre la marcha, nos interesa usar datos (nodos) que implementen esta interface. Java nuevamente nos ofrece una clase que ya implementa MutableTreeNode y por tanto tiene todos los

Ing. Martín Salcedo Quiñones

Página 5

Universidad Católica Los Ángeles de Chimbote – Programación Visual II métodos necesarios para saber quién es hijo de quién y los métodos necesarios para cambiar estas asociaciones. Esta clase es DefaultMutableTreeNode. Tiene además un método intereseante, que es setUserObject(). Este método nos permite guardar dentro la información que queramos. Esta información será nuestro dato real, lo que realmente nos interesa. DefaultMutableTreeNode únicamente nos ahorrará escribir el código necesario para mantener asociaciones entre padres e hijos, además de hacer de almacén de nuestro dato. Vamos a proceder a construir un árbol que tenga la siguiente apariencia:

Primero instanciamos nuestro modelo de datos, el DefaultTreeModel y la parte visual,

el

JTree.

Metemos

el

primero

dentro

del

segundo.

La

clase

DefaultTreeModel necesita en su constructor el nodo raíz del árbol, es decir, el dato que hace de padre de todos los demás, el de más alto nivel. Por ello, debemos instanciar este primer dato para poder construir el DefaultTreeModel. Ese

primer

dato

será

un

DefaultMutableTreeNode.

A

este

DefaultMutableTreeNode podemos pasarle el dato que queramos bien a través del método que comentamos setUserObject(), bien a través del constructor. Nuestro dato será un simple String que diga "abuelo" y lo meteremos en el constructor. El código quedaría así DefaultMutableTreeNode abuelo = new DefaultMutableTreeNode("abuelo"); modelo = new DefaultTreeModel(abuelo); JTree tree = new JTree(modelo);

 Ahora sólo nos queda ir añadiendo el resto de los datos del árbol. Lo único que tenemos que hacer es ir creando los nodos, como DefaultMutableTreeNode. A

Ing. Martín Salcedo Quiñones

Página 6

Universidad Católica Los Ángeles de Chimbote – Programación Visual II cada uno de ellos meterle el dato que queramos, bien en el constructor, bien con el método setUserObject(). En nuestro caso usaremos un simple String con el texto que queremos que se muestre. Finalmente, hay que ir asociando estos datos. El abuelo ya lo tenemos creado, así que el código de creación de los demás nodos puede ser este: DefaultMutableTreeNode padre = new DefaultMutableTreeNode("padre"); DefaultMutableTreeNode tio = new DefaultMutableTreeNode("tio"); DefaultMutableTreeNode hijo=new DefaultMutableTreeNode("hijo"); DefaultMutableTreeNode hija=new DefaultMutableTreeNode("hija");

Para asociar estos datos tenemos dos opciones: 1. Usar los métodos add(), insert() y setParent() de DefaultMutableTreeNode

para ir añadiendo unos nodos a otros. 2. Usar el método insertNodeInto() de DefaultTreeModel. A este método le

pasamos nodo padre e hijo que queremos asociar y el se encarga de hacer la asociación. La diferencia de hacerlo de una manera u otra es que JTree se entera automáticamente de cambios de DefaultTreeModel y los refleja automáticamente en pantalla, pero no se entera de los cambios en los DefaultMutableTreeNode y por tanto no los refresca en pantalla.

Puesto que estamos haciendo un ejemplo simple y es más simple, usaremos el método insertNodeInto() para hacer la asociación. Este método lleva tres parámetros: •

Nodo que queremos que sea hijo



Nodo que queremos que sea padre



En qué posición queremos que esté el hijo respecto a otros hijos. Dicho de otra forma, cuando despleguemos un padre que tiene por ejemplo cuatro hijos, en qué posición queremos que esté este nuevo hijo: el primero, en medio, el último.

El código para estas asociaciones es sencillo:

Ing. Martín Salcedo Quiñones

Página 7

Universidad Católica Los Ángeles de Chimbote – Programación Visual II modelo.insertNodeInto(padre,abuelo,0); modelo.insertNodeInto(tio, abuelo, 1); modelo.insertNodeInto(hijo, padre, 0); modelo.insertNodeInto(hija, padre, 1);

Por lo tanto, el código quedaría de la siguiente manera: import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.WindowConstants; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel;

public class PruebaJTree { public static void main(String[] args) { // Construccion del arbol DefaultMutableTreeNode abuelo = new DefaultMutableTreeNode("abuelo"); DefaultTreeModel modelo = new DefaultTreeModel(abuelo); JTree tree = new JTree(modelo); // Construccion de los datos del arbol DefaultMutableTreeNode padre = new DefaultMutableTreeNode("padre"); DefaultMutableTreeNode tio = new DefaultMutableTreeNode("tio"); modelo.insertNodeInto(padre, abuelo, 0); modelo.insertNodeInto(tio, abuelo, 1); DefaultMutableTreeNode hijo = new DefaultMutableTreeNode("hijo"); DefaultMutableTreeNode hija = new DefaultMutableTreeNode("hija"); modelo.insertNodeInto(hijo, padre, 0); modelo.insertNodeInto(hija, padre, 1); // Construccion y visualizacion de la ventana JFrame v = new JFrame(); JScrollPane scroll = new JScrollPane(tree); v.getContentPane().add(scroll); v.pack(); v.setVisible(true); v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } }

 Al momento de ejecutar el código antes indicado, se visualiza:

Ing. Martín Salcedo Quiñones

Página 8

Universidad Católica Los Ángeles de Chimbote – Programación Visual II

Objeto JFormattedTextField

El JFormattedTextField es un componente java un paso más evolucionado que un JTextField normal. El JTextField permite al usuario ingresar texto. Cuando desde nuestro código le pedimos el contenido, nos devuelve el texto introducido por el usuario como String. Cuando desde código le decimos lo que queremos que muestre, debemos pasarle un String. El JTextField, además, no hace ningún tipo de comprobación sobre el texto. El JFormattedTextField da un paso más allá. Aunque el usuario mete un texto, el JFormattedTextField lo convierte a la clase que nosotros queramos (un Integer , Float, Date o incluso una clase nuestra propia). Cuando queramos pasarle algo, le

podemos pasar directamente cualquiera de estas clases y él se encarga de la conversión a texto para mostrar. Para editar cualquier tipo básico de java, estilo Integer , Float, Double, Date, etc, basta con llamar al método setValue() del JFormattedTextField pasándole uno

Ing. Martín Salcedo Quiñones

Página 9

Universidad Católica Los Ángeles de Chimbote – Programación Visual II de estos tipos de datos, o bien pasárselo en el constructor. Por ejemplo, para Integer, nos bastaría con cualquiera de los dos casos siguientes: JFormattedTextField textField1 = new JFormattedTextField (new Integer(3)); // o bien .... JFormattedTextField textField2 = new JFormattedTextField (); textField2.setValue(new Integer(3));

Con esto ya tenemos un editor que nos permite recoger  Integer  directamente cuando el usuario lo edite: Integer valor = textField1.getValue();

Supongamos que el usuario escribe algo en el JFormattedTextField y luego pincha con el ratón en otros sitio (se dice que el JFormattedTextField pierde el foco), por ejemplo, en un botón de "Aceptar" los cambios introducidos. En el momento que el JFormattedTextField pierde el foco, comprueba el texto escrito por el usuario. Si es correcto, lo guarda de forma que el método getValue() nos devolverá el nuevo valor. Si es incorrecto, pondrá automáticamente el último valor  bueno, deshaciendo el cambio hecho por el usuario. Este comportamiento puede cambiarse con el método setFocusLostBehavior() , al que podemos pasar varios valores: •

JFormattedTextField.COMMIT. Si el texto introducido es correcto, se

guarda para devolverlo cuando se haga getValue(). Si es incorrecto, no se hace nada, el texto en pantalla queda como esta, o sea, mal. getValue() nos devolverá el último valor correcto, independientemente de lo que se muestre en pantalla. •

JFormattedTextField.REVERT. Cuando hacemos click en otro sitio, el

editor vuelve automáticamete a su último valor bueno, descartando todas nuestras ediciones, sean correctas o no. Para que esta opción tenga sentido, debemos llamar desde código al método commitEdit() sin que el

Ing. Martín Salcedo Quiñones

Página 10

Universidad Católica Los Ángeles de Chimbote – Programación Visual II JFormattedTextField pierda el foco, por ejemplo, cuando se pulsa sobre el editor, validando así los cambios realizados. •

JFormattedTextField.COMMIT_OR_REVERT . Esta es la opción por 

defecto y la más útil. Si el texto introducido es incorrecto, se vuelve automáticamente al último valor bueno conocido. Si el texto no es válido, se muestra el último valor bueno conocido. •

JFormattedTextField.PERSIST. Esta opción no hace nada con el texto

introducido, independientemente de que esté bien o mal. getValue() siempre devolverá el último valor bueno conocido. Para que el editor recoga el nuevo valor, debemos llamar a commitEdit() previamente. Existen varios JFormattedTextField.AbstractFormatter  además de los que podamos hacernos nosotros. Uno de los más conocidos es el MaskFormatter . Este formateador  restringe el texto válido incluso mientras lo estamos tecleando. Al instanciar el MaskFormatter  le damos un "patrón" sobre cómo queremos que sea el texto. Una vez configurado todo, el usuario no podrá escribir en el FormattedTextField nada que se salga de ese "patrón". Veamos con un ejemplo qué quiero decir.

Supongamos que quiero un editor que me permita escribir un número con dos cifras enteras y dos decimales. No queremos que el usuario escriba algo que no sea un número y no queremos que escriba ni más ni menos de las cifras de las indicadas. El editor debe admitir y devolvernos con setValue() y getValue() un Float.

Para conseguir esto, basta instanciar un MaskFormatter y pasárselo al JFormattedTextField en el constructor. Para evitar problemas, le damos un valor  válido inicial válido al editor. El new MaskFormatter lanza una excepción, así que debemos capturarla. try { /* El "patrón" para el editor. Las # representan cifras. En la API puedes ver más. Ojo con el punto decimal, según el idioma puede ser una coma.*/ MaskFormatter mascara = new MaskFormatter("##.##");

Ing. Martín Salcedo Quiñones

Página 11

Universidad Católica Los Ángeles de Chimbote – Programación Visual II // Se construye el JFormattedTextField pasándole la máscara JFormattedTextField textField = new JFormattedTextField(mascara); // Se da un valor inicial válido para evitar problemas textField.setValue(new Float("12.34")); } catch (...)

Ya está listo. Nuestro editor sólo admite números de dos cifras enteras y dos decimales y no nos deja escribir otra cosa. Los métodos getValue() y setValue() devuelven y admiten Floats.

Ing. Martín Salcedo Quiñones

Página 12

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF