Beruflich Dokumente
Kultur Dokumente
Objetivo: Aportar:
un framework que permita la creacin elegante de:
x x x x aplicaciones con interfaz de usuario ricas basadas en estndares altamente configurables Integrable con el framework Spring
Una librera rica de componentes para el desarrollo de interfaces de usuario Un conjunto de clases de soporte
` `
Subproyecto del framework de Spring Idea base: Dar soporte para el desarrollo de aplicaciones Swing El xito de Spring RCP consiste en aportar una opcin viable para desarrolladores en forma de
Una plataforma Un conjunto de buenas prcticas
Swing es una biblioteca grfica para Java que forma parte de las Java Foundation Classes (JFC). Incluye widgets para interfaz grfica de usuario tales como
cajas de texto Botones Desplegables tablas. Otros
import javax.swing.*; public class Main{ private static void mostrarVentana() { JFrame frame = new JFrame(Nuestra primera ventana"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel(Este es nuestro primer programa con Swing"); frame.getContentPane().add(label); frame.setVisible(true); } public static void main(String[] args) { mostrarVentana(); } }
public class Main implements ActionListener{ private static int numero_clicks = 0; JButton boton; JLabel label = new JLabel(); private void mostrarVentana() { JFrame frame = new JFrame("Nuestra primera ventana"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); boton= new JButton("Comienza a dar click!"); JPanel panel = new JPanel(); panel.add(boton); panel.add(label); frame.getContentPane().add(panel); frame.setVisible(true); boton.addActionListener(this); } public void actionPerformed(ActionEvent ae) { numero_clicks++; label.setText("Numero de clicks: "+ numero_clicks); } public static void main(String[] args) { (new Main()).mostrarVentana(); } }
Un framework de comandos para la gestin de acciones y eventos Swing asociados a vistas Gestin y validacin de formularios para enlazar automticamente la interfaz del usuario con el modelo Soporte para
Gestin mltiple de ventanas Configuracin de pginas Gestin de vistas o persepectivas
Project @sourceforge
Java Swing application framework built on the Spring Framework with the goal of simplifying whats required to build professional, enterpriseready rich client applications.
` ` ` ` ` `
Home: http://sf.net/projects/spring-rich-c/ Dev-List: springframework-rcp-dev@lists.sourceforge.net Issues: http://opensource2.atlassian.com/projects/spring/browse/RCP Wiki:http://opensource2.atlassian.com/confluence/spring/display/ RCP Forum: http://forum.springframework.org/ CVS
http://cvs.sourceforge.net/viewcvs.py/spring-rich-c/spring-richclient/ -d :pserver:anonymous@cvs.sf.net:/cvsroot/spring-rich-c
Nos bajamos el proyecto eclipse piloto-rcp-0.0 de la pgina del curso. Importamos el proyecto desde Eclipse.
Vamos a comenzar creando una aplicacin simple que se limite a mostrar una vista (pantalla) con un mensaje. Spring RCP se basa en Spring, y lo que nos aporta es una implementacin formada por un conjunto de beans preparados para ser cableados entre s. Para obtener la funcionalidad bsica, vamos a necesitar declarar y cablear unos cuantos beans que forman la infraestructura de cualquier proyecto Spring RCP.
` `
` org.springframework.richclient.application.Application
Es el bean principal que define la aplicacin real. Tiene que llamarse forzosamente application porque es lo que se espera el lanzador de aplicaciones. Est implementado por la clase:
Tiene dos constructores, uno con dos argumentos y otro que slo recibe:
org.springframework.richclient.application.config.Applicat ionLifecycleAdvisor.
` `
Editar el fichero application-context.xml (es el beans.xml de Spring renombrado) ste fichero es el corazn de una aplicacin SRCP. Examinar la declaracin del bean application:
Esta declaracin est an incompleta, dado que vamos a usar el constructor que recibe dos parmetros.
Un Advisor de ciclo de vida es un bean que, AOP mediante, ser invocado en diferentes estapas del ciclo de vida de la aplicacin, como onStartup, onClose, etc. SRCP nos aporta una clase abstracta que implementa ya el advisor por defecto para el ciclo de vida, ApplicationLifecyclceAdvisor . Dado que es abstracta, debemos extenderla con nuestra propia clase y usar un bean de sta como parmetro para el constructor para el bean application.
Entre otras cosas, este bean va a especificar cual es la vista por defecto de la aplicacin que estamos desarrollando. La recibe en un parmetro startingPageId que espera como valor una referencia a un bean declarado que represente una vista.
` ` ` ` `
Las vistas en SRCP llevan por detrs una clase que las implementa. Una clase vista deber extender la clase AbstractView, lo que le fuerza a implementar el mtodo createControl(). ste devuelve un JComponent (swing) que supone el componente visual en s que ser representado. Para que SRCP lo considere una vista de la aplicacin, debemos declararla como tal en el application-context.xml. Para esto, damos de alta un bean que implemente la clase DefaultViewDescriptor y le pasamos como parmentro viewClass la clase que implementa la vista
En primer lugar, vamos a crear la clase es.uniovi.si.MiVista que extienda AbstractView. Implementamos el createControl() para que retorne una Jlabel con un mensaje de Hola Mundo
JLabel etiqueta = new Jlabel(); etiqueta.setText(Hola Mundo del SRCP!"); return etiqueta ;
<bean name="applicationLifecycleAdvisor" class="es.uniovi.si.PilotoLifecycleadvisor"> <property name="startingPageId"> <value>welcomePage</value> </property> </bean> <bean name="welcomePage" class="org.springframework.richclient.application.support. DefaultViewDescriptor"> <property name="viewClass"> <value>es.uniovi.si.MiVista</value> </property> </bean>
Funcionalmente, ya tenemos nuestra vista implementada. No obstante, SRCP requiere otros dos elementos para poder realizar su trabajo:
El bean serviceLocator El bean applicationServices
Es el bean responsable de localizar los servicios de aplicacin que realmente implementan la lgica de negocio del sistema. Implementa uno de los JEE Core Design Patterns. Para darlo de alta (consultar la declaracin):
La clase
org.springframework.richclient.application.support.De
implementa algunos servicios por defecto que son habitualmente necesarios en las aplicaciones. Por ejemplo, la carga de recursos de imagen
faultApplicationServices
` `
Ya estamos listos para usar Spring RCP. Creamos es.uniovi.si.Main y en su mtodo main,
Resuelto en piloto-rcp-1.0
Extender la versin anterior para que contenga una nueva vista verLibrosPage implementada por la clase es.uniovi.si.VerLibrosVista que contenga un JPanel y ste dos etiquetas con sendos mensajes de bienvenida. Pasos:
Implementamos VerLibrosVista:
JPanel panel = new JPanel(); panel.add(new JLabel("Bienvenido a mi aplicacin SRCP")); panel.add(new JLabel("Hola!")); return panel;
Damos de alta el bean Lo ponemos como vista por defecto. Resuelto en piloto 2.0
Spring RCP permite (obliga!) a tener declarado un resource bundle con las cadenas de texto de la aplicacin. Para esto:
Creamos el fichero en ui Lo declaramos en el application-context.xml
En ste estn ` Para declararlo: dadas de alta <bean id="messageSource" cadenas por class="org.springframework.context.support.ResourceBundleMessageSou defecto.
Para que SpringRCP procese el fichero de recursos, es necesario dar de alta otro bean, el applicationObjectConfigurer, y pasrselo al applicationServices como parmetro.
<bean id="applicationServices" class="org.springframework.richclient.application.support.Defaul tApplicationServices" > <property name="applicationObjectConfigurerId"> <idref bean="applicationObjectConfigurer" /> </property> </bean> <bean id="applicationObjectConfigurer" dependson="serviceLocator" class="org.springframework.richclient.application.config.Defau ltApplicationObjectConfigurer"> </bean>
En el fichero de rescursos, vamos a dar de alta las siguientes propiedades para las vistas:
Label Caption Message
` `
Ejemplo:
welcomePage.label = Bienvenido!
En aplicaciones swing complejas es conveniente aplicar algn framework de comandos que simplifique la gestin de la interfaz de usuario Estos frameworks suelen extender la funcionalidad bsica de Spring, dando soporte a la creacin, gestin y configuracin de:
Barras de men Barras de herramientas Mens emergentes
El SRCCF aporta:
Comandos accionables, aplicados habitualmente para el desarrollo de comandos locales (el comportamiento no depende de la vista) Comandos Targeteables (Objetivables?) o globales. Comandos que en tiempo de ejecucin pueden variar su comportamiento dependiendo de la vista en la que se encuentren Agrupaciones de Comandos. Sistema de configuracin de comandos (acciones asociadas, etiquetas, tooltips, iconos, etc.)
` `
El framework de comandos de SRCP basa su configuracin en el fichero commands-context.xml Es un fichero estndar de configuracin para un BeanFactory de Spring donde declararemos la estructura de menuBar y toolBar de nuestra aplicacin cableando diferentes beans. La ubicacin de ste fichero se inyecta al ApplicationLifecycleAdvisor durante la inicializacin del objeto:
<property name="windowCommandBarDefinitions" value="ui/commands-context.xml"/>
<bean name="applicationLifecycleAdvisor" class="es.uniovi.si.PilotoLifecycleAdvisor"> <property name="windowCommandBarDefinitions" value="ui/commandscontext.xml"/> <property name="startingPageId"> <value>verLibrosPage</value> </property> </bean>
Un men o una barra de herramientas se implementa mediante un bean de tipo CommandGroupFactoryBean. En la propiedad members (de tipo list) vamos dando de alta sus opciones o submens. Puede ser:
Un comando global Un comando local Un separador Otro bean de tipo CommandGroupFactoryBean
Vamos a dar de alta un men con una opcin fileMenu que contenga anidadas los comandos globales predefinidos:
propertiesCommand deleteCommand
<bean id="fileMenu" class="org.springframework.richclient.command.CommandGroup FactoryBean"> <property name="members"> <list> <value>separator</value> <value>propertiesCommand</value> <value>separator</value> <value>deleteCommand</value> <value>separator</value> <bean class= "org.springframework.richclient.command.support.ExitComm and"/> </list> </property> </bean>
Para poder usar los dos comandos globales, debemos darlos de alta en el bean windowCommandManager:
<bean id="windowCommandManager" class="org.springframework.richclient.application.supp ort.ApplicationWindowCommandManager"> <property name="sharedCommandIds"> <list> <value>propertiesCommand</value> <value>deleteCommand</value> </list> </property> </bean>
ltimo paso: Tenemos que decirle al lifeCycleAdvisor que el men est implementado por el bean menuBar:
<bean name="applicationLifecycleAdvisor" class="es.uniovi.si.PilotoLifecycleAdvisor"> <property name="startingPageId"> <value>verLibrosPage</value> </property> <property name="windowCommandBarDefinitions" value="ui/commandscontext.xml"/> <property name="menubarBeanName" value="menuBar" /> <property name="windowCommandManagerBeanName value="windowCommandManager" /> </bean>
La etiquetas e iconos por defecto de stos se encuentran empaquetadas en el jar de recursos de Spring RCP, pero podemos sobrescribirlas.
Como hemos visto, SRCP aporta comandos locales predefinidos que podemos incorporar al men referenciando la clase que los implementa (caso de Exit). Hay ms comandos que podemos aprovechar. Ejemplo:
org.springframework.richclient.command.support.NewWindowCommand org.springframework.richclient.command.support.ShowViewMenu org.springframework.richclient.command.support.AboutCommand
Modificar el piloto para que el men tenga una opcin windowMenu en el que se aniden los comandos predefinidos
org.springframework.richclient.command.support.NewWindowCommand org.springframework.richclient.command.support.ShowViewMenu
Los comandos en el men son aplicaciones del patrn command. Podemos aadir nuestros propios comandos al men de la aplicacin. La clase que representa la accin debe implementar la interfaz ActionCommand ActionCommand fuerza a implementar el mtodo doExecuteCommand()
Ser la etiqueta con el que nos referiremos a l en adelante. Damos de alta sus propiedades en el messages.properties Lo insertamos en el men Ventana y lo probamos. Resuelto en piloto 5.0
` `
En el commands-context.xml
<bean id="toolBar" class="org.springframework.richclient.command.CommandGroupFactoryBean"> <property name="members"> <list>
</list> </property>
Aadir la barra de herramientas a la aplicacin, y configurarla para que tenga los comandos globales
Properties Cut Copy Delete
` `
Probar la aplicacin Implementar un nuevo comando es.uniovi.si.comandos.BarraCommand que imprima un mensaje por pantalla. Qu sucede?
Resuelto en piloto 6.0
` `
Para poder utilizar nuestros iconos e imgenes en nuestra aplicacin tenemos que configurar la factora que se encargar de cargarlas a memoria. De esto se encarga el bean imageSource Para incluir una imagen en la aplicacin:
La copiamos al directorio images La asociamos a su objeto en el images.properties.
Vamos a asociar un icono .gif al comando para que se muestre con su representacin grfica en la barra de herramientas. Para ello:
Descargamos los archivos icono2.gif y magnolia.gif al directorio images Editamos el images.properties y asociamos los iconos a los dos comandos que hemos creado y a la aplicacin:
Hasta ahora hemos definido comandos globales en el men y la barra de herramientas, pero permanecen inactivos. La implementacin de estos comandos depende del contexto vista actual-, lo que permite que, por ejemplo, el comando properties no haga lo mismo en una pantalla que en otra. En consecuencia, es cada pgina la que debe registrar su implementacin especfica del comando global.
La clase AbstractView tiene un mtodo protected void registerLocalCommandExecutors(PageComponentContext context) que ser invocado por el contenedor cuando se inicializa la vista. El ste debemos registrar a travs del contexto la implementacin de cada comando global que deseemos asociar en la vista.
El commandId es la cadena que identifica al commando. Los Ids de los comandos globales predefinidos estn declarados en la clase GlobalCommandIds. Ej:
GlobalCommandIds.PROPERTIES
` `
Vamos a asociar una ActionCommandExecutor al comando global propertiesCommand en la pgina MiVista. Para ello:
Declaramos un atributo nuevoLibroExecutor:
private ActionCommandExecutor nuevoLibroExecutor = new NuevoLibroExecutor();
context.register(GlobalCommandIds.PROPERTIES, nuevoLibroExecutor);
Las vistas dentro de las ventanas no tienen porqu estar fijas como hasta ahora. Spring RCP incorpora el framework VLDocking para la gestin de ventanas. Con VLDocking, el usuario puede modificar el layout de las vistas dentro de la ventana de la aplicacin.
El framework VLDocking es un sistema de acoplamiento de ventanas Java para construir aplicaciones JFC Swing Las ventanas acoplables permiten al usuario reorganizar su workspace de acuerdo a sus necesidades, permitiendo:
Drag & Drop las partes dockables de las aplicaciones Minimizar ventanas Hacer ventanas flotantes y desplazarlas fuera de la superficie del workspace Cambiar fcilmente de workspace.
Basta con sobrescribir la declaracin por defecto del bean applicationPageFactory para que a partir de ahora lo implemente el VLDockingApplicationPageFactory
VLDocking permite mapear una configuracin inicial del workspace en un documento XML El framework leer el documento y en base al mismo, inicializar el layout de las vistas dentro de la ventana de la aplicacin.
Para poder utilizar esta caracterstica, basta con aadir el pageFactory haciendo de proxy entre las pginas y el lifycycleAdvisor
<bean id="proxyPage" class="org.springframework.richclient.application.docking.vldocking.VLDock ingPageDescriptor"> <property name="initialLayout"> <bean class="org.springframework.core.io.ClassPathResource"> <constructor-arg type="java.lang.String"> <value>/layouts/vldocking.xml</value> </constructor-arg> </bean> </property> </bean>
<?xml version="1.0"?> <VLDocking version="2.1"> <DockingDesktop name="proxyPage"> <DockingPanel> <Split orientation="1" location="0.2506361323155216"> <Dockable> <Key dockName="verLibrosPage" /> </Dockable> <Split orientation="0" location="0.7484536082474227"> <TabbedDockable> <Dockable> <Key dockName="verLibrosPage" /> </Dockable> <Dockable> <Key dockName="welcomePage" /> </Dockable> </TabbedDockable> <Split orientation="0" location="0.7484536082474227"> <Dockable> <Key dockName="welcomePage" /> </Dockable> </Split> </Split> </Split> </DockingPanel> </DockingDesktop> </VLDocking>
Resuelto en piloto10.0.
` `
Declarar un nuevo id de comando global que se llame miComandoGlobalCommand Asociarlo a la toolBar Asociarlo a la vista de Mensajes de forma similar a lo realizado en el ejercicio anterior. Resuelto piloto 11.0
` ` `
Ahora mismo estamos usando docking views con descriptores de vista DefaultViewDescriptor. La clase VLDockingViewDescriptor extiende la anterior, aadindole ms funcionalidad. Es un bean con las propiedades:
closeEnabled floatEnabled maximizeEnabled autoHideEnabled
Realiza una representacin estndar para un conjunto de objetos, mostrando sus propiedades en las columnas de la tabla. La tabla ofrece las siguientes caractersticas:
Usa Glazed Lists como modelo de datos subyacente. Esto da soporte ordenacin de columnas y filtrado de datos. Permite la seleccin de filas. Permite asociar command executors a eventos como el dobleClick (setDoubleClickHandler(ActionCommandExecutor)) Renderizado de mens popup contextuales. Informa del nmero de filas y del nmero de stas seleccionadas para mostrarlo, por ejemplo, en una barra de estado.
` ` `
Mtodo getControl() -> retorna el JComponent AbstractObjectTable es abstracta, luego debemos extenderla y:
Invocar el constructor del padre pasndole los datos necesarios Sobrescribir el mtodo getDefaultInitialData para que devuelva el conjunto de datos inicial.
Creamos la clase LibroBean (ttulo, autor, editorial y precio) y EditorialBean(nombre y direccin) Creamos la clase Librera que contenga un HashSet, de forma que:
Inicializamos el hashset en el constructor introduciendo dos o tres libros. La librera tenga un mtodo Object [] getAllLibros() que retorne un array con las instancias de LibroBean (hashSet.toArray()). La damos de alta como el bean libreria en Spring
` ` `
Creamos una clase es.uniovi.si.ui.LibroTable que extienda AbstractObjectTable. Declaramos una propiedad de tipo Libreria. Creamos un constructor que:
Reciba la librera como parmetro Invoque al heredado con los parmetros:
x libros (identificador de la tabla)
Establecemos los nombres de las etiquetas para las columnas en el resource bundle.
titulo.label=Ttulo autor.label=Autor editorial.nombre.label=Editorial editorial.direccion.label=Direccin editorial precio.label=Precio
` `
Preparamos VerLibrosVista para recibir LibrosTable por inyeccin dando de alta la propiedad. Programamos createControl para que ...
JPanel panel = new JPanel(); LibrosTable tabla = new LibrosTable(libreria); JScrollPane sp= new JScrollPane( tabla.getControl()); panel.add(sp); return panel;
Retorna un JComponent
Finalmente, inyectamos la librera en la vista, aunque no es una inyeccin al uso, puesto que la clase que lo recibe no es la vista en s sino el descriptor:
<property name="viewProperties"> <map> <entry key="libreria" value-ref="libreria" /> </map>
Ambas acciones tienen que poder acceder al bean seleccionado en la tabla. Para asociarlos, nos servimos de los mtodos:
La AbstractObjectTeble se espera un objeto de tipo CommandGroup. Para insertar en el men, por ejemplo, un comando global:
popup.add((ActionCommand) getWindowCommandManager().getCommand( GlobalCommandIds.PROPERTIES, ActionCommand.class)); Devuelve una instancia del bean windowCommandManager donde damos de alta los comandos globales
` `
Vamos a asociar un men emergente a la tabla que muestre el comando global de properties. Para ello, en el mtodo createControl() de la vista donde instanciamos e inicializamos la tabla:
Creamos un command group.
CommandGroup popup = new CommandGroup();
Lo asociamos a la tabla.
customerTable.setPopupCommandGroup(popup);
` `
Hemos creado el popup pero no tenemos manejador para el comando global propertiesCommand Creamos una inner class PropertiesExecutor que extienda ActionCommandExecutor y muestre un mensaje en un dilogo: Y lo registramos
JOptionPane.showMessageDialog(null, "pulsado...");
`
private ActionCommandExecutor propertiesExecutor = new PropertiesExecutor(); @Override protected void registerLocalCommandExecutors(PageComponentContext context) { context.register(GlobalCommandIds.PROPERTIES, propertiesExecutor); }
Resuelto en 14.0
Implementa un dalogo con un ttulo y un rea para informacin El contenido de los dilogos puede ser gestionado por:
CompositeDialogPage, aplicable cuando trabajamos con varios DialogPages simultneamente FormBackedDialogPage, que es el que vamos a aplicar aqu.
Vamos a crear un dilogo que sustituya al dilogo de swing que tenemos temporalmente asociado al popup de la tabla. Nos basamos en el TitledPageApplicationDialog de SpringRCP
En primer lugar, debemos crear el formulario que dar soporte al dalogo. Para ello:
Creamos es.uniovi.si.form.LibroForm de forma que:
x Extienda AbstractForm x El constructor:
x reciba un LibroBean x Invoque al constructor padre pasndole el libro como referencia. x Ejecute setId(libro).
x Tenga un mtodo createControl que retorne un JPanel vaco. x Establecemos sus etiquetas en el resource bundle:
libro.title=Informacin del libro libro.description=Introduzca los detalles del libro a continuacin.
Una vez creado el form que le da soporte, creamos la clase es.uniovi.si.dialog.LibroPropertiesDialog de forma que:
Extienda la clase TitledPageApplicationDialog Contenga un atributo form de tipo Form El constructor:
x Reciba un LibroBean libro x Instancia un LibroForm y lo almacene en form. x Invoque a setDialogPage pasndole como referencia new FormBackedDialogPage(form)
protected void onAboutToShow() { //La tabla nos devuelve la referencia al LibroBean que hemos pulsado LibroBean libro = (LibroBean) form.getFormModel().getFormObject(); //Construimos un mensaje pasndole como parmetros los datos del libro, y lo asociamos al dilogo String title = getMessage( "libroProperties.edit.title, new Object[]{ libro.getTitulo(),libro.getAutor() }); setTitle(title); }
@Override protected boolean onFinish() { form.getFormModel().commit(); return true; } @Override protected void onCancel() { super.onCancel(); }
Para poder averiguar qu libro ha sido pulsado, nos valdremos del mtodo getSelectedRows() de AbstractObjectTable, que retorna los ndices de los objetos seleccionados. Extendemos la implementacin de LibrosTable implementando el mtodo:
public LibroBean[] getSelectedLibros() { int[] selected = getTable().getSelectedRows(); LibroBean[] libros= new LibroBean[selected.length]; for (int i = 0; i < selected.length; i++) { libros[i] = (LibroBean) getTableModel().getElementAt(selected[i]); } return libros; }
Finalmente, modificamos el mtodo execute() del PropertiesExecutor para que muestre el dilogo que hemos creado:
new LibroPropertiesDialog(tabla.getSelectedLibro()).showDialog()
` `
` `
Nos crean automticamente la representacin swing del formulario. Tienen que estender la clase AbstractFormBuilder Tres tipos implementados:
GridBagLayoutFormBuilder HtmlFormBuilder TableFormBuilder
` `
Mtodo
JComponent[]add(String fieldName)
addTextArea(String fieldName)
addPasswordField(String fieldName)
Vamos a completar el objeto de tipo form que tenemos creado para que refleje los datos del libroBean seleccionado en la tabla Para ello, editamos el LibroForm y en el mtodo createControl:
Instanciamos el TableFormBuilder:
TableFormBuilder formBuilder = new TableFormBuilder(getBindingFactory());
Aadimos un separador para notificar que empieza la seccin de los datos del libro:
formBuilder.addSeparator("General");
Y un salto de lnea:
formBuilder.row();
return formBuilder.getForm();
Modificar la versin actual del piloto para que tenga un comando global newCommand asociado a un Executor NuevoLibroExecutor que implementaremos como una inner class que cree un nuevo libro y lo aada a la tabla. Para ello:
Incluimos newCommand en la barra de herramientas y lo declaramos como comando global. En el ejecutor:
x Instanciamos un nuevo LibroBean (con su correspondiente EditorialBean anidado) x Creamos una nueva instancia de LibroPropertiesDialog pasndole el nuevo libro en blanco que acabamos de construir y lo mostramos. x Una vez retorne el flujo de ejecucin:
x Lo aadimos a la librera. x Lo aadimos a la lista interna de la tabla, a la que accedemos mediante
tabla.getBaseEventList(): tabla.getBaseEventList().add(libro);
` `
Extender la aplicacin para que incorpore un proceso de login al arrancar, y deje pasar al usuario admin/admin. Para ello, implementaremos el mtodo onPostStartup del lifecycleAdvisor, y desde ah, lanzaremos un nuevo dilogo mediante el cual recoger usuario y contrasea. Para ello:
Creamos UsuarioBean Creamos y declaramos el bean Usuarios con Cableamos un usuario bean admin en el bean usuarios Creamos LoginDialog Creamos LoginForm Implementar el onPostStartup y realizar la comparacin de user/password en l. Resuelto en piloto 18.0
x Object getAllUsuarios()
SRCP incorpora su propio sistema de validacin para los datos de entrada en los formularios. Nos permite definir
Restricciones: Las restricciones pueden ser simples, o composiciones (en forma de array) de otras restricciones. Reglas: Conjunto de restricciones que se aplican sobre una determinada clase.
Las reglas se definen un mismo bean que acte como fuente de reglas para toda la aplicacin, que debe extender la clase DefaultRulesSource.
Una restriccin debe implementar la interfaz Constraint boolean test(Object argument) La clase DefaultRulesSource genera ya de por s unas cuantas restricciones estndar, heredadas de ConstraintAccessor. Ejemplos:
public Constraint required() propiedad requerida public Constraint regexp (String expresion) El valor de la propiedad debe cumplir la expresin regular. (java.util.regex) public range ( Comparable min, Comparable max ) El valor de la propiedad debe estar dentro del rango (tambin para integer,long, etc.). minLength(int lenght) & maxLength(int lenght) Para control de longitudes de cadenas de texto. lt(Comparable), lte(Comparable),gt(Comaprable),gte(Comparable),eq(Comparable, Comaparable)
` `
Cuando definimos una regla, a cada campo se le asocia una sola restriccin Para asociar varias restricciones a un campo (ejemplo, requerido y longitud mxima), hay que componerlas en una nueva restriccin. La clase DefaultRulesSource aporta mtodos para esto:
Constraint all(Constrain[]) Se tienen que superar todas Constraint any(Constrain[]) Se tiene que superar alguna Constraint not(Constraint constraint) Negacin Constraint or(Constraint constraint1, Constraint constraint2) - O no exclusiva
private final Constraint NAME_CONSTRAINT = all(new Constraint[]{ required(), minLength(2), regexp("[-'.a-zA-Z ]*")});
Las reglas se materializan en clases que extienden la clase Rules, sobrescribiendo su mtodo initRules() para aadir las restricciones que consideremos necesarias Si queremos crear una regla que aada a la propiedad xx del objeto de clase MiClase la restriccin anterior:
public class MiClaseRules extends Rules { public MiClaseRules ( Class clase ) { super(clase); } @Override protected void initRules() { add(XX", NAME_CONSTRAINT); }; }
Vamos a aadir una serie de reglas sobre las propiedades de LibroBean para que stas entren en funcionamiento cuando damos de alta un libro a travs del formulario. En primer lugar, creamos una clase es.uniovi.si.rules.ValidationRules que extienda DefaultRulesSource Definimos una Constraint ID_CONSTRAINT que aglutine las retricciones de:
Campo requerido Mnima longitud de 5 Mxima longitud de 50 Que su contenido sea alfabtico
Aadir las reglas necesarias para que al hacer login, el usuario y la contrasea cumplan:
Requeridos Longitud mxima de 15 No ser iguales! Ejemplo:
not(eqProperty(propiedad1 ", " propiedad1 "))
Crear una nueva tabla es.uniovi.si.ui.UsuariosTable que se nutra del bean usuarios y mostrarla en welcomePage.
Recapitulando: Un dilogo tena que tener detrs una clase que gestionase el o los formularios que se muestran en l (pgina de dilogo). Tipos de wrapper para los formularios:
FormBackedDialogPage: Gestiona un nico formulario CompositeDialogPage: Para componer ms de un formulario simultneamente en un mismo dilogo
` `
` `
Clase abstracta no la podemos instanciar Implementacin de la interfaz DialogPage que aglutina varias pginas de dilogo de forma que puedan funcionar coordinadamente en una sola. Sus subclases proporcionan diferentes formas de componer grficamente los dilogos que gestiona Subclases:
TabbedDialogPage Compone los dilogos en tabs. TreeCompositeDialogPage Genera un rbol para permitir la navegacin pos los diferentes subdilogos.
Vamos a modificar la versin actual de la aplicacin para que los datos de los libros sean editados en un dilogo compuesto que nos permita separar la parte de la editorial. Para ello:
Creamos un nuevo formulario EditorialForm preparado para editar instancias de EditorialBean Quitamos de LibroForm toda referencia la editorial. Creamos una nueva clase LibroPropertiesCompositeDialog que:
x Extienda TitledPageApplicationDialog x Albergue una referencia a cada tipo de formulario x En el constructor...
x Implementar los mtodos onAboutToShow y inFinish recordando hacer el commit en ambos formularios.
` ` ` ` `
Diseada para representar informacin jerarquizada. Un JTree no contiene el modelo, slo lo muestra, aunque mantiene una referencia al mismo. Los datos se muestran verticalmente Cada fila mostrada contiene un solo elemento de datos denominado nodo. Las expansiones y contracciones de los nodos de un Jtree generan eventos que pueden ser procesados por nuestra aplicacin.
Vamos a reemplazar la tabla que muestra los usuarios por un rbol que tenga el aspecto del de la imagen. Para ello,
Damos de alta al menos un segundo usuario Creamos una nueva clase es.uniovi.si.ui.UsuarioTreeFactory tal que:
x Tenga un mtodo esttico getTree(...) que
x Reciba el bean Usuarios y Retorne un JTree x Construya una jerarqua de DefaultMutableTreeNode que represente el rbol que queremos renderizar.
Creamos el nodo raz y, dado que no tendr correspondencia con ningn objeto del modelo, lo etiquetamos como Usuarios. Luego, para cada UsuarioBean en la lista de usuarios:
x Creamos su correspondiente nodo de tipo DefaultMutableTreeNode:
new
x Creamos dos hijos, uno con el valor de la propiedad nombre y otro con los apellidos, y se los aadimos al nodo al que est ligado el UsuarioBean:
usuarioNode.add(new DefaultMutableTreeNode(usuario.getNombre())); usuarioNode.add(new DefaultMutableTreeNode(usuario.getApellidos()));
DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); JTree tree = new JTree(treeModel); return tree;
Y en MiVista... Probar ahora a aadir justo antes de retornar el JTree. Probamos la aplicacin. Qu sucede?
panel.add(getComponentFactory().createScrollPane( UsuarioTreeFactory.getTree(usuarios)));
tree.setRootVisible(false);
El Jtree invoca el mtodo toString de los objetos de negocio que tiene asociados a los nodos del rbol. En consecuencia, un UsuarioBean, a no ser que tenga sobrescrito el toString, mostrar su referencia. Para arreglarlo, tenemos que desarrollar un objeto TreeCellRenderer que el Jtree consultar antes de mostrar un nodo
Para ello:
Creamos una nueva clase es.uniovi.si.ui.UsuariosTreeCellRenderer que
x Extienda FocusableTreeCellRenderer x Implemente el mtodo:
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {...
Este mtodo es invocado automticamente por el Jtree para cada nodo del rbol que trate de renderizar.
Para los otros, recuperamos el objeto de usuario y, en caso de que sea un UsuarioBean, preparamos su renderizado:
Object userObject = node.getUserObject(); if (userObject instanceof UsuarioBean) { UsuarioBean usuario= (UsuarioBean) userObject; this.setText("Usuario "+usuario.getUser()); } else { this.setText(userObject.toString()); }
JTree es un componente Swing, y como tal notifica sus interacciones con el usuario mediante el disparo de eventos. Acepta diferentes tipos de listeners:
voidaddTreeExpansionListener(TreeExpansionListener tel): Listener para eventos del tipo TreeExpansion voidaddTreeSelectionListener(TreeSelectionListener tsl): Listener para eventos del tipo TreeSelection. voidaddTreeWillExpandListener(TreeWillExpandListener tel) Listener para eventos TreeWillExpand .
Vamos a procesar los eventos de tipo Selection sobre un Jtree (1 click). Para ello:
Crear una nueva inner class a MiVista UsuariosSelectionListener que implemente el interface TreeSelectionListener Implementar su mtodo valueChanged (TreeSelectionEvent e) para que muestre un mensaje con la propiedad user del usuario bean seleccionado. Para referenciarlo:
UsuarioBean usuario = (UsuarioBean)((DefaultMutableTreeNode)e.getNewLeadSelectionPath().getPathCompone nt(1)).getUserObject();
El mtodo getPathComponente retorna el objeto que previamente hemos ligado al jtree comenzando por 0 (root). As, en nuestro ejemplo:
@Override public void valueChanged(TreeSelectionEvent e) { if ( ((DefaultMutableTreeNode)e.getNewLeadSelectionPath().getPathComponent(1) ).getUserObject() instanceof UsuarioBean ) { UsuarioBean usuario = (UsuarioBean)((DefaultMutableTreeNode)e.getNewLeadSelectionPath().getPat hComponent(1)).getUserObject(); System.out.println("Es el usuario "+usuario.getNombre()); JOptionPane.showMessageDialog(null, "Seleccionado usuario "+usuario.getNombre()); } System.out.println(e.getPath().toString()); }
Hasta ahora para construir los formularios hemos usado el TableFormBuilder, que coloca inevitablemente la etiqueta y el campo a continuacin fila a fila en el formulario. El GridBagLayoutFormBuilder permite definir la orientacin de las etiquetas de los campos, permitiendo forzar a que est
Encima Debajo A la izquierda A la derecha.
Se basa en la aplicacin del GridBagLayout de Swing que ve el panel como una matriz con filas y columnas irregulares.
GridBagLayoutFormBuilder formBuilder = new GridBagLayoutFormBuilder(this.getBindingFactory()); formBuilder.appendSeparator("General"); formBuilder.nextLine(); formBuilder.appendLabeledField("titulo",LabelOrientation.TOP); formBuilder.appendLabeledField("autor",LabelOrientation.TOP); formBuilder.appendLabeledField("precio",LabelOrientation.TOP); return formBuilder.getPanel();
Crear un UsuarioDialog que, aprovechando el ya confeccionado LoginForm y creando un nuevo formulario DatosUsuarioForm para el resto de los datos del usuario, componga un CompositeDialog que se dispare al pinchar encima de uno de los usuarios del Jtree. Resuelto en piloto 26.0
` `
Extender la aplicacin para que MensajesView muestre un mensaje notificando las expansiones y contracciones del rbol de usuarios. Empezar por plantear un diseo para la solucin. Cmo comunicamos dos vistas? Resuelto en piloto 27.0
Activar el comando DELETE COMMAND para que se puedan eliminar libros de la tabla de libros. Resuelto en piloto 28.0
Crear una nueva vista UltimaVista donde aparezca un formulario con un edit box y un botn, de forma que al pulsar el botn se aada el contenido del edit box al panel de la vista MensajesView Resuelto en piloto 29.0