Soporte Java para el desarrollo de GUIs Interfaces gráficas de usuario (2): Swing Swing Programación Orientada a Objetos Facultad de Informática AWT Soporte nativo para GUIs Juan Pavón Mestras Dep. Sistemas Informáticos y Programación Universidad Complutense Madrid Juan Pavón Mestras Facultad de Informática UCM, 2004 Una aplicación Swing sencilla ! ! ! Cuando el usuario texto la aplicación Cuando el usuario texto la aplicación Cuando el usuario terminar Java Swing 2 Una aplicación Swing sencilla El comportamiento deseado para esta aplicación es: ! Swing utiliza el modelo de eventos basado en delegación de AWT (definido a partir de Java 1.1) ! pulsa en el botón Dí Hola, en el campo de ha de poner 'Hola' pulsa en el botón Dí Adios, en el campo de ha de poner 'Adios' cierra la ventana, la aplicación ha de El diseño de toda interfaz conlleva, a grandes rasgos, los siguientes pasos: ! Decidir la estructura de la interfaz • Qué componentes gráficos se van a utilizar, y cómo se van a relacionar estos componentes) ! Decidir la disposición (layout) de los componentes • Existen dos tipos de componentes: contenedores y componentes atómicos • Los contenedores sirven para organizar los componentes contenidos en los mismos. Esta organización se denomina disposición (o layout) ! Decidir el comportamiento de la interfaz: gestión de eventos • Algunos componentes son controles: permiten reaccionar ante eventos del usuario. El comportamiento se especifica programando las respuestas a dichos eventos. Normalmente, dichas respuestas supondrán invocar funcionalidades de la lógica de la aplicación • Conviene mantener la interfaz y la lógica lo más independientes posibles (veremos patrones que permiten lograr esto) Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 3 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 4 Una aplicación Swing sencilla: estructura Una aplicación Swing sencilla: estructura import importjavax.swing.*; javax.swing.*; Loro (JFrame) public publicclass classLoro Loroextends extendsJFrame JFrame{{ private privateJTextField JTextFieldeco; eco; public publicLoro() Loro(){{ setTitle("Loro"); setTitle("Loro"); Panel Principal (JSplitPane) Botonera (JPanel) Hola (JButon) Juan Pavón Mestras Facultad de Informática UCM, 2004 Ordena la redimensión y la disposición de toda la jerarquía de componentes en la ventana Eco (JTextField) Adios (JButon) Java Swing 5 Una aplicación Swing sencilla: estructura Facultad de Informática UCM, 2004 Java Swing 6 Una aplicación Swing sencilla: estructura private privateJComponent JComponentcreaBotonera() creaBotonera(){{ JPanel JPanelbotonera botonera==new newJPanel(); JPanel(); ////Se Secrean creanlos losbotones botones...... JButton JButtonhola hola==new newJButton("Dí JButton("DíHola"); Hola"); JButton JButtonadios adios==new newJButton("Dí JButton("DíAdios"); Adios"); ////....yyseseañaden añadenalalpanel panel botonera.add(hola); botonera.add(hola); botonera.add(adios); botonera.add(adios); return returnbotonera; botonera; }} ////...... }} ////...... Juan Pavón Mestras JComponent JComponentbotonera botonera==creaBotonera(); creaBotonera(); JComponent JComponenteco eco==creaEco(); creaEco(); ////Crea Creapanel panelcon conbotonera botonerayyeco eco JSplitPane JSplitPanepanelPrincipal panelPrincipal== new JSplitPane(JSplitPane.VERTICAL_SPLIT,botonera,eco); new JSplitPane(JSplitPane.VERTICAL_SPLIT,botonera,eco); ////Añade Añadeelelpanel panelaalalaventana ventanaprincipal principal getContentPane().add(panelPrincipal); getContentPane().add(panelPrincipal); ////Se 'redimensiona' toda la interfaz Se 'redimensiona' toda la interfazgráfica gráficaen enlalaventana ventana pack(); pack(); ////YYhace hacevisible visiblelalaventana, ventana,con consus suscomponentes componentes setVisible(true); setVisible(true); }} public publicstatic staticvoid voidmain(String[] main(String[]args) args){{ Loro Loroloro loro==new newLoro(); Loro(); //... //...aquí aquítermina terminalalaejecución ejecucióndel del'hilo 'hiloprincipal', principal', ////......pero peroqueda quedapendiente pendientelalaejecución ejecucióndel delhilo hilode de ////......tratamiento tratamientode deeventos... eventos...AApartir partirde deahora ahoratoda todalala ////......ejecución ejecuciónesesgobernada gobernadapor porlalainteracción interaccióncon conelelusuario. usuario. }} private privateJComponent JComponentcreaEco() creaEco(){{ ////Se Secrea creaelelcampo campode detexto textodonde dondeponer ponereleleco eco eco = new JTextField("Pulsa eco = new JTextField("Pulsaun unbotón"); botón"); return returneco; eco; }} Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 7 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 8 Una aplicación Swing sencilla: comportamiento ! ! ! Una aplicación Swing sencilla: comportamiento Los controles señalizan eventos Diferentes tipos de eventos, dependiendo de los controles La forma de tratar eventos en Swing (y en AWT, a partir de JDK 1.1) es mediante un mecanismo denominado delegación: ! ! ! ! OyenteHola actionPerformed (ActionEvent ev) Por cada tipo de evento notificado por un control, el control acepta un oyente de dicho evento (métodos addXXXListener) Dicho oyente ha de implementar una interfaz adecuada (XXXListener) Cuando se produce un evento, el control invoca un método apropiado del oyente. Es en este método donde se trata el evento OyenteAdios actionPerformed (ActionEvent ev) OyenteVentana Estas clases están declaradas en el paquete java.awt.event windowClosing (WindowEvent ev) import java.awt.event.*; Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 9 Una aplicación Swing sencilla: comportamiento asociado a los botones Java Swing 10 addWindowListener( addWindowListener( new newWindowAdapter() WindowAdapter(){{ public publicvoid voidwindowClosing(WindowEvent windowClosing(WindowEventev) ev){{ ////Se Setermina terminalalaejecución ejecuciónde delalaaplicación aplicación System.exit(0); System.exit(0); }} }); }); ////...... ////....yyseseañaden añadenalalpanel panel botonera.add(hola); botonera.add(hola); botonera.add(adios); botonera.add(adios); return returnbotonera; botonera; Java Swing Terminar la ejecución public publicLoro() Loro(){{ setTitle("Loro"); setTitle("Loro"); JButton JButtonadios adios==new newJButton("Dí JButton("DíAdios"); Adios"); adios.addActionListener( adios.addActionListener( new newActionListener() ActionListener(){{ public publicvoid voidactionPerformed(ActionEvent actionPerformed(ActionEventev) ev){{ eco.setText("Adios!"); eco.setText("Adios!"); }}); }}); }} Escribir adios en el campo de texto Una aplicación Swing sencilla: comportamiento asociado a la ventana principal private privateJComponent JComponentcreaBotonera() creaBotonera(){{ JPanel JPanelbotonera botonera==new newJPanel(); JPanel();////Panel Panelpara paracontener contenerlos losbotones botones ////Se crean los botones ... Se crean los botones ... JButton JButtonhola hola==new newJButton("Dí JButton("DíHola"); Hola"); hola.addActionListener( hola.addActionListener( new newActionListener() ActionListener(){{ public publicvoid voidactionPerformed(ActionEvent actionPerformed(ActionEventev) ev){{ eco.setText("Hola!"); eco.setText("Hola!"); }}); }}); Juan Pavón Mestras Facultad de Informática UCM, 2004 Juan Pavón Mestras Facultad de Informática UCM, 2004 Escribir hola en el campo de texto 11 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 12 Funcionamiento de las aplicaciones con GUI en Java ! ! ! ! Java es, por diseño, un lenguaje multiproceso: en un programa Java pueden existir (y de hecho existen) simultáneamente múltiples hilos de ejecución (threads) concurrentes Uno de estos hilos es el hilo de tratamiento de eventos En las aplicaciones con GUI, el hilo principal se limita a construir la estructura de la GUI, a asociar los oyentes adecuados con los controles y, hecho esto, termina … … pero la aplicación en sí no termina, puesto que todavía queda, al menos, un hilo con vida: el de tratamiento de eventos ! ! ! ! ! ! Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 14 JFrame import importjava.awt.Color; java.awt.Color; import importjava.awt.Dimension; java.awt.Dimension; import importjava.awt.BorderLayout; java.awt.BorderLayout; import importjava.awt.event.WindowAdapter; java.awt.event.WindowAdapter; import importjava.awt.event.WindowEvent; java.awt.event.WindowEvent; import importjavax.swing.JFrame; javax.swing.JFrame; import importjavax.swing.JLabel; javax.swing.JLabel; import importjavax.swing.JMenuBar; javax.swing.JMenuBar; Toda aplicación Swing tiene, al menos, un contenedor raíz (una ventana) La clase JFrame proporciona ventanas al uso (aunque puede haber otro tipo de ventanas) A su vez, JFrame incluye una serie de elementos: • • Juan Pavón Mestras Facultad de Informática UCM, 2004 El tratamiento de los eventos debe ser rápido • La ejecución de los oyentes se lleva a cabo en el hilo de tratamiento de eventos: si tal ejecución tarda mucho, o se bloquea, bloquea a dicho hilo, que no puede tratar el resto de eventos rutinarios, por lo que la aplicación en sí se bloquea, y no responderá • Si un tratamiento de un evento necesita mucho tiempo para ser realizado, una solución puede ser crear otro hilo que lo lleve a cabo (no es sencillo porque aparecen los problemas de sincronización de hilos) JFrame ! La aplicación avanza guiada por los eventos del usuario Cuando, desde el código de la aplicación, se realizan cambios sobre la interfaz (p.ej. cambiar el texto de una etiqueta, dibujar algo, limpiar un cuadro de texto, etc.) tales cambios no son inmediatos, sino que se encolan (en estructuras internas del framework AWT/Swing) para ser procesados por el hilo de tratamiento de eventos una vez que termine la ejecución del código del oyente que ha provocado los cambios • La ejecución de métodos que cambian la presentación de componentes no debe interpretarse como ejecuciones, sino como promesas de ejecuciones (que se realizarán cuando sea posible) 13 Java Swing Consecuencias del funcionamiento: ! Este hilo se encarga de tratar automáticamente eventos rutinarios (p.ej. redibujar una ventana cuando ésta pasa a primer plano, o cuando se quita una ventana que la ocultaba parcialmente, actualizar la presentación como resultado de cambios ordenados por la aplicación, etc.) … y también se encarga de tratar los eventos de usuario, invocando a los oyentes previamente registrados Juan Pavón Mestras Facultad de Informática UCM, 2004 ! Funcionamiento de las aplicaciones con GUI en Java Java Swing Los contenidos se añaden en el panel de contenidos (content pane) accesible a través del método getContentPane (por defecto, un objeto de tipo Jpane, aunque puede cambiarse con setContentPane). La barra de menú puede fijarse con setJMenuBar public publicclass classTopLevelDemo TopLevelDemo{{ public publicstatic staticvoid voidmain(String main(Strings[]) s[]){{ JFrame frame = new JFrame("TopLevelDemo"); JFrame frame = new JFrame("TopLevelDemo"); frame.addWindowListener(new frame.addWindowListener(newWindowAdapter() WindowAdapter(){{ public void windowClosing(WindowEvent public void windowClosing(WindowEvente)e){{ System.exit(0); System.exit(0); }} }); }); 15 //... //... Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 16 JFrame JSplitPane y Box: Haciendo layout fácil en Swing JLabel JLabelyellowLabel yellowLabel==new newJLabel(""); JLabel(""); yellowLabel.setOpaque(true); yellowLabel.setOpaque(true); yellowLabel.setBackground(Color.yellow); yellowLabel.setBackground(Color.yellow); yellowLabel.setPreferredSize(new yellowLabel.setPreferredSize(newDimension(200, Dimension(200,180)); 180)); ! El control de la disposición en Swing (y en AWT) se delega en objetos especiales, denominados gestores de disposición (layout managers) ! JMenuBar JMenuBarcyanMenuBar cyanMenuBar==new newJMenuBar(); JMenuBar(); cyanMenuBar.setOpaque(true); cyanMenuBar.setOpaque(true); cyanMenuBar.setBackground(Color.cyan); cyanMenuBar.setBackground(Color.cyan); cyanMenuBar.setPreferredSize(new cyanMenuBar.setPreferredSize(newDimension(200, Dimension(200,20)); 20)); ! Swing ofrece además dos componentes que facilitan la realización del layout: ! frame.setJMenuBar(cyanMenuBar); frame.setJMenuBar(cyanMenuBar); frame.getContentPane().add(yellowLabel, frame.getContentPane().add(yellowLabel,BorderLayout.CENTER); BorderLayout.CENTER); ! }} frame.pack(); frame.pack(); frame.setVisible(true); frame.setVisible(true); Juan Pavón Mestras Facultad de Informática UCM, 2004 Para añadir componentes a un JFrame se añaden componentes a su panel de contenidos Java Swing En AWT vimos diversos tipos de gestores de disposición, que ofrecen mecanismos más o menos sofisticados para organizar los contenidos en un contenedor JSplitPane permite dividir una región en dos subregiones, y asignar a cada una de ellas un peso determinado (que dictará la forma en cómo se repartirá el espacio extra en cada subregión cuando el contenedor crezca) Box permite organizar vertical u horizontalmente componentes, así como especificar espaciado fijo entre ellos, y componentes de glue (componentes invisibles que crecen cuando la caja crece, dejando el resto de los componentes adecuadamente situados) • Combinando JSplitPane y Box es posible especificar layouts complicados, sin necesidad de vérselas con las complejidades de más bajo nivel de los layout managers 17 JSplitPane y Box: Haciendo layout fácil en Swing Juan Pavón Mestras Facultad de Informática UCM, 2004 18 Java Swing JSplitPane y Box: Haciendo layout fácil en Swing JSplitPane peso=1 peso=0 JSplitPane 0 1 JSplitPane 1 Box 0 Box glue Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 19 Juan Pavón Mestras Facultad de Informática UCM, 2004 glue Java Swing 20 JSplitPane y Box: Haciendo layout fácil en Swing JSplitPane y Box: Haciendo layout fácil en Swing public class class LayoutDemo LayoutDemo {{ public public static static void void main(String main(String s[]) s[]) {{ public JButton b1 b1 == new new JButton("Botón JButton("Botón 1"); 1"); JButton JButton b2 b2 == new new JButton("Botón JButton("Botón 2"); 2"); JButton JButton b3 b3 == new new JButton("Botón JButton("Botón 3"); 3"); JButton JLabel e1 e1 == new new JLabel("Etiqueta JLabel("Etiqueta 1"); 1"); JLabel JLabel e2 e2 == new new JLabel("Etiqueta JLabel("Etiqueta 2"); 2"); JLabel Box cajaEtiquetas cajaEtiquetas == Box.createVerticalBox(); Box.createVerticalBox(); Box cajaEtiquetas.add(e1); cajaEtiquetas.add(e1); cajaEtiquetas.add(e2); cajaEtiquetas.add(e2); cajaEtiquetas.add(Box.createVerticalGlue()); cajaEtiquetas.add(Box.createVerticalGlue()); Box cajaBotones cajaBotones == Box.createVerticalBox(); Box.createVerticalBox(); Box cajaBotones.add(b1); cajaBotones.add(b1); cajaBotones.add(b2); cajaBotones.add(b2); cajaBotones.add(b3); cajaBotones.add(b3); cajaBotones.add(Box.createVerticalGlue()); cajaBotones.add(Box.createVerticalGlue()); Las cajas se crean con los métodos estáticos createHorizontalBox y createVerticalBox de Box. JSplitPane panelSecundario1 panelSecundario1 == JSplitPane new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new new JPanel(), JPanel(), new cajaEtiquetas); cajaEtiquetas); panelSecundario1.setDividerSize(1); panelSecundario1.setDividerSize(1); panelSecundario1.setResizeWeight(1); panelSecundario1.setResizeWeight(1); JSplitPane panelSecundario2 panelSecundario2 == JSplitPane new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new cajaBotones, cajaBotones, panelSecundario1); panelSecundario1); panelSecundario2.setDividerSize(1); panelSecundario2.setDividerSize(1); El glue se crea con los métodos estáticos de Box createVerticalBox y createHorizontalBox. Con createHorizontalStrut y createVerticalStrut puede introducirse espacios fijos entre los componentes Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 21 JSplitPane y Box: Haciendo layout fácil en Swing Juan Pavón Mestras Facultad de Informática UCM, 2004 22 Botones ! JSplitPane panelPrincipal panelPrincipal == JSplitPane new JSplitPane(JSplitPane.VERTICAL_SPLIT, JSplitPane(JSplitPane.VERTICAL_SPLIT, new panelSecundario2, panelSecundario2, new JPanel()); JPanel()); new panelPrincipal.setDividerSize(1); panelPrincipal.setDividerSize(1); panelPrincipal.setResizeWeight(1); panelPrincipal.setResizeWeight(1); ! Los botones, junto con los menús, son los controles más típicos en una GUI Existen diferentes tipos (especializaciones de AbstractButton) ! ! JFrame frame frame == new new JFrame("LayoutDemo"); JFrame("LayoutDemo"); JFrame JButton: Botón aislado. Puede pulsarse, pero su estado no cambia JToggleButton : Botón seleccionable. Cuando se pulsa el botón, su estado pasa a seleccionado, hasta que se pulsa de nuevo (entonces se deselecciona) • isSelected() permite chequear su estado frame.addWindowListener(new WindowAdapter() WindowAdapter() {{ frame.addWindowListener(new public void void windowClosing(WindowEvent windowClosing(WindowEvent e) e) {{ public System.exit(0); System.exit(0); }} }); }); ! ! frame.setContentPane(panelPrincipal); frame.setContentPane(panelPrincipal); frame.pack(); frame.pack(); frame.setVisible(true); frame.setVisible(true); }} JCheckBox : Especialización de JToggleButton que implementa una casilla de verificación. Botón con estado interno, que cambia de apariencia de forma adecuada según si está o no está seleccionado JRadioButton: Especialización de JToggleButton que tiene sentido dentro de un mismo grupo de botones (ButtonGroup) que controla que sólamente uno de ellos está seleccionado • Nota: ButtonGroup es únicamente un controlador, no un componente) ! }} Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing Java Swing 23 El evento semántico más común anunciado por los botones es ActionEvent Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 24 Botones Botones Box caja caja == Box.createHorizontalBox(); Box.createHorizontalBox(); Box caja.add(new JButton("Un JButton("Un botón botón normal")); normal")); caja.add(new caja.add(new JToggleButton("Un botón seleccionable")); seleccionable")); caja.add(new JToggleButton("Un botón caja.add(new JToggleButton("Otro JToggleButton("Otro botón botón seleccionable",true)); seleccionable",true)); caja.add(new caja.add(new JCheckBox("Cine")); JCheckBox("Cine")); caja.add(new caja.add(new JCheckBox("Teatro")); JCheckBox("Teatro")); caja.add(new caja.add(new JCheckBox("Música")); JCheckBox("Música")); caja.add(new ButtonGroup grupo new ButtonGroup(); ButtonGroup(); ButtonGroup grupo == new JRadioButton r1 r1 == new new JRadioButton("Hombre"); JRadioButton("Hombre"); JRadioButton JRadioButton r2 r2 == new new JRadioButton("Mujer"); JRadioButton("Mujer"); JRadioButton JRadioButton r3 r3 == new new JRadioButton("Asexuado"); JRadioButton("Asexuado"); JRadioButton Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 25 Menús grupo.add(r1); grupo.add(r1); grupo.add(r2); grupo.add(r2); grupo.add(r3); grupo.add(r3); caja.add(r1); caja.add(r1); caja.add(r2); caja.add(r2); caja.add(r3); caja.add(r3); Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 26 Menús • La creación de una barra de menús básica supone: • Crear un objeto de tipo JMenuBar. • Para cada entrada, crear un objeto de tipo JMenu. • Incluir objetos de tipo JMenuItem en el menú. Esto puede incluir menús anidados. • Asociar a los items acciones apropiadas (notifican eventos semánticos de tipo ActionEvent, ya que, en realidad, especializan a AbstractButton). • Con setJMenuBar es posible añadir una barra de menús a una ventana (JFrame). • Importante: En una GUI, muchas veces existen controles ligados a la misma acción (eg. un botón que hace lo mismo que un item de un menú). En este caso ambos controles pueden compartir el mismo oyente (y es aconsejable hacerlo así). • Más importante aún: El diseño de una barra de menús debe ser consistente (poner opciones semánticamente relacionadas juntas). Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 27 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 28 Menús Menús JMenu menu11 menu11 == new new JMenu("Submenú"); JMenu("Submenú"); JMenu menu11.add(new JMenuItem("Opción JMenuItem("Opción 1")); 1")); menu11.add(new menu11.add(new JMenuItem("Opción JMenuItem("Opción 2")); 2")); menu11.add(new menu1.add(menu11); menu1.add(menu11); barra.add(menu1); barra.add(menu1); barra.add(new JMenu("Menú JMenu("Menú 2")); 2")); barra.add(new setJMenuBar(barra); setJMenuBar(barra); pack(); pack(); setVisible(true); setVisible(true); public class class PruebaMenu PruebaMenu extends extends JFrame JFrame {{ public public void void ejecuta() ejecuta() {{ public JMenuBar barra barra == new new JMenuBar(); JMenuBar(); JMenuBar JMenu menu1 menu1 == new new JMenu("Menú JMenu("Menú 1"); 1"); JMenu menu1.add(new JMenuItem("Una JMenuItem("Una opción opción de de texto")); texto")); menu1.add(new menu1.add(new JSeparator()); JSeparator()); menu1.add(new ButtonGroup grupo grupo == new new ButtonGroup(); ButtonGroup(); ButtonGroup JRadioButtonMenuItem r1 r1 == new new JRadioButtonMenuItem("Opción JRadioButtonMenuItem("Opción 1"); 1"); JRadioButtonMenuItem JRadioButtonMenuItem r2 r2 == new new JRadioButtonMenuItem("Opción JRadioButtonMenuItem("Opción 2"); 2"); JRadioButtonMenuItem grupo.add(r1); grupo.add(r1); grupo.add(r2); grupo.add(r2); menu1.add(r1); menu1.add(r1); menu1.add(r2); menu1.add(r2); menu1.add(new JSeparator()); JSeparator()); menu1.add(new menu1.add(new JCheckBoxMenuItem("Selección JCheckBoxMenuItem("Selección 1",true)); 1",true)); menu1.add(new menu1.add(new JCheckBoxMenuItem("Selección JCheckBoxMenuItem("Selección 2")); 2")); menu1.add(new Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing }} public static static void void main(String[] main(String[] args) args) {{ public new PruebaMenu().ejecuta(); PruebaMenu().ejecuta(); new }} }} 29 Interacción modal ! ! ! ! ! ! Java Swing 30 Interacción modal Muchas veces surge la necesidad de lanzar, esporádicamente, ventanas secundarias para indicar algún hecho, o pedir algún dato al usuario: cuadros de diálogo La mayor parte de estas interacciones suelen ser modales (es decir, la ejecución del programa se interrumpe hasta que el usuario cierra el cuadro de diálogo) Swing ofrece la posibilidad de crear diálogos a medida… …pero (afortunadamente), también ofrece la posibilidad de crear/configurar diálogos prefabricados que son útiles en muchas situaciones ¿Cómo funciona la interacción modal?: Swing lanza un hilo adicional para manejar dichas interacciones (y el resto de los eventos rutinarios). El hilo de tratamiento de eventos se sincroniza (espera) la finalización de dicho hilo de interacción modal Importante: Un abuso de la interacción modal conduce a interfaces poco usables (en el límite, a interacciones tipo consola) Juan Pavón Mestras Facultad de Informática UCM, 2004 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing ! La clase JOptionPane ofrece un conjunto de métodos estáticos que lanzan diferentes tipos de diálogos (estos métodos están sobrecargados para poder crear diálogos con diferentes grados de fineza): ! ! ! ! 31 showMessageDialog : Muestra un diálogo de mensaje showConfirmDialog : Muestra un diálogo de confirmación. Permite determinar la opción elegida por el usuario de forma modal (yes, no, cancel) showInputDialog: Muestra un diálogo en el que se solicita, de forma modal, una entrada al usuario. Dependiendo de la versión de método utilizada, el usuario puede teclear la entrada, o bien seleccionarla de una lista de entradas disponibles showOptionDialog: Muestra un diálogo que puede personalizarse con botones (en general, con componentes) a medida Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 32 Interacción modal Interacción modal JOptionPane.showMessageDialog(this, // // La La ventana ventana padre. padre. JOptionPane.showMessageDialog(this, "Error deconocido!: deconocido!: Lo Lo llevas llevas muy muy mal!", mal!", //El //El mensaje. mensaje. "Error "Error", // // El El título título de de la la ventana ventana de de diálogo. diálogo. "Error", JOptionPane.ERROR_MESSAGE // // El El tipo tipo de de mensaje mensaje JOptionPane.ERROR_MESSAGE ); ); int seleccionada seleccionada == int JOptionPane.showConfirmDialog(this, JOptionPane.showConfirmDialog(this, "Lo aceptas?", aceptas?", "Aviso", "Aviso", "Lo JOptionPane.YES_NO_OPTION, // // Configuración Configuración del del mensaje mensaje JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); JOptionPane.INFORMATION_MESSAGE); switch(seleccionada) {{ switch(seleccionada) case JOptionPane.YES_OPTION: JOptionPane.YES_OPTION: ... ... // // tratar tratar SI SI case case JOptionPane.NO_OPTION: JOptionPane.NO_OPTION: .. .. // // tratar tratar NO NO case case JOptionPane.CLOSED_OPTION: JOptionPane.CLOSED_OPTION: .. .. // // tratar tratar ventana ventana cerrada cerrada case default: ... ... // // esta esta opción opción nunca nunca debería debería alcanzarse alcanzarse default: }} JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this, "Te informo informo de de que que lo lo llevas llevas fatal", fatal", "Info", "Info", "Te JOptionPane.INFORMATION_MESSAGE); JOptionPane.INFORMATION_MESSAGE); int seleccionada seleccionada == int JOptionPane.showConfirmDialog(this, JOptionPane.showConfirmDialog(this, "Lo aceptas?","Aviso", aceptas?","Aviso", "Lo JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); JOptionPane.WARNING_MESSAGE); ... // // los los posibles posibles valores valores devueltos devueltos son son los los anteriores anteriores yy ... ... // // JOptionPane.CANCEL_OPTION JOptionPane.CANCEL_OPTION ... JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this, "Te aviso aviso de de que que lo lo llevas llevas fatal", fatal", "Aviso", "Aviso", "Te JOptionPane.WARNING_MESSAGE); JOptionPane.WARNING_MESSAGE); JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this, Este mensaje mensaje es es para para tí, tí, majete!", majete!", "Mensaje", "Mensaje", Este JOptionPane.PLAIN_MESSAGE); JOptionPane.PLAIN_MESSAGE); Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 33 Interacción modal Java Swing 34 Interacción modal String nombre nombre == JOptionPane.showInputDialog(this, JOptionPane.showInputDialog(this, String "Cómo te te llamas, llamas, majete?", majete?", "Cómo "Petición", JOptionPane.QUESTION_MESSAGE JOptionPane.QUESTION_MESSAGE "Petición", ); ); // ... ... procesar procesar entrada entrada // String[] sexo sexo == {"hetero","homo","bi","auto"}; {"hetero","homo","bi","auto"}; String[] int opcion opcion == int JOptionPane.showOptionDialog(this, JOptionPane.showOptionDialog(this, "Y tú tú qué qué eres?", eres?", "Petición", "Petición", "Y -1, // // opciones->quedan opciones->quedan fijadas fijadas por por el el array array de de opciones opciones -1, JOptionPane.QUESTION_MESSAGE, JOptionPane.QUESTION_MESSAGE, null,//icono. no no hay. hay. null,//icono. sexo, // // array array de de opciones opciones sexo, sexo[0] // // opcion opcion inicial inicial sexo[0] ); ); ... // // procesamiento procesamiento de de la la opcion opcion ... ... ... String[] colores colores == {"rojo","negro","amarillo", {"rojo","negro","amarillo", String[] "azul","majenta"}; "azul","majenta"}; Object opcion opcion == Object JOptionPane.showInputDialog(this, JOptionPane.showInputDialog(this, "Selecciona un un color, color, resalao!", resalao!", "Petición", "Petición", "Selecciona JOptionPane.QUESTION_MESSAGE, JOptionPane.QUESTION_MESSAGE, null, //icono. //icono. no no hay. hay. null, colores, // // opciones. opciones. Se Se le le podría podría pasar pasar un un array array de de colores, // objetos objetos arbitrarios arbitrarios // colores[0] //opción //opción inicial inicial colores[0] ); ); // ...procesar ...procesar opción... opción... // Juan Pavón Mestras Facultad de Informática UCM, 2004 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 35 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 36 Interacción modal: selección de archivos ! ! Interacción modal: selección de archivos Los diálogos de tipo JFileChooser facilitan esta tarea La forma habitual de trabajar con JFileChooser es: ! ! ! selector = new JFileChooser(); selector.setFileFilter(new FiltroTexto()); selector.setFileSelectionMode(JFileChooser.FILES_ONLY); selector.setCurrentDirectory(new File(System.getProperty("user.dir"))); Crear una instancia de JFileChooser. Configurar dicha instancia de forma adecuada. Dicha configuración, normalmente, se limita a poner filtros sobre lo que puede seleccionarse con el selector de ficheros, así como a fijar la carpeta actual (con setCurrentDirectory): • Con setFileSelectionMode. • Con setFileFilter : Aquí debe añadirse una instancia de una subclase adecuada de FileFilter. ! ! La interacción es modal: los métodos show devuelven el estado de la operación. Si todo ha ido bien, el método getSelectedFile devuelve un objeto de tipo File, que debe ser tratado de forma adecuada Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 37 Interacción modal: selección de archivos ! Un filtro de ficheros class classFiltroTexto FiltroTextoextends extendsFileFilter FileFilter{{ public publicboolean booleanaccept(File accept(Filef)f){{ String Stringnombre nombre==f.getName(); f.getName(); return nombre.substring(Math.max(nombre.length()-4,0)).equals(".txt"); return nombre.substring(Math.max(nombre.length()-4,0)).equals(".txt"); }} public publicString StringgetDescription() getDescription(){{ return return"Ficheros "Ficherosde detipo tipotexto"; texto"; }} }} Mostrar un selector de ficheros utilizando alguno de los siguientes métodos: • showDialog : Selector a medida. • showOpenDialog : Selector para abrir un fichero. • showSaveDialog : Selector para salvar un fichero. ! Creación y configuración de un selector Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 38 Interacción modal: selección de archivos El mismo selector permite crear diferentes diálogos de selección Uso habitual de un diálogo creado a través de un FileChooser selector.showOpenDialog(this) if ( selector.showOpenDialog(this) == JFileChooser.APPROVE_OPTION ) { File f = selector.getSelectedFile(); // Hacer lo que sea pertinente con el fichero ... } selector.showSaveDialog(this) Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 39 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 40 Otros contenedores Swing ! JPanel. Un contenedor intermedio genérico ! ! ! ! Otros componentes atómicos Swing ! Se utiliza para poner otros componentes FlowLayout por defecto (los componentes se colocan uno detrás de otro) ! ! JScrollPane. Un panel con barras de scroll JTabbedPane. Un panel con diferentes vistas ! ! ! ! ! JLabel. Etiquetas JTextField. Entrada de una línea de texto JTextArea. Entradas de varias líneas de texto JSlider. Una barra de selección en una escala JList. Una lista de elementos seleccionables JComboBox. Una lista de elementos desplegable JPopupMenu. Un menú desplegable JToolBar. Una barra de herramientas Puede cambiarse de situación por los bordes de su contenedor e incluso llevarse fuera ! Las herramientas suelen ser (aunque no obligatoriamente) botones Juan Pavón Mestras ! Facultad de Informática UCM, 2004 Java Swing 41 Juan Pavón Mestras Facultad de Informática UCM, 2004 Java Swing 42