Sie sind auf Seite 1von 122

`

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

para la construccin rpida de aplicaciones Swing

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

Crear un proyecto Java en Eclipse y crear dentro una clase Main :

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

Clases de soporte para:


Construccin de dilogos bien formados Wizards Validacin de datos de entrada Barras de botones Internacionalizacin Gestin de imgenes Monitorizacin de progreso Hojas de propiedades Ordenacin y actualizacin de tablas Estndares de GUI como buildes/helpers, ayuda, ventanas Acerca De

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:

<bean id="application" class="org.springframework.richclient.application.Application"> <constructor-arg index="0" ref="applicationDescriptor" /> </bean>

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.

Vamos a extender la aplicacin creando nuestro propio lifeCycleAdvisor. Para ello:


Creamos una clase es.uniovi.si.PilotoLifecycleAdvisor que extienda la clase DefaultApplicationLifecycleAdvisor. Lo damos de alta en el xml:
<bean name="applicationLifecycleAdvisor" class=es.uniovi.si.PilotoLifecycleAdvisor"> </bean>

Y se lo referenciamos al bean application como advisor del ciclo de vida.


<bean name="application class="org.springframework.richclient.application.Application"> <constructor-arg index="0" ref="applicationDescriptor" /> <constructor-arg index="1" ref="applicationLifecycleAdvisor" /> </bean>

` ` ` ` `

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 ;

Y damos de alta la vista...

... Establecindola a dems como startPageId en el bean que implementa el advisor.

<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

` <bean id=serviceLocator class=org.springframework.richclient.application.App licationServicesLocator> </bean>

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

` <bean id=applicationServices class=org.springframework.richclient.application.sup port.DefaultApplicationServices>

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,

String appContextPath = "ctx/richclient-applicationcontext.xml"; ApplicationContext appCtx = new ClassPathXmlApplicationContext(appContextPath); new ApplicationLauncher(appCtx);

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

rce"> <property name="basenames"> <list> <value>ui.messages</value> <value>org.springframework.richclient.application.messages</value> </list> </property> </bean>

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!

Dar de alta tambin la propiedad:


applicationDescriptor.label=Piloto de RCP!

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

SRCP aporta su propio framework de comandos, incluido en el paquete: org.springframework.richclient.command

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"/>

Configurar el lifecycleAdvisor para que lea el fichero de comandos en 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>

Crear el fichero en el entorno de trabajo.

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

Y adems, una accin Exit implementada por


org.springframework.richclient.command.support.ExitCommand

Por un lado, definimos el men principal:


<bean id="menuBar class="org.springframework.richclient.command.CommandGroupFact oryBean"> <property name="members"> <list> <ref bean="fileMenu"/> </list> </property> </bean>

Y por otro, el submen fileMenu

<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>

Resuelto en piloto 3.0

PropertiesCommand y deleteCommand son dos de los comandos globales de SRCP:


cut copy paste undo redo save save as select all delete properties Run

La etiquetas e iconos por defecto de stos se encuentran empaquetadas en el jar de recursos de Spring RCP, pero podemos sobrescribirlas.

Extender el fileMenu con los comandos cut y copy. Para ello:


Declararlos como shared commands Ids en el bean windowCommandManager. Asociarlos al bean fileMenu. Tngase en cuenta que sus ids son cutCommand y copyCommand

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

Ejecutar la aplicacin y comprobar su funcionamiento. Resuelto en piloto 4.0

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()

Vamos a aadir nuestro primer comando a nuestra aplicacin. Para ello:


Creamos la clase es.uniovi.si.comandos.PruebaCommand, forzando a que implemente la interfaz ActionCommand. Implementamos el doExecuteCommand para que muestre un mensaje por pantalla. Importante: en el constructor, invocamos al constructor heredado pasndole un string con el id del comando:
super("pruebaCommand");

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

` `

Elemento predefinido en SRCP Para aadirla:


En el applicationContext

<bean name="applicationLifecycleAdvisor" class="es.uniovi.si.PilotoLifecycleAdvisor"> <property name="toolbarBeanName" value="toolBar" /> </bean>

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:

pruebaCommand.icon=images/magnolia.gif barraCommand.icon=images/icono2.gif applicationInfo.image=images/magnolia.gif

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.

void register(String commandId, ActionCommandExecutor localExecutor)

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();

Declaramos la clase es.uniovi.si.comandos.NuevoLibroExecutor


public class NuevoLibroExecutor implements ActionCommandExecutor { public void execute() { System.out.println("Ejecutado el comando nuevoLibro"); }

Y asociamos el nuevo ejecutor al comando global propertiesCommand


Resuelto en piloto 8.0

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

<bean id="applicationPageFactory" depends-on="serviceLocator" class="org.springframework.richclient.application.dockin g.vldocking.VLDockingApplicationPageFactory"> </bean>

Resuelto en piloto 9.0.

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>

Arrancar la aplicacin, modificar el layout y volver a examinare el fichero xml Qu ha ocurrido?

Crear una nueva vista que:


Contenga un JPanel sin ningn mensaje ni componente Se llame MensajesVista y la damos de alta como MensajesView. Se activen los comandos globales de COPY y CUT, mostrando cada uno un mensaje personalizado:
x Pulsado COPIAR en la pantalla de Mensajes x Pulsado CORTAR en la pantalla de Mensajes

Modificar el layout para que la aplicacin tenga el siguiente aspecto...

Resuelto en piloto10.0.

Crear un comando global es muy sencillo, basta con:


declararlo en el windowCommandManager como comando global (enumerndolo en la lista de sharedCommandsIds) Insertarlo en el men adecuado Establecer sus etiquetas e iconos para que pueda ser representado.

` `

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

Establecindolas a true/false determinamos las posibles acciones sobre la ventana.

<property name="closeEnabled" value="true" />

Cambiar MensajesPage y WelcomePage para que sean VLDockingViewDescriptor Establecer:


welcomePage con autohide Mensajes Page con
x closeEnabled x floatEnabled x maximizeEnabled

Resuelto en piloto 12.0

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.

Constructor: AbstractObjectTable(String modelId, String[] columnPropertyNames)


Las cadenas que identifican las columnas:
x Son mapeos de las propiedades de los beans que contenga la tabla. Ejemplos:

` ` `

Mtodo public Object[] getDefaultInitialData()

x titulo -> .getTitulo() x editorial.nombre -> .getEditorial().getNombre()

Debe retornar el conjunto inicial de datos a mostrar.

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)

x String []{"titulo","autor","editorial.nombre",editori al.direccion","precio"} Almacene la librera en la propiedad.


`

En el mtodo getDefaultInitialData, retornamos el array de LibroBeans

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>

Resuelto en piloto 13.0

Como hemos visto, AbstractObjectTable permite asociar:


Mens emergentes contextuales Command Executors asociado al doble click sobre una fila.

` public void setPopupCommandGroup( CommandGroup popupCommandGroup)

Ambas acciones tienen que poder acceder al bean seleccionado en la tabla. Para asociarlos, nos servimos de los mtodos:

public void setDoubleClickHandler( ActionCommandExecutor doubleClickHandler)

La AbstractObjectTeble se espera un objeto de tipo CommandGroup. Para insertar en el men, por ejemplo, un comando global:

CommandGroup popup = new CommandGroup();

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();

Aadimos el comando global properties.

popup.add((ActionCommand) getWindowCommandManager().getCommand( GlobalCommandIds.PROPERTIES, ActionCommand.class));

Lo asociamos a la tabla.

Ejecutamos. Sale el popup? Por qu est deshabilitado?

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

En aplicaciones SRCP tenemos dos alternativas para la creacin de dilogos:


Dilogos Swing estndar
x Podemos usarlos perfectamente, pero no aprovechamos caractersticas como la validacin automtica que nos da SRPC

Dilogos SRPC: Tenemos cuatro tipos:


x x x x ConfirmationDialog InputApplicationDialog TitledPageApplicationDialog WizardDialog.

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)

Sobrescribimos el mtodo onAboutShow():

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); }

Sobrescribimos los mtodos onFinish() y onCancel()

@Override protected boolean onFinish() { form.getFormModel().commit(); return true; } @Override protected void onCancel() { super.onCancel(); }

Creamos el mensaje en el messages.properties


libroProperties.edit.title=Editando el libro {0} de {1}

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; }

Y como slo nos interesa el primero (no podemos seleccionar ms de uno)

public LibroBean getSelectedLibro() { return (LibroBean) getSelectedLibros()[0]; }

Finalmente, modificamos el mtodo execute() del PropertiesExecutor para que muestre el dilogo que hemos creado:

new LibroPropertiesDialog(tabla.getSelectedLibro()).showDialog()

Resuelto en piloto 15.0

` `

Es la base de la implementacin de los formularios. Comandos implementados:


CommitCommand: Vuelca los datos al backing bean (el que se est editando) RevertCommand: Recarga los datos del formulario con los del backing bean NewFormObjectCommand: crea una nueva instancia del modelo.

Constructor que estamos usando:


protected AbstractForm(Object formObject) Crea un FormModel a partir del objeto que le pasamos.

` `

Nos crean automticamente la representacin swing del formulario. Tienen que estender la clase AbstractFormBuilder Tres tipos implementados:
GridBagLayoutFormBuilder HtmlFormBuilder TableFormBuilder

` `

Construye el formulario Swing en forma de tabla. Constructor:


TableFormBuilder(BindingFactory bindingFactory) La binding factory
x se obtiene del formulario, mediante el mtodo getBindingFactory(); x Genera bindings (enlaces) con las clases del modelo que tiene enlazado el formulario.

Algunos mtodos para construir formularios:


Objetivo Aade un campo al formulario. El fieldName se entiende como una propiedad del backing bean Aade un separador etiquetado al formulario Crea una nueva fila Una vez configurado, retorna el objeto de tipo JComponent Como add pero fuerza a que el campo sea de tipo textarea Como add pero fuerza a que el campo sea de tipo password

Mtodo
JComponent[]add(String fieldName)

void addSeparator(String text)

void row() JComponent getForm()

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();

Para cada propiedad


formBuilder.add("titulo"); formBuilder.add("editorial.nombre");

Hasta que tenga el siguiente aspecto:

Y al final, retornamos el formulario una vez formateado: Resuelto en piloto 16.0

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);

Resuelto en piloto 17.0

` `

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

Restriccin para que la propiedad afectada cumpla:


Requerida Longitud mxima de 30 Alfabtica

private final Constraint NAME_CONSTRAINT = all(new Constraint[]{ required(), minLength(2), regexp("[-'.a-zA-Z ]*")});

Restriccin para que la propiedad afectada cumpla:


Requerida Se encuentre entre 0 y 120
private final Constraint AGE_CONSTRAINT = all(new Constraint[]{ required(), range(0,120)});

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); }; }

Para activar las reglas en una aplicacin, tenemos que:


Por un lado, asociarlas al bean que extiende el DefaultRulesSource en su constructor, mediante si mtodo addRules(). Ejemplo
addRules(new MiClase(MiClase.class));

Declarar el bean en el contenedor bajo la etiqueta de rulesSource:


<bean id="rulesSource" class="es.uniovi.si.rules.ValidationRules" />

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

Declaramos una inner class LibroBeanRules que:


Extienda la clase Rules En su constructor reciba la clase LibroBean.class y llame al padre.

public LibroBeanRules(Class<LibroBean> clase ) { super(clase); }


`

Realice las siguientes asociaciones entre campos y restricciones:


Ttulo: ID_CONSTRAINT Autor: ID_CONSTRAINT editorial.nombre: required()

Sobrescribimos el constructor, de forma que:


Invoque al constructor padre Aada las reglas contenidas en LibroBeanRules a si coleccin de reglas.
addRules(new LibroBeanRules(LibroBean.class));

Finalmente, lo declaramos como fuente de reglas en el contenedor

<bean id="rulesSource" class="es.uniovi.si.rules.ValidationRules" />

Resuelto en piloto 19.0

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 "))

Resuelto en piloto 20.0

Crear una nueva tabla es.uniovi.si.ui.UsuariosTable que se nutra del bean usuarios y mostrarla en welcomePage.

Resuelto en piloto 21.0

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 Reciba un LibroBean x Instancie ambos atributos de dilogo x Instancia un objeto TabbedDialogPage:


CompositeDialogPage compositeDialogPage = new TabbedDialogPage("libroProperties");

x Aada al mismo los dos formularios:


compositeDialogPage.addForm(libroForm); compositeDialogPage.addForm(editorialForm);

x Establezca la pgina de dilogo compuesta como pgina de dilogo del dilogo.


setDialogPage(compositeDialogPage);

x Implementar los mtodos onAboutToShow y inFinish recordando hacer el commit en ambos formularios.

Resuelto en piloto 22.0

Probar a cambiar la creacin de la pgina del dilogo por:

CompositeDialogPage compositeDialogPage = new TreeCompositeDialogPage("libroProperties");

` ` ` ` `

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.

Para crear la estructura de rbol,

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

DefaultMutableTreeNode rootNode=new DefaultMutableTreeNode("Usuarios");

DefaultMutableTreeNode usuarioNode = DefaultMutableTreeNode(usuario);

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()));

x Y se lo aadimos al nodo root:


rootNode.add(usuarioNode);

Una vez compuesta la estructura jerrquica a representar,

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.

Dentro del mtodo:

Llamamos al constructor del padre Hacemos un cast de value a DefaultMutableTreeNode

DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;

Personalizamos el nodo root:

if (node.isRoot()) {this.setText("Lista de usuarios"); } else {

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()); }

Finalmente, retornamos una referencia del propio renderer.


return this;
`

Y se lo establecemos al Jtree como renderizador de celdas en la factora que acabamos de implementar:


tree.setCellRenderer(new UsuariosTreeCellRenderer());

Resuelto en piloto 23.0

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 .

Adems de todos los heredados de JComponent

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:

getPathComponent(0)).getUserObject() getPathComponent(1)).getUserObject() getPathComponent(2)).getUserObject()

La cadena Lista de usuarios Instancias de UsuarioBean Cadenas de texto de las propiedades

@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()); }

Resuelto en piloto 24.0

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.

Para ponerlo en prctica, sustituir el cdigo del LibroForm por lo siguiente:

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();

Resuelto en piloto 25.0

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

Das könnte Ihnen auch gefallen