tag:blogger.com,1999:blog-66770939751065562072024-03-13T17:46:48.307+01:00Swing Facil, en españolSwing fácil es un blog dedicado a la tecnología Java Swing y a como darle un toque personal a nuestros diseños de interfaz.Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.comBlogger23125tag:blogger.com,1999:blog-6677093975106556207.post-90154077114519411922013-12-13T14:44:00.000+01:002013-12-13T14:44:03.973+01:00Crear un proyecto JSF2 con Eclipse y Tomcat<h2>JSF2, Instalación y Configuración</h2><div>Vamos a explicar como crear un proyecto JSF2 desde 0.</div><h3>Requisitos:</h3><div><ul><li>Java --> Necesitaremos Java 6 o superior para utilizar Tomcat 7</li>
<li>Servidor --> Necesitamos un servidor que soporte servlets 2.5 o superior y además que contenga las librerías de JSF2, cosa que añadiremos manualmente ya que Tomcat no incorpora estas librerías</li>
<li>Librerías --> jsf-api.jar y jsf-impl.jar son extricatamente necesarias para utilizar JSF2 en Tomcat</li>
<li>Un IDE --> Eclipse 3.6 o superior, ya que desde esta versión tiene incorporado soporte para JSF2</li>
</ul></div><h3>Paso a paso</h3><div>Una vez instalado Eclipse e integrado Tomcat, pasaremos a la creación del proyecto en sí.</div><div><div class="separator" style="clear: both; text-align: center;"><br />
</div><ol><li>Creamos un nuevo proyecto de tipo Java<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf3XUOFMRVyBd_QVm8ohAr_D6hGAbkpPsYq5-J7a6NQA1Xlv2_-_aEEBqEHsihW48e7W253x1CEWOk7LjQgVZ76QsW9X6mKgcJU06D75MUsjyimEH5AgxLptQPcN2QNumatwutfpCUwiOh/s1600/new.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Nuevo proyecto" border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf3XUOFMRVyBd_QVm8ohAr_D6hGAbkpPsYq5-J7a6NQA1Xlv2_-_aEEBqEHsihW48e7W253x1CEWOk7LjQgVZ76QsW9X6mKgcJU06D75MUsjyimEH5AgxLptQPcN2QNumatwutfpCUwiOh/s320/new.png" title="Nuevo proyecto" width="320" /></a></li>
<li> Ahora lo configuramos como un proyecto web, para esto hacemos click sobre el y en el menú contextual seleccionamos <i>Configure -> Convert to Faceted Form<br />
<span id="goog_409250937"></span><span id="goog_409250938"></span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCQsUu_2kxuSpjfW291yM-0BXFVVoEmbKtU_2C38SzL5kueYB1hg3Xfl1SFvFPMfKE2sUlU9Yh2onjfqRl9fxqMEj-fFpygh7eWEW6_4jZT2-fEaKB_fbZ6goMM2duLB_V91qSwTEjF_9q/s1600/eclipse_faceted.png" imageanchor="1" style="font-style: normal; margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="70" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCQsUu_2kxuSpjfW291yM-0BXFVVoEmbKtU_2C38SzL5kueYB1hg3Xfl1SFvFPMfKE2sUlU9Yh2onjfqRl9fxqMEj-fFpygh7eWEW6_4jZT2-fEaKB_fbZ6goMM2duLB_V91qSwTEjF_9q/s320/eclipse_faceted.png" width="320" /></a></i></li>
<li>Elegimos ahora las facetas del proyecto que se muestran en la imagen siguiente y clickamos en el mensaje señalado para añadir las librerías necesarias:<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK7prAzjg28OcZbhNo0za8pzgvE5uy9GIYpERRclEkdjBlZTDsgPznhxWyad1kVaar8S1n4c2pu7IOVN5eMcU0ZgH-oXK2qwpmAvH4T21y_-vQAJLHH0Y9Mdg3quhYnvnrhER_Q73tm-Hn/s1600/facets_conf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="259" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK7prAzjg28OcZbhNo0za8pzgvE5uy9GIYpERRclEkdjBlZTDsgPznhxWyad1kVaar8S1n4c2pu7IOVN5eMcU0ZgH-oXK2qwpmAvH4T21y_-vQAJLHH0Y9Mdg3quhYnvnrhER_Q73tm-Hn/s320/facets_conf.png" width="320" /></a></li>
<li>Si estamos utilizando Tomcat, deberemos añadir la implementación de JSF, para ello clickamos para crear una nueva <i>User Library </i>y añadimos los JARs necesarios, en este caso serían <b>jsf-api.jar y jsf-impl.jar</b>, aunque por comodidad añadiremos también la librería de etiquetas JSTL.<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNQSgR6EmjaE8b6yQNFXyZgLJQEOOO3Ph-Kq0F1-tK2u_vjG2mvEpZfKq8QshBe0Ci3dvzEbZgVc01K4LoK5FsCzDJvnKEOpipXOlR8lOpM6tGU8DlY1j6q9km2oVv14FD1N_1csgHdEuo/s1600/user_library.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNQSgR6EmjaE8b6yQNFXyZgLJQEOOO3Ph-Kq0F1-tK2u_vjG2mvEpZfKq8QshBe0Ci3dvzEbZgVc01K4LoK5FsCzDJvnKEOpipXOlR8lOpM6tGU8DlY1j6q9km2oVv14FD1N_1csgHdEuo/s320/user_library.png" width="247" /></a></li>
<li>Damos Ok a todo y cerramos las ventanas. Al final debería de quedarnos un proyecto con la siguiente estructura:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizM-w8GepVisB2D4JlOuBLjApqpufX7IrgE4Mfx9Phr9QeG0d8ut2OxG5WujDYCwaW_HapRBcoASJeliE4v7-eBU0HIGGeOnhGuBX-Bzh5oxNsZiPgxQjLcgHHhjEXpE1T9gJFEtni9Vqh/s1600/proy_struct.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizM-w8GepVisB2D4JlOuBLjApqpufX7IrgE4Mfx9Phr9QeG0d8ut2OxG5WujDYCwaW_HapRBcoASJeliE4v7-eBU0HIGGeOnhGuBX-Bzh5oxNsZiPgxQjLcgHHhjEXpE1T9gJFEtni9Vqh/s320/proy_struct.png" width="204" /></a></li>
</ol></div><div>Como vemos durante este proceso se habrán generado los ficheros necesarios para configurar cualquier aplicación web JSF, faces-config.xml y web.xml.<br />
<br />
El contenido de los mismos se detalla a continuación:<br />
Fichero web.xml con el contenido mínimo para hacer funcionar nuestra aplicación JSF. El PROJECT_STAGE no es necesrio definirlo, pero de esta manera tendremos más información sobre fallos y otros asusntos durante el desarrollo.<br />
<pre class="brush: xml"><web-app id="WebApp_ID" version="3.0" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>JSF2-inicio</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name><param-value>Development</param-value></context-param>
</web-app>
</pre><br />
Este fichero faces-config.xml debe estar siempre presente aunque no tenga ningún contenido, como es nuestro caso.<br />
<pre class="brush: xml"><faces-config version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
</faces-config>
</pre><br />
Para probar nuestra aplicación solo nos queda añadir un par de páginas estáticas con algo de contenido y ver que todo funciona correctamente.<br />
Bajo la carpeta <i>WebContent</i> de nuestro proyecto añadimos los siguientes ficheros:<br />
<br />
<b>index.jsp</b><br />
<pre class="brush:js"><% response.sendRedirect("hello.jsf"); %>
</pre><br />
<b>hello.xhtml</b><br />
<pre class="brush:xml"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Hola Mundo JSF!</title>
</h:head>
<h:body>
<h1>Hola Mundo JSF!</h1></h:body>
</html>
</pre><br />
Ahora solo nos queda desplegar la aplicación en nuestro Tomcat y usar cualquier navegador para acceder a <b>http://localhost:3080/JSF2-inicio/</b> para lanzar nuestra aplicación JSF. El nombre de host y puerto dependerá de la configuración que cada uno tenga en su máquina.<br />
<br />
A continuación os dejo unos enlaces para descargar este proyecto inicial en blanco ya montado, que nos servirá como base en el resto de capítulos del tutorial. <a href="https://drive.google.com/file/d/0BxzOnh3QzsqpdkZ1UUxrQWRNY00/edit?usp=sharing" rel="nofollow" target="_blank">JSF-inicio</a><br />
<br />
Y las librerías JSF y JSTL que incluimos en el punto 4. <a href="https://drive.google.com/file/d/0BxzOnh3QzsqpdXF4ckpfX1ZiNE0/edit?usp=sharing" rel="nofollow" target="_blank">Librerías</a></div>Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com2tag:blogger.com,1999:blog-6677093975106556207.post-43755516784747827052013-12-05T14:18:00.000+01:002013-12-05T14:18:41.411+01:00JSF vs MVC usando servlet + RequestDispatcher. Ventajas y desventajasEn esta entrada, y antes de entrar propiamente en materia, vamos a repasar algunas de las características de JSF que lo hacen una buena alternativa a usar en nuestras aplicaciones web para implementar el modelo MVC<br />
<br />
<h3>
Ventajas de JSF vs MVC usando RequestDispatcher</h3>
<div>
<ul>
<li>Controles de GUI personalizados --> JSF proporciona una serie de APIs y etiquetas personalizadas para crear formularios HTML con interfaces complejas</li>
<li>Manejo de eventos --> JSF hace fácil diseñar código Java que se invoca cuando se envían los formularios. El código puede responder a botones especiales, cambios de un valor particular, selecciones del usuario y más</li>
<li>Beans manejados --> En JSF podemos usar property="*" con jsp:setProperty para generar un bean basado en los parámetros de la request. JSF extiende esta capacidad y añade otras utilidades para simplificar el tratamiento de los parámetros de la request</li>
<li>Soporte AJAX integrado --> Podemos usar jQuery y otras librerías con servlets y JSPs, pero JSF utiliza AJAX sin necesidad de programación explícita Javascript y usando etiquetas muy simples.</li>
<li>Conversión y validación de campos de formularios --> JSF tiene incorporadas capacidades para comprobar que los valores de los formularios están en el formato requerido y para convertir desde cadenas de texto a otro mucho tipos de datos. Si faltan los valores o tienen un formato no apropiado, el formulario se puede repintar autómaticamente con mensajes de error y con los valores introducidos anteriormente.</li>
<li>Plantillas de página --> Aunque JSP tiene jsp:include para reutilizar contenido, JSF tiene un sistema completo de plantillas que permite construir páginas que comparten disposición o contenido.</li>
<li>Configuración centralizada basada en archivos --> Muchos de los valores de JSF se representan en ficheros XML o de propiedades. Esto implica que muchos cambios se pueden hacer sin necesidad de recompilar el código Java y que se pueden hacer cambios generales en la aplicación modificando un único fichero.</li>
<li>Enfoque coherente --> JSF fomenta el uso de MVC en toda la aplicación</li>
</ul>
</div>
<br />
<h3>
DesVentajas de JSF vs MVC usando RequestDispatcher</h3>
<div>
<ul>
<li>Mayor curva de aprendizaje --> Para usar MVC con el RequestDispatcher estándar solo necesitamos conocer JSP estándar y el API servlet. Para usar MVC con JSF necesitas conocer el API servlet y un framework completo bastante complejo. Otro ejemplo, para añadir funcionalidad AJAX sobre una aplicación existente es mucho más fácil y rápido usar jQuery que convertir la aplicación a JSF2.</li>
<li>Peor documentación --> Comparada con los servlet estándar y la API JSP, JSF no tiene apenas documentación online disponible y clara.</li>
<li>Menos transparente --> En las aplicaciones JSF pasan muchas más cosas que se escapan de nuestro alcance que en una aplicación web java normal. Por esto las aplicaciones JSF son más difíciles de entender y más difícil de testear y optimizar.</li>
<li>El hecho de fomentar el uso de MVC hace muy difícil usar otro enfoque</li>
</ul>
</div>
<br />
Esto nos da algo de visión de conjunto de las bondades y debilidades de JSF frente a la implementación de un modelo MVC usando el core de Java, aunque por supuesto habría que entrar a valorar otra muchas alternativas y frameworks como:<br />
<br />
<ul>
<li>Spring MVC</li>
<li>Apache Wicket</li>
<li>Apache Tapestry</li>
<li>jMaki</li>
<li>y otros tantos...</li>
</ul>
Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com0tag:blogger.com,1999:blog-6677093975106556207.post-92181220343630794882013-11-26T17:27:00.000+01:002013-11-26T17:27:03.898+01:00¿Que es JSF (Java Server Faces)?<div>
En esta nueva etapa vamos a adentrarnos en el uso de otra tecnología Java, se trata de JSF, cuya última versión, JSF 2.2 introduce soporte a HTML5, Faces Flow, Stateless views y Resource library contracts.<br />
<br />
JavaServer Faces (JSF) es un framework MVC que facilita la construcción de la interfaz de usuario en aplicaciones web mediante el uso de componentes reutilizables.</div>
<div>
JSF define una serie de componentes estándar y proporciona una API para el desarrollo de componentes personalizados, además de permitir extender los componentes estándar ya existentes.</div>
<h2>
Beneficios</h2>
<div>
JSF minimiza el esfuerzo de crear y mantener aplicaciones que corren en un servidor de aplicaciones Java por los siguientes motivos:<br />
<br />
<ul>
<li>Proporciona componentes gráficos reusables</li>
<li>Hace fácil la transferencia de información entre componentes</li>
<li>Mantiene el estado de la interfaz entre peticiones al servidor</li>
<li>Permite implementar componentes personalizados</li>
<li>Enlaza eventos en la parte cliente con la parte servidora de la aplicación</li>
<li>Beans administrados</li>
<li>APIs para validar entradas, definir la navegación entre páginas, internacionalización y accesibilidad, etc...</li>
</ul>
<div>
<br /></div>
<div>
A lo largo de una serie de entradas iremos introduciéndonos y profundizando en el manejo de esta tecnología en proyectos web.</div>
</div>
<ul class="list" style="background-color: white; font-family: Helvetica, Arial, sans-serif; font-size: 12px; list-style: none; margin: 0px; padding: 0px 0px 0px 15px;">
</ul>
Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com0tag:blogger.com,1999:blog-6677093975106556207.post-10103527589369468402012-05-03T15:31:00.001+02:002012-05-03T15:31:41.677+02:00JTable con imágenes y textoHola a todos y especialmente a <a href="http://www.blogger.com/profile/15835508266817525583" rel="nofollow" style="color: #262626; font-family: Georgia, serif; font-size: 12px; font-weight: bold; line-height: 19px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none;">Marmoleria Cañones</a> que es la persona que me pidió esta nueva entrada sobre <i>JTable</i>.<br />
<br />
En la sección <a href="http://swing-facil.blogspot.com.es/p/consultas-necesitas-ayuda-con-tu-codigo.html" style="background-color: white; color: #391a02; font-family: Georgia, serif; font-size: 14px; font-weight: bold; margin-bottom: 0px; margin-left: 10px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: center; text-decoration: none; text-shadow: rgb(248, 242, 214) 1px 1px 1px; text-transform: uppercase;">CONSULTAS ¿NECESITAS AYUDA CON TU CÓDIGO?</a> me pedía si podía hacer un nuevo ejemplo con un <i>TableCellRenderer</i> para poder mostrar una imagen y una descripción en un <i>JTable</i>...<br />
<br />
Nada más fácil, el <i>TableCellRenderer</i> por defecto que tiene instalado la clase <i>JTable</i> nos renderiza las imágenes sin necesidad de introducir código nuevo. Por lo tanto solo tenemos que pasar un objeto de la clase <i>ImageIcon</i> como contenido de una fila y se pintará automáticamente, siempre que la clase <i>TableCellRenderer</i> sepa que tipo de objeto debe pintar.<br />
Por lo tanto la clave de esto pasa por decir que tipo de objeto se debe pintar, el modelo de datos por defecto de un <i>JTable</i> es el <i>DefaultTableModel</i>, este modelo hace creer al renderer que todos los objetos que debe pintar son <i>Object</i>, por lo que lo único necesario para poder mostrar una imagen es crear una clase que extienda <i>DefaultTableModel </i>y sobreescribir el método que indica que tipo de objeto contiene cada columna.<br />
En el modelo por defecto tenemos:<br />
<pre class="brush: js">public Class<?> getColumnClass(int columnIndex) {
return Object.class;
}
</pre>Y la modificación que debemos hacer:<br />
<pre class="brush: js"> private class MyTableModel extends DefaultTableModel {
public MyTableModel(Object[][] data, Object[] columnNames) {
super(data, columnNames);
}
@Override
public Class<?> getColumnClass(int columnIndex) {
Class<?> clazz = Object.class;
Object aux = getValueAt(0, columnIndex);
if (aux != null) {
clazz = aux.getClass();
}
return clazz;
}
}
</pre><br />
<br />
Es decir, nuestra tabla queda así:<br />
<pre class="brush: js">package tableIconoDescripcion;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class Table extends JTable {
public Table() {
super();
String [] columnNames = new String[]{ "Nombre", "Icono", "Descripción"};
Object [][] data = new Object[][]{
{"Angel", createImage("icono1.jpg"), "angelarcosheredia@gmail.com"},
{"Juan", createImage("icono2.jpg"), "juan@gmail.com", false},
{"Ana", createImage("icono3.jpg"), "ana@hotmail.com", false}
};
MyTableModel model = new MyTableModel(data, columnNames);
this.setRowHeight(100);
this.setModel(model);
}
/**
* Para recuperar una imagen de un archivo...
* @param path Ruta de la imagen relativa al proyecto
* @return una imagen
*/
public ImageIcon createImage(String path) {
URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
private class MyTableModel extends DefaultTableModel {
public MyTableModel(Object[][] data, Object[] columnNames) {
super(data, columnNames);
}
@Override
public Class<?> getColumnClass(int columnIndex) {
Class<?> clazz = Object.class;
Object aux = getValueAt(0, columnIndex);
if (aux != null) {
clazz = aux.getClass();
}
return clazz;
}
}
}
</pre><br />
Este sería el resultado obtenido:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo-6Q_pE4KDxHHi4GhV0JJfmmLRQIVrr9IQsiSTbGPNh3DGLQNTDuiJA5CnjCupmD6f8chYco0CphcLoqXW0zmaK_dUTWv416cbWZhRw3h5FkIVQ1dXZL9FoecrsuuoTEyvBZE1HhsI_2m/s1600/JTable.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo-6Q_pE4KDxHHi4GhV0JJfmmLRQIVrr9IQsiSTbGPNh3DGLQNTDuiJA5CnjCupmD6f8chYco0CphcLoqXW0zmaK_dUTWv416cbWZhRw3h5FkIVQ1dXZL9FoecrsuuoTEyvBZE1HhsI_2m/s400/JTable.JPG" width="400" /></a></div><br />
<br />
Y para lanzar la aplicación simplemente ejecutamos este código.<br />
<pre class="brush: js">package tableIconoDescripcion;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Componentes Swing en JTable");
final Table table = new Table();
// La añadimos a un scroll para mostrar la cabecera
JScrollPane scroll = new JScrollPane(table);
frame.add(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 200);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Eso es todo, para cualquier otra aclaración, no dudéis en contactar conmigo.<br />
<br />
Un saludoAnonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com9tag:blogger.com,1999:blog-6677093975106556207.post-69529223597907232332012-04-19T13:41:00.000+02:002012-04-19T13:41:11.388+02:00Validable JTextField, espresiones regulares en JavaHola compañeros, en la mayoría de los formularios de nuestras aplicaciones nos vemos en la necesidad de validar las entradas del usuario.<br />
<br />
Esto en primer lugar puede parecer una tarea tediosa, sin embargo, vamos a ver como realizarla de una manera fácil.<br />
<br />
<h3>Expresiones regulares en Java</h3>Para ello nos valdremos del uso de <i>expresiones regulares</i>. Las <i>expresiones regulares</i> son una manera de describir un conjunto de cadenas de texto que comparten características comunes. Se pueden usar para buscar, editar o manipular textos.<br />
El soporte para las expresiones regulares en java lo proporciona la API <i>java.util.regex</i>.<br />
Las clases principales de este paquete que vamos a utilizar son la clase <i>Pattern </i>y la clase <i>Matcher</i>.<br />
<br />
La clase Pattern proporciona una versión compilada de una expresión regular, no tiene constructor público por lo que para usarlo deberemos invocar a uno de sus métodos estáticos compile.<br />
Un objeto Matcher se encarga de interpretar el patrón y realiza operaciones buscando coincidencias en una cadena introducida. Al igual que la clase Pattern, no dispone de constructores públicos por lo que para obtener una instancia invocaremos al método matcher en un objeto Pattern.<br />
<br />
Un ejemplo del uso básico de estas clases lo presentamos a continuación, las utilizaremos para buscar cadenas que sean exactamente “a”, “b” o “c”.<br />
<pre class="brush: js">String regEx = "[abc]";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher("a");
if (matcher.matches()) {
System.out.println("Se encontró la cadena buscada");
}
</pre><br />
Siguiendo con el tema de los formularios en Swing, podemos utilizar expresiones de este tipo para crear un componente de texto que valide la entrada.<br />
Para ello crearemos una clase que hereda de JTextField y que nos permite pasar una expresión regular al constructor para validar la entrada cada vez que se pulse una tecla. Nuestro componente quedaría así:<br />
<br />
<pre class="brush: js">package validableJTextfield;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.BorderFactory;
import javax.swing.JTextField;
import javax.swing.border.Border;
public class ValidableTextField extends JTextField {
private Pattern pattern;
private Border wrongBorder = BorderFactory.createLineBorder(Color.RED);
private Border defaultBorder;
/**
* Constructor.
* @param regEx Expresión regular para evaluar
*/
public ValidableTextField(String regEx) {
super();
this.defaultBorder = this.getBorder();
this.setColumns(15);
this.pattern = Pattern.compile(regEx);
this.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) { }
@Override
public void keyReleased(KeyEvent e) {
validateText();
}
@Override
public void keyPressed(KeyEvent e) { }
});
}
private void validateText() {
Matcher matcher = pattern.matcher(this.getText());
if (!matcher.matches()) {
this.setBorder(wrongBorder);
} else {
this.setBorder(defaultBorder);
}
}
}
</pre><br />
Os dejo un ejemplo de la construcción de las expresiones regulares más comunes:<br />
<br />
[abc] “a”, “b”, o “c” (simple)<br />
[^abc] Cualquier carácter excepto “a”, “b”, o “c” (negación)<br />
[a-zA-Z] De la “a” a la “z”, o de la “A” a la “Z”, ambas inclusive(rango)<br />
[a-d[m-p]] De la “a” a la “d”, o de la “m” a la “p”: [a-dm-p] (union)<br />
[a-z&&[def]] “d”, “e”, o “f” (intersección)<br />
[a-z&&[^bc]] “a” a la “z”, excepto “b” y “c”: [ad-z] (resta)<br />
[a-z&&[^m-p]] “a” a la “z”, pero no de la “m” a la “p”: [a-lq-z] (resta)<br />
<br />
Y algunos atajos.<br />
. Cualquier carácter. <br />
\d Un dígito: [0-9]<br />
\D Dígitos no: [^0-9]<br />
\s Un espacio en blanco: [ \t\n\x0B\f\r]<br />
\S Cualquiera excepto un espacio en blanco: [^\s]<br />
\w Un carácter alfanumérico: [a-zA-Z_0-9]<br />
\W Un carácter no de palabra: [^\w]<br />
<br />
Veamos algunos ejemplos del uso de estar expresiones en nuestro componente, crearemos 4 ValidableTextField y le asignaremos a cada uno una expresión regular distinta para obtener algo como esto:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEije227nKuRDTjMovDPw2i16YVYkazoPT6AaLHl_4BNkW0q93Wnt-J1XNLylSVJVubbAzKYF8HoDPmzqTv9fQElriRAL6oWwoUqmrPOfkK55bt4Vimu6ILE6Qt3TOBoKGrKy0JhMAzaEsUd/s1600/validableJTextfield.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEije227nKuRDTjMovDPw2i16YVYkazoPT6AaLHl_4BNkW0q93Wnt-J1XNLylSVJVubbAzKYF8HoDPmzqTv9fQElriRAL6oWwoUqmrPOfkK55bt4Vimu6ILE6Qt3TOBoKGrKy0JhMAzaEsUd/s400/validableJTextfield.JPG" width="233" /></a></div><br />
<pre class="brush: js">package validableJTextfield;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Validable JTextField");
JPanel container = new JPanel();
JLabel labelLetters = new JLabel("Solo letras");
ValidableTextField textFieldLetters = new ValidableTextField("[a-zA-Z]*");
JLabel labelNumbers = new JLabel("Solo números");
ValidableTextField textFieldNumbers = new ValidableTextField("[0-9]*");
JLabel labelLetters3 = new JLabel("Tres caracteres alfanuméricos");
ValidableTextField textFieldLetters3 = new ValidableTextField("[a-zA-Z0-9]{3}");
JLabel labelLetters35 = new JLabel("Entre 3 y 5 caracteres alfanuméricos");
ValidableTextField textFieldLetters35 = new ValidableTextField("[a-zA-Z0-9]{3,5}");
container.add(labelLetters);
container.add(textFieldLetters);
container.add(labelNumbers);
container.add(textFieldNumbers);
container.add(labelLetters3);
container.add(textFieldLetters3);
container.add(labelLetters35);
container.add(textFieldLetters35);
frame.getContentPane().add(container);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(225, 250);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Y eso es todo por hoy si os han quedado cuestiones sin resolver sobre este tema, no dudéis en utilizar la página de Consultas ¿Necesitas ayuda con tu código? Para poneros en contacto conmigo.Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com1tag:blogger.com,1999:blog-6677093975106556207.post-64174791355279815002012-03-23T09:47:00.001+01:002012-03-23T09:47:40.575+01:00Escalar imagen con Swing, Zoom a una imagenVamos a ver como agrandar o reducir el zoom de una imagen con Swing. Esta entrada es una sugerencia de un compañero, por lo que aprovecho para deciros que si tenéis alguna sugerencia sobre lo que os gustaría que escribiésemos no tenéis más que decirlo.<br />
<br />
Antes de explicar como lo hemos hecho, informamos de que desde el JDK1.1 la clase <i>Image</i> tiene un método de conveniencia llamado <i>getScaledInstace()</i> que devolverá una versión a escala de la imagen de acuerdo a las dimensiones proporcionadas.<br />
<br />
Esta método además acepta un "hint" de los 5 que exponemos a continuación:<br />
<br />
<ul><li><b>SCALE_REPLICATE</b>: Mucho rendimiento, poca calidad, podemos obtener imágenes pixeladas</li>
<li><b>SCALE_FAST</b>: Es sinónimo de SCALE_REPLICATE.</li>
<li><b>SCALE_AREA_AVERAGING</b>: Es más lento que los anteriores pero proporciona más calidad.</li>
<li><b>SCALE_SMOOTH</b>: Es sinónimo de SCALE_AREA_AVERAGING.</li>
<li><b>SCALE_DEFAULT</b>: Tomaremos el valor por defecto, que será SCALE_FAST.</li>
</ul><br />
<br />
Más adelante con la introducción del JDK1.2, se nos ofrecieron clases como la BufferredImage y Graphics2D y unos “hint” más flexibles gracias a RenderingHints. A diferencia de los antiguos "hints" estos nos proporcionan un mayor control sobre el tratamiento de las imágenes cuando llamamos a <i>Graphics2D.drawImage()</i>. Estas claves ya las explicamos con anterioridad por lo que si queréis saber más sobre esto es conveniente que reviséis la entrada sobre <a href="http://swing-facil.blogspot.com/2011/12/renderinghints-renderizados-y.html" target="_blank">RenderingHints</a> que escribimos con anterioridad.<br />
<br />
<b><i>RenderingHints.KEY_INTERPOLATION:</i></b><br />
<br />
<ul><li>VALUE_INTERPOLATION_NEAREST_NEIGHBOR: Mucho rendimiento, pero baja calidad.</li>
<li>VALUE_INTERPOLATION_BILINEAR: Es algo más lento pero proporciona mayor calidad.</li>
<li>VALUE_INTERPOLATION_BICUBIC: Es similar a BILINEAR pero utiliza más muestras a la hora de filtrar las imágenes y suele ofrecer más calidad.</li>
</ul><br />
<b><i>RenderingHints.KEY_RENDER_QUALITY: </i></b><br />
<br />
<ul><li>VALUE_RENDER_SPEED: Significa “Prefiero velocidad antes que calidad, pero lo dejo en tus manos”, es sinónimo de VALUE_INTERPOLATION_NEAREST_NEIGHBOR.</li>
<li>VALUE_RENDER_QUALITY: “Prefiero calidad antes que velocidad, lo dejo en tus manos”, sería como usar VALUE_INTERPOLATION_BILINEAR.</li>
<li>VALUE_RENDER_DEFAULT: Significa “no me importa, hazlo sin más”, sinónimo de VALUE_RENDER_SPEED.</li>
</ul><div><br />
</div><br />
Usando <i>RenderintHints</i>, <i>BufferedImage </i>y <i>Graphics2D </i>obtendremos mejores resultados, más velocidad y calidad, por lo que será el método que utilizaremos en nuestro ejemplo.<br />
<br />
Pasamos a mostrar el código y dado que es algo complejo explicaremos que hace cada método. En principio simplemente crearemos un panel con un par de botones para aumentar y reducir el nivel de zoom aplicado, y un panel donde pintaremos nuestra imagen con el zoom deseado.<br />
Además de esto necesitamos algún método que nos transforme nuestro objeto Image a BufferredImage, para ello nos serviremos de <i>toBufferredImage(Image imagen)</i> y <i>hasAlpha(Image imagen)</i>. Este último nos dirá si la imagen contiene píxeles transparentes ya que la manera de crear la imagen en este caso será distinta.<br />
<br />
Después de esto solo nos queda sobreescribir el método <i>paintComponent()</i> del panel donde mostraremos la imagen para utilizar los parámetros de nivel de zoom y claves de renderizado que elegimos y ya lo tendremos todo armado.<br />
<br />
<pre class="brush: js">package imageZoom;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.net.URL;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class ZoomPanel extends JPanel {
private BufferedImage originalImage;
public ZoomPanel(String pathToImage) {
originalImage = toBufferedImage(createImage(pathToImage).getImage());
initPanel();
}
private void initPanel(){
final Zoom zoom = new Zoom();
JButton plus = new JButton(new AbstractAction("+") {
@Override
public void actionPerformed(ActionEvent e) {
zoom.increaseZoom();
}
});
JButton minus = new JButton(new AbstractAction("-") {
@Override
public void actionPerformed(ActionEvent e) {
zoom.decreaseZoom();
}
});
this.setLayout(new BorderLayout());
this.add(minus, BorderLayout.WEST);
this.add(zoom, BorderLayout.CENTER);
this.add(plus, BorderLayout.EAST);
}
private class Zoom extends JPanel {
private float xScaleFactor = 1;
private float yScaleFactor = 1;
public void increaseZoom() {
xScaleFactor+= 0.1;
yScaleFactor+= 0.1;
repaint();
}
public void decreaseZoom() {
xScaleFactor-= 0.1;
yScaleFactor-= 0.1;
repaint();
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
int newW = (int) (originalImage.getWidth() * xScaleFactor);
int newH = (int) (originalImage.getHeight() * yScaleFactor);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.clearRect(0, 0, getWidth(), getHeight());
g2.drawImage(originalImage, 0, 0, newW, newH, null);
}
}
private ImageIcon createImage(String path) {
URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
/**
* Obtiene una BufferedImage a partir de una Image.
* return BufferredImage bi
*/
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
image = new ImageIcon(image).getImage();
boolean hasAlpha = hasAlpha(image);
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
int transparency = Transparency.OPAQUE;
if (hasAlpha) {
transparency = Transparency.BITMASK;
}
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
Graphics g = bimage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
/**
* Devuelve true si una imagen tiene pixeles transparentes.
*
* @param image a testear
* @return true si tiene pixeles transparentes
*/
public static boolean hasAlpha(Image image) {
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}
ColorModel cm = pg.getColorModel();
return cm.hasAlpha();
}
}
</pre><br />
Lo que obtendríamos sería algo similar a esto que os muestro.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZhpUkcnv2rfSNQW1LJSEaRqmj1dzZam12_6tI2tDgZwIdPlLSPSQ7LQDjFOhHanBxTk0ZhNbseV0TNZQJY1aRkCKcs90NtifDuwqyCjcozgkIHNttAXf3gfiJbMvbngdIpTfC_8TLleQL/s1600/zoom_panel.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZhpUkcnv2rfSNQW1LJSEaRqmj1dzZam12_6tI2tDgZwIdPlLSPSQ7LQDjFOhHanBxTk0ZhNbseV0TNZQJY1aRkCKcs90NtifDuwqyCjcozgkIHNttAXf3gfiJbMvbngdIpTfC_8TLleQL/s400/zoom_panel.JPG" width="400" /></a></div><br />
<br />
<br />
Para lanzar la aplicación de ejemplo, lanzar el código siguiente sustituyendo "images/ER.jpg" por una imagen de vuestro equipo y lo podréis ver en acción.<br />
<br />
<pre class="brush: js">package imageZoom;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Launch {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Zoom a imagen");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ZoomPanel zoom = new ZoomPanel("images/ER.jpg");
frame.add(zoom);
frame.setPreferredSize(new Dimension(485,300));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Saludos y hasta pronto, ya sabéis que se agradecen los comentarios.<br />Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com3tag:blogger.com,1999:blog-6677093975106556207.post-4038588619828956922012-03-21T17:13:00.000+01:002012-03-21T17:14:23.814+01:00GradientPaint demo, ejemplos del uso de gradientes en javaHoy hablaremos de los gradientes o degradados de color tan usados como relleno del fondo en multitud de situaciones.<br />
Para ponernos en situación explicaremos primero que es un gradiente.<br />
Básicamente un gradiente nos permite rellenar una forma con una degradación lineal del color. Es decir, si tenemos un punto A con un color <i>X</i> y un punto B con otro color <i>Y</i>, el espacio entre ambos puntos va cambiando progresivamente de color desde el color <i>X</i> al color <i>Y</i>.<br />
<br />
Una vez aclarado esto, paso a enseñaros unos ejemplos del uso de gradientes. Para crearlos haremos uso de la clase <i>GradientPaint</i> que nos permite aplicar esta degradación de color entre 2 puntos que explicábamos arriba.<br />
Los constructores de esta clase nos permiten especificar los 2 puntos y los 2 colores que utilizaremos para crear el gradiente.<br />
<br />
<pre class="brush: js">GradientPaint gp = new GradientPaint(Point2D pt1, Color color1, Point2D pt2, Color color2, boolean cyclic);
</pre><br />
Estos puntos podemos especificarlos mediante un objeto <i>Point</i> o bien mediante coordenadas:<br />
<br />
<pre class="brush: js">GradientPaint gp = new GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2, boolean cyclic);
</pre><br />
El último parámetro indica si el gradiente debe repetirse en todo el espacio de manera cíclica o si fuera del espacio contenido entre ambos puntos el color debe ser sólido.<br />
<br />
Pasamos ahora a ver algunos ejemplos del uso de gradientes.<br />
<br />
<u>Gradiente horizontal</u><br />
<br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class HorizontalGradientPanel extends JPanel {
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/*
* Para crear un gradiente horizontal,
* las coordenadas a usar seran del {0,0} al {anchura del componente, 0}
*/
GradientPaint horizontalGradient = new GradientPaint(0, 0, Color.RED, getWidth(), 0, Color.BLUE);
g2d.setPaint(horizontalGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
</pre><br />
<u>Gradiente vertical</u><br />
<br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class VerticalGradientPanel extends JPanel {
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/*
* Para crear un gradiente vertical,
* las coordenadas a usar seran del {0,0} al {0, altura del componente}
*/
GradientPaint verticalGradient = new GradientPaint(0, 0, Color.GREEN, 0, getHeight(), Color.YELLOW);
g2d.setPaint(verticalGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
</pre><br />
<u>Gradiente diagonal</u><br />
<u><br />
</u><br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class DiagonalGradientPanel extends JPanel {
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/*
* Para crear un gradiente diagonal,
* las coordenadas a usar seran del {0,0} al {anchura del componente / ,
* altura del componente / 2}
*/
GradientPaint diagonalGradient = new GradientPaint(0, 0, Color.GRAY, getWidth() / 2, getHeight() / 2, Color.ORANGE);
g2d.setPaint(diagonalGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
</pre><br />
<u>Gradiente redondo</u><br />
Este degradado es un tanto especial, no usaremos la clase <i>GradientPaint</i> para crearlo, en lugar de eso implementaremos nuestro propio <i>Paint</i>. La interfaz <i>Paint</i> define como generar los patrones de color usados para operar con <i>Graphics2D</i>. Este ejemplo no es tan fácil de entender como los demás que exponemos en esta entrada, pero podéis reutilizar el código a placer.<br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.PaintContext;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import javax.swing.JPanel;
public class RoundGradientPanel extends JPanel {
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/* Para crear un gradiente circular. */
RoundGradient roundGradient = new RoundGradient(getWidth() / 2, getHeight() / 2, Color.PINK, new Point(0, 100), Color.CYAN);
g2d.setPaint(roundGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
private class RoundGradient implements Paint {
protected Point2D point;
protected Point2D mRadius;
protected Color color1, color2;
public RoundGradient(double x, double y, Color color1, Point2D radius, Color color2) {
if (radius.distance(0, 0) <= 0) {
throw new IllegalArgumentException("Radius must be greater than 0.");
}
point = new Point2D.Double(x, y);
this.color1 = color1;
mRadius = radius;
this.color2 = color2;
}
@Override
public int getTransparency() {
int a1 = color1.getAlpha();
int a2 = color2.getAlpha();
return (((a1 & a2) == 0xff) ? OPAQUE
: TRANSLUCENT);
}
@Override
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds,
AffineTransform xform, RenderingHints hints) {
Point2D transformedPoint = xform.transform(point, null);
Point2D transformedRadius = xform.deltaTransform(mRadius, null);
return new RoundGradientContext(transformedPoint, color1, transformedRadius, color2);
}
}
private class RoundGradientContext implements PaintContext {
protected Point2D mPoint;
protected Point2D mRadius;
protected Color color1, color2;
public RoundGradientContext(Point2D p, Color c1, Point2D r, Color c2) {
mPoint = p;
color1 = c1;
mRadius = r;
color2 = c2;
}
public void dispose() {
}
public ColorModel getColorModel() {
return ColorModel.getRGBdefault();
}
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h);
int[] data = new int[w * h * 4];
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
double distance = mPoint.distance(x + i, y + j);
double radius = mRadius.distance(0, 0);
double ratio = distance / radius;
if (ratio > 1.0)
ratio = 1.0;
int base = (j * w + i) * 4;
data[base + 0] = (int) (color1.getRed() + ratio * (color2.getRed() - color1.getRed()));
data[base + 1] = (int) (color1.getGreen() + ratio * (color2.getGreen() - color1.getGreen()));
data[base + 2] = (int) (color1.getBlue() + ratio * (color2.getBlue() - color1.getBlue()));
data[base + 3] = (int) (color1.getAlpha() + ratio * (color2.getAlpha() - color1.getAlpha()));
}
}
raster.setPixels(0, 0, w, h, data);
return raster;
}
}
}
</pre><br />
<u>Gradiente horizontal cíclico</u><br />
<br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class HorizontalCyclicGradientPanel extends JPanel {
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/*
* Para crear un gradiente horizontal cíclico, simplemente especificar
* la anchura del color
* y crear el gradiente con la propiedad cíclica a "true"
*/
GradientPaint diagonalGradient = new GradientPaint(0, 0, Color.RED, 20, 0, Color.BLUE, true);
g2d.setPaint(diagonalGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
</pre><br />
<u>Gradiente vertical cíclico</u><br />
<br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class VerticalCyclicGradientPanel extends JPanel {
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/*
* Para crear un gradiente horizontal cíclico, simplemente especificar
* la altura del color
* y crear el gradiente con la propiedad cíclica a "true"
*/
GradientPaint diagonalGradient = new GradientPaint(0, 0, Color.GREEN, 0, 20, Color.YELLOW, true);
g2d.setPaint(diagonalGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
</pre><br />
Este sería el resultado de juntar todos estos ejemplos en un panel.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBAkoD3JgwU0Jgltfi8xoKm5VvokjdeHkVNtScUBtP1lEed9rD67y__V6xAmXuqLgKQqmVQmFPgTAB3X4YItvV8W-Ciu3XbZjXAyX4g_9lsgqa1qmsNuqukiT4oseP_WXSSdLe342zGEHv/s1600/gradient_demo.JPG" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="398" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBAkoD3JgwU0Jgltfi8xoKm5VvokjdeHkVNtScUBtP1lEed9rD67y__V6xAmXuqLgKQqmVQmFPgTAB3X4YItvV8W-Ciu3XbZjXAyX4g_9lsgqa1qmsNuqukiT4oseP_WXSSdLe342zGEHv/s400/gradient_demo.JPG" /></a></div><br />
Para ver todo esto en funcionamiento, aquí os dejo la clase que carga la aplicación.<br />
<br />
<pre class="brush: js">package gradientPaintDemo;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GradientsDemo extends JPanel {
private static void createAndShowGUI() {
// Crea y prepara la ventana.
JFrame frame = new JFrame("Ejemplos de gradientes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(3, 3, 10, 10));
frame.getContentPane().add(new HorizontalGradientPanel());
frame.getContentPane().add(new VerticalGradientPanel());
frame.getContentPane().add(new DiagonalGradientPanel());
frame.getContentPane().add(new RoundGradientPanel());
frame.getContentPane().add(new HorizontalCyclicGradientPanel());
frame.getContentPane().add(new VerticalCyclicGradientPanel());
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Eso es todo por hoy, espero que lo aquí expuesto os haya sido útil de alguna manera.<br />
<br />
Un saludoAnonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com4tag:blogger.com,1999:blog-6677093975106556207.post-38655267026623036732012-03-07T17:39:00.000+01:002012-03-07T17:39:16.410+01:00Java GUI, Swing o AWTMuchas veces ante la necesidad de crear una interfaz gráfica nos vemos en la necesidad de decidir si utilizar Swing o AWT. Bien, veamos similitudes y diferencias entre uno y otro.<br />
<br />
<u>Un repaso a AWT</u><br />
<br />
AWT son las siglas de <i>Abstract Window ToolKit</i>, las herramientas originales de Java para crear interfaces gráficas.<br />
Es una librería GUI portable para aplicaciones autónomas y/o applets, proporciona la conexión entre nuestra aplicación y el GUI nativo.<br />
<br />
Las prestaciones de AWT incluyen:<br />
<br />
<ul><li>Un amplio grupo de componentes de usuario</li>
<li>Un modelo de manejo de eventos robusto</li>
<li>Herramientas gráficas y de imágenes (clases de Formas, colores y fuentes)</li>
<li>Manejadores de diseño que no dependen del tamaño de pantalla o resolución</li>
<li>Clases de transferencia de datos, para copiar-pegar a través del portapapeles de la plataforma</li>
</ul><br />
Los componentes de AWT dependen de componentes de código nativo, por lo que a los componentes se les suele llamar “heavyweight components” (componentes pesados).<br />
AWT está pensado para aplicaciones que corran en navegadores antiguos y definido con los mínimos de cualquier aplicación, es por esto que no incluye componentes complejos como pueden ser tablas, vistas de árbol, barras de progreso y otros.<br />
<br />
<u>Un vistazo a Swing</u><br />
<u><br />
</u><br />
Swing implementa un juego de componentes construidos sobre AWT y además proporciona un “look and feel” conectable/intercambiable. Está escrito 100% en código Java y basado en el framework <i>Lightweight UI </i>de la JDK 1.1.<br />
<br />
Sus características incluyen:<br />
<br />
<ul><li>Todas las prestaciones de AWT</li>
<li>Componentes 100% Java de las versiones de los componentes de AWT</li>
<li>Un rico conjunto de componentes de alto nivel (listas en árbol, paneles de pestañas, etc...)</li>
<li>Un diseño Java puro, no depende de terceros.</li>
<li>Look and feel intercambiable</li>
</ul><br />
Al no depender de componentes de la plataforma, a los componentes de Swing se les llama “lightweight components”.<br />
Swing es parte de las JFC (Java Foundation Classes), se creó para solucionar muchas de las limitaciones de AWT. Swing se creó como un bien diseñado, flexible y poderoso juego de herramientas GUI.<br />
<br />
Si nos paramos a comparar sus componentes, vemos que son bastante similares. Os dejo una tabla con la correspondencia de algunos componentes AWT con su análogo Swing.<br />
<br />
<table><tbody>
<tr><th>AWT</th><th>Swing</th></tr>
<tr><td>Applet</td><td>JApplet</td></tr>
<tr><td>Frame</td><td>JFrame</td></tr>
<tr><td>Window</td><td>JWindow</td></tr>
<tr><td>Dialog</td><td>JDialog</td></tr>
<tr><td>Component</td><td>JComponent</td></tr>
<tr><td>Panel</td><td>JPanel</td></tr>
<tr><td>Button</td><td>JButton</td></tr>
<tr><td>Canvas</td><td>Panel</td></tr>
<tr><td>Checkbox</td><td>JCheckBox o JRadioButton</td></tr>
<tr><td>Choice</td><td>JComboBox</td></tr>
<tr><td>Label</td><td>JLabel</td></tr>
<tr><td>List</td><td>JList</td></tr>
<tr><td>TextArea</td><td>JTextArea</td></tr>
<tr><td>TextField</td><td>JTextField</td></tr>
<tr><td>Menu</td><td>JMenu</td></tr>
<tr><td>MenuItem</td><td>JMenuItem</td></tr>
</tbody></table><br />
Como conclusión, podríamos decir que si queremos que nuestra aplicación corra en cualquier entorno, independientemente de la antigüedad del mismo, deberíamos usar AWT; ahora bien, si lo que queremos es una herramienta potente, flexible, usar tablas y otros componentes complejos; y completamente adaptable a nuestras necesidades, desde luego nuestra decisión está clara, usaremos la tecnología Swing.<br />
<br />
Como punto final vamos a ver como crear un programa sencillo, un panel al que añadimos 2 botones, usando ambas tecnologías para poder ver las diferencias.<br />
<br />
Ejemplo con AWT<br />
<pre class="brush: js">package AWTvsSwing;
import java.applet.Applet;
import java.awt.Button;
import java.awt.FlowLayout;
public class MainAWT extends Applet {
@Override
public void init() {
Button button1 = new Button();
button1.setLabel("My Button 1");
Button button2 = new Button("My Button 2");
setLayout(new FlowLayout());
add(button1);
add(button2);
}
}
</pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpfCpWymswErYwwFf_bXHeys2-Tfpf2ilOBxdE6dIxXyizg42qbF1gZvjWjzuRk3bMforW3APLS4KN-VKthVRTCOAhQuZxPiYgC7vOQmWeBTo78HgWVeHmxhrTwoNWeHbs6CVX0qskmiwS/s1600/awt_applet.JPG" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="286" width="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpfCpWymswErYwwFf_bXHeys2-Tfpf2ilOBxdE6dIxXyizg42qbF1gZvjWjzuRk3bMforW3APLS4KN-VKthVRTCOAhQuZxPiYgC7vOQmWeBTo78HgWVeHmxhrTwoNWeHbs6CVX0qskmiwS/s400/awt_applet.JPG" /></a></div><br />
Ejemplo con Swing<br />
<pre class="brush: js">package AWTvsSwing;
import java.awt.FlowLayout;
import javax.swing.JApplet;
import javax.swing.JButton;
public class MainSwing extends JApplet {
@Override
public void init() {
JButton button1 = new JButton();
button1.setText("My Button 1");
JButton button2 = new JButton("My Button 2");
setLayout(new FlowLayout());
add(button1);
add(button2);
}
}
</pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkz3E1THafvprXtoLr_X8UI8iWmB-63YTfgw-DuJFvh-FJ9QTTdEwrLMoHSvBpBnPWAufhCoDhw78pEbL_jHNgZ-gy1_KAUoCTctGoiiRly_jkd40Ua3CRp9upLw_XTWVTXIA3qVuL8cVF/s1600/swing_applet.JPG" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="287" width="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkz3E1THafvprXtoLr_X8UI8iWmB-63YTfgw-DuJFvh-FJ9QTTdEwrLMoHSvBpBnPWAufhCoDhw78pEbL_jHNgZ-gy1_KAUoCTctGoiiRly_jkd40Ua3CRp9upLw_XTWVTXIA3qVuL8cVF/s400/swing_applet.JPG" /></a></div>Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com0tag:blogger.com,1999:blog-6677093975106556207.post-4062197180359881032012-02-20T17:37:00.000+01:002012-02-20T17:37:08.374+01:00Bordes Java Swing, BorderFactory y ejemplosA cualquier <i>JComponent</i> se le puede poner uno o mas bordes. Un objeto <i>Border </i>sabe como dibujar los límites de un componente Swing y además de para dibujar lineas o cualquier otro aspecto visual, se pueden utilizar por ejemplo para dar mayor tamaño a los componentes.<br />
<br />
Para establecer un borde a un componente debemos usar el método <i>setBorder(Border border)</i>.<br />
En otro <a href="http://swing-facil.blogspot.com/2011/05/bordes-redondeados-creando-nuestro.html">tutorial</a> ya enseñamos con anterioridad como definir nuestros propios bordes, hoy os enseñaré el uso de la clase <i>BorderFactory</i> que nos permite crear la mayoría de los tipos de bordes que Swing puede crear.<br />
<br />
Veamos unos ejemplos de como crear los bordes mas comunes y las opciones que tenemos. En el código podéis leer comentarios sobre que tipos de bordes podemos crear con <i>BorderFactory</i>.<br />
<br />
<pre class="brush: js">package borderFactory;
import java.awt.Color;
import java.awt.Container;
import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
public class BorderSamples extends JPanel {
/**
* Constructor.
*/
public BorderSamples() {
super();
addComponents();
}
/**
* Añade los componentes.
*/
private void addComponents() {
// Borde vacio con 10px por cada lado
Border empty = BorderFactory.createEmptyBorder(10, 10, 10, 10);
/** Bordes simples */
// Borde de color rojo con grosor de linea de 2px
Border line = BorderFactory.createLineBorder(Color.RED, 2);
// Bordes biselado de varios colores
Border bevelRaised = BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.BLUE, Color.GREEN, Color.BLACK, Color.RED);
Border bevelLowered = BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.BLUE, Color.GREEN, Color.BLACK, Color.RED);
// Bordes grabados de varios colores
Border etchedRaised = BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.RED, Color.GRAY);
Border etchedLowered = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.RED, Color.GRAY);
/** Bordes mate */
/* En este tipo de bordes podemos elegir el grosor de cada uno de los lados y el color con el que pintarlo*/
Border matte = BorderFactory.createMatteBorder(3, 3, 5, 5, Color.ORANGE);
URL imgURL = getClass().getResource("images/star.png");
ImageIcon ico = new ImageIcon(imgURL);
/* Ademas de elegir el grosor podemos establecer una icono como imagen de fondo del borde. */
Border matteIco = BorderFactory.createMatteBorder(10, 10, 0, 20, ico);
/** Bordes compuestos */
/* El TitledBorder añade una etiqueta al borde que utilizamos para crearlo,
* podemos elegir la posición del texto */
Border titled = BorderFactory.createTitledBorder(line, "titulo", TitledBorder.CENTER, TitledBorder.TOP, null, Color.BLUE);
/* Un CompoundBorder lo creamos por la combinación de 2 bordes simples. */
Border compound = BorderFactory.createCompoundBorder(titled, etchedRaised);
// Paneles
JPanel simplePanel = new JPanel();
JPanel mattePanel = new JPanel();
JPanel compoundPanel = new JPanel();
simplePanel.setLayout(new BoxLayout(simplePanel, BoxLayout.Y_AXIS));
mattePanel.setLayout(new BoxLayout(mattePanel, BoxLayout.Y_AXIS));
compoundPanel.setLayout(new BoxLayout(compoundPanel, BoxLayout.Y_AXIS));
createComponent("LineBorder", line, simplePanel);
createComponent("EmptyBorder", empty, simplePanel);
createComponent("BevelBorder elevado", bevelRaised, simplePanel);
createComponent("BevelBorder rebajado", bevelLowered, simplePanel);
createComponent("EtchedBorder elevado", etchedRaised, simplePanel);
createComponent("EtchedBorder rebajado", etchedLowered, simplePanel);
createComponent("MatteBorder", matte, mattePanel);
createComponent("MatteBorder con icono", matteIco, mattePanel);
createComponent("TitledBorder", titled, compoundPanel);
createComponent("CompoundBorder", compound, compoundPanel);
simplePanel.setBorder(BorderFactory.createTitledBorder("Bordes simples"));
mattePanel.setBorder(BorderFactory.createTitledBorder("Bordes mate"));
compoundPanel.setBorder(BorderFactory.createTitledBorder("Bordes compuestos"));
this.add(simplePanel);
this.add(mattePanel);
this.add(compoundPanel);
}
/**
* Crea un panel al que le inserta un label con el texto especificado,
* le establece el borde deseado y lo inserta
* en el contenedor que le pasamos como parametro
* @param text Texto de la etiqueta
* @param border Borde a establecer
* @param container Contenedor a usar
*/
private void createComponent(String text, Border border, Container container) {
JPanel panel = new JPanel();
JLabel label = new JLabel(text);
label.setBorder(border);
panel.add(label);
container.add(panel);
}
}
</pre><br />
Este sería el resultado de aplicar a las etiquetas creadas cada uno de los distintos bordes.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYHjF26Ru3A5RhPtNU60-IrA1gzhvFafpywK3r4HklIoz5u77uoKDvKwM8KAi9vI0bVv39OZQKePgRpVmmfd-QZdF7YWPDdw7xVbmOlIcxbU3wolGougmhXpLYCTWvm-IMCSKtz2Yzaa1I/s1600/bordes.JPG" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="400" width="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYHjF26Ru3A5RhPtNU60-IrA1gzhvFafpywK3r4HklIoz5u77uoKDvKwM8KAi9vI0bVv39OZQKePgRpVmmfd-QZdF7YWPDdw7xVbmOlIcxbU3wolGougmhXpLYCTWvm-IMCSKtz2Yzaa1I/s400/bordes.JPG" /></a></div><br />
Y para lanzar la aplicación de ejemplo.<br />
<br />
<pre class="brush: js">package borderFactory;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Ejemplos de uso de BorderFactory");
BorderSamples panel = new BorderSamples();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(350, 450);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Por supuesto hay muchas más opciones que explotar, pero esa tarea de investigación la dejo para vosotros :)<br />
Esto es todo por hoy, gracias por leerme y espero haberos sido de ayuda.Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com1tag:blogger.com,1999:blog-6677093975106556207.post-58886029452152960212012-02-09T13:40:00.000+01:002012-02-09T13:40:17.388+01:00BorderLayout y GridLayout, ejemplos de layouts en javaHola a todos, hoy vamos a hablar sobre la manera en la que disponemos los componentes Swing en los contenedores de nuestras aplicaciones. Es aquí donde los <i>LayoutManager </i>entran en juego. Por ejemplo cuando hacemos:<br />
<br />
<pre class="brush: js">JPanel panel = new JPanel();
for(int i = 0; i < 10; i++) {
panel.add(new JLabel("Etiqueta " + i));
}
</pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcZjZ_I43q6Eke_oIB8HYmQ-sUawlTQefUaWQkhRSAWBJDN7TPZHFXi6_iwBT21trjNEJDic-6xzn63jjhz9qQ7tESY2mRUPlFFo4ncQ8VoL1JYI5RVdWUTXiCOZrJsojkIyLYS_s_DNzV/s1600/FlowLayout.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="101" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcZjZ_I43q6Eke_oIB8HYmQ-sUawlTQefUaWQkhRSAWBJDN7TPZHFXi6_iwBT21trjNEJDic-6xzn63jjhz9qQ7tESY2mRUPlFFo4ncQ8VoL1JYI5RVdWUTXiCOZrJsojkIyLYS_s_DNzV/s400/FlowLayout.PNG" width="400" /></a></div>
Las etiquetas que estamos añadiendo se disponen en fila de izquierda a derecha, esto es porque al crear un panel, por defecto tiene establecido un FlowLayout.
Este dispondrá de esta manera los componentes, con una separación de 10 pixeles entre componentes hasta que no quepan mas componentes en la misma línea, momento en el cual saltará a la siguiente.
Pero no debemos limitarnos a la manera de disponer los componentes por defecto, vamos a pasar a explicar dos de los <i>LayoutManager </i>que mas se usan. Estos son: <i>BorderLayout </i>y <i>GridLayout</i>.<br />
<br />
<b><span style="font-size: large;">BorderLayout </span></b><br />
<br />
Una disposición Border, dispone un contenedor ordenando y redimensionando sus componentes para adaptarse a cinco regiones: NORTE, SUR, ESTE, OESTE y CENTRO.<br />
Cada una de estas regiones está definida por constantes propias de la clase BordeLayout:<br />
<br />
<ul>
<li>BorderLayout.NORTH </li>
<li>BorderLayout.SOUTH </li>
<li>BorderLayout.EAST </li>
<li>BorderLayout.WEST </li>
<li>BorderLayout.CENTER </li>
</ul>
Para utilizarlo, bastará con especificar una de estas constantes como limitación al añadir el componente.<br />
<br />
<pre class="brush: js">JPanel panel = new JPanel();
//Establecemos el BorderLayout al panel
panel.setLayout(new BorderLayout(10, 10));
panel.add(new JButton(“boton”), BorderLayout.CENTER);
</pre>
Por conveniencia si no especificamos ninguna de estas constantes el componente se insertará en el centro del contenedor.
El constructor BorderLayout(int hgap, int vgap) nos permite especificar el espacio en pixeles que existirá entre los componentes en el contenedor, así por ejemplo para hacer que entre los componentes exista un espacio horizontal de 10 pixeles y otro vertical de 20 pixeles bastaría con:
<br />
<pre class="brush: js">BorderLayout layout = new BorderLayout(10, 20);
</pre>
Si no especificamos ningún espacio, por defecto no habrá separación entre los componentes.
Veamos un ejemplo real de como usarlo:
<br />
<pre class="brush: js">package layout.borderLayout;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
public class BorderLayoutPanel extends JPanel {
public BorderLayoutPanel() {
// establecemos el layout
this.setLayout(new BorderLayout(5, 10));
init();
}
/**
* Añadimos componentes
*/
private void init() {
JButton north = new JButton("NORTH");
JButton south = new JButton("SOUTH");
JButton east = new JButton("EAST");
JButton west = new JButton("WEST");
JButton center = new JButton("CENTER");
this.add(north, BorderLayout.NORTH);
this.add(south, BorderLayout.SOUTH);
this.add(east, BorderLayout.EAST);
this.add(west, BorderLayout.WEST);
this.add(center, BorderLayout.CENTER);
}
}
</pre>
Este código nos creará un panel al que se le establece un <i>BorderLayout </i>con 5 pixeles de separación horizontal entre los componentes y 10 pixeles de separación vertical.<br />
Para verlo en funcionamiento:
<br />
<pre class="brush: js">package layout.borderLayout;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Ejemplos de uso de layouts");
BorderLayoutPanel panel = new BorderLayoutPanel();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre>
<br />
Y este sería el resultado.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdtzdaPkiJFGeD79unDBqsvmoaCkfHhB0Ypxs2sL3Ah4qAdb-Fuq2TEOn4cQ5xACTwWHEwGZycLFa2BF2VaMcJgGJdZINl5oA9qkUikIFnouoN_gW8T3H7A0v0LaJzAUcjSzQ5eb-iPf67/s1600/BorderLayout.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="399" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdtzdaPkiJFGeD79unDBqsvmoaCkfHhB0Ypxs2sL3Ah4qAdb-Fuq2TEOn4cQ5xACTwWHEwGZycLFa2BF2VaMcJgGJdZINl5oA9qkUikIFnouoN_gW8T3H7A0v0LaJzAUcjSzQ5eb-iPf67/s400/BorderLayout.PNG" width="400" /></a></div>
<b><span style="font-size: large;"><br /></span></b><br />
<b><span style="font-size: large;">GridLayout</span></b><br />
<br />
<b><span style="font-size: large;"></span></b>El <i>GridLayout </i>dispone los componentes de un contenedor en una rejilla rectangular. El contenedor se dividirá en rectangulos iguales y en cada uno se colocará uno de los componentes.
A la hora de construir este layout debemos especificar el número de filas y columnas que necesitamos para nuestros componentes, para ello usaremos el siguiente constructor <i>GridLayout(int rows, int cols)</i> , además si queremos controlar el espacio que existirá entre los componentes en el contenedor de manera similar a como hicimos con <i>BorderLayout </i>podemos usar este otro:<i> GridLayout(int rows, int cols, int hgap, int vgap)</i>.
Pasemos a un ejemplo que nos aclaré más las cosas, por ejemplo digamos que queremos disponer 10 JButton en un panel de manera que se distribuyan en 2 filas y 5 columnas, con una separación horizontal de 15 pixeles y una separación vertical de 5 pixeles.
Aquí os dejo el código que configuraría el panel:
<br />
<pre class="brush: js">package layout.gridLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
public class GridLayoutPanel extends JPanel {
public GridLayoutPanel() {
// establecemos el layout
this.setLayout(new GridLayout(2, 5, 15, 5));
init();
}
/**
* Añadimos componentes
*/
private void init() {
for(int i = 0; i < 10; i++) {
this.add(new JButton("Boton " + i));
}
}
}
</pre>
Para verlo en funcionamiento:
<br />
<pre class="brush: js">package layout.gridLayout;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Ejemplos de uso de layouts");
GridLayoutPanel panel = new GridLayoutPanel();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre>
Y este sería el aspecto que tendría este contenedor.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCmbUelWMCAuaxbDc1gthetl7bIm5meVs_Pt716u3NTnzSYvhgCf4SSMeomlf9AV7_uXHpOYRiH1g7bZACXzsMGViDJkARzsnKIB5w10IJIc6-MpxmwIsufQ_WCl0VurJ81U_B6AKA7Xn_/s1600/GridLayout.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="321" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCmbUelWMCAuaxbDc1gthetl7bIm5meVs_Pt716u3NTnzSYvhgCf4SSMeomlf9AV7_uXHpOYRiH1g7bZACXzsMGViDJkARzsnKIB5w10IJIc6-MpxmwIsufQ_WCl0VurJ81U_B6AKA7Xn_/s400/GridLayout.PNG" width="400" /></a></div>
<br />
<br />
<br />
Podríamos hablar largo y tendido sobre <i>LayoutManager </i>en Java, pero esto será tema de siguiente artículos.<br />
<br />
Un saludo y gracias por leerme.Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com4tag:blogger.com,1999:blog-6677093975106556207.post-86251308056561995252012-01-18T10:22:00.000+01:002012-01-18T10:22:01.053+01:00JButton, JCheckBox, JComboBox en JTable<br />
El componente <i>JTable </i>es uno de los mas complejos que nos ofrece el paquete <i>Swing </i>en cuanto a diseño de interfaces se refiere, precisamente por su complejidad también permite una personalización casi absoluta del componente.<br />
<br />
La clase <i>JTable </i>sirve para mostrar tablas de datos, permitiendo opcionalmente al usuario editar los datos. Los <i>JTable </i>no contienen ni almacenan datos, simplemente es una manera de mostrarlos.<br />
Los <i>JScrollPane </i>son los componentes que habitualmente sirven como contenedor para los <i>JTable</i>, este automáticamente coloca la cabecera de la tabla en la parte superior de la vista de manera que los nombres de las columnas permanecen visibles cuando hacemos “scroll”.<br />
<br />
El encargado de decirnos <i><b>como se muestra</b></i> un valor en cada celda es el <i>TableCellRenderer</i>, esta interfaz define el método requerido por un objeto que querría ser dibujado en las celdas de un JTable.<br />
Así mismo, el encargado de decirnos <i><b>como se comporta</b></i> cada celda es el <i>TableCellEditor</i>, una interfaz que define el método que cualquier objeto que querría ser editor de valores de un <i>JTable </i>necesita implementar.<br />
<br />
Otro de los componentes mas importantes es el <i>TableModel</i>, esta interfaz especifica los métodos que el <i>JTable </i>usará para interrogar a un modelo de datos tabulado. Un <i>JTable </i>puede configurarse para mostrar cuanlquier modelo de datos que implemente esta interfaz con solo un par de líneas de código:<br />
<br />
<pre class="brush: js">MyTableModel model = new MyTableModel(columnNames, data);
// Establecemos el modelo
JTable table = new JTable(model);
</pre>
<br />
En nuestro ejemplo de hoy, explicamos como mostrar componentes complejos como <i>JCheckBox</i>, <i>JComboBox </i>y <i>JButton </i>en el interior de nuestras tablas.<br />
<br />
En primer lugar definiremos nuestro <i>TableModel</i>, en este estableceremos como queremos que nuestra tabla se comporte.<br />
<br />
<pre class="brush: js">package tablaCompleja.componentes;
import javax.swing.table.AbstractTableModel;
public class MyTableModel extends AbstractTableModel {
/** Nombre de las columnas. */
private String[] columnNames;
/** Datos. */
private Object[][] data;
/**
* Constructor.
* @param columnNames Nombres de las columnas
* @param data Datos de la tabla
*/
public MyTableModel(String[] columnNames, Object[][] data) {
this.columnNames = columnNames;
this.data = data;
}
@Override
public String getColumnName(int column) {
// Nombre de las columnas para la cabecera
return columnNames[column];
}
@Override
public int getRowCount() {
// Devuelve el número de filas
return data != null ? data.length : 0;
}
@Override
public int getColumnCount() {
// Devuelve el número de columnas
return columnNames.length;
}
/**
* Nos devolverá la clase que contiene cada columna,
* es necesario para trabajar correctamente con los componentes
* que mostraremos en la tabla.
*/
@Override
public Class getColumnClass(int columnIndex) {
Class clazz = Object.class;
Object aux = getValueAt(0, columnIndex);
if (aux != null) {
clazz = aux.getClass();
}
return clazz;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
// Devuelve el valor que se debe mostrar en la tabla en cada celda
return data[rowIndex][columnIndex];
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
// Si queremos que la tabla sea editable deberemos establecer estos valores
data[rowIndex][columnIndex] = aValue;
fireTableCellUpdated(rowIndex, columnIndex);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
// Permitimos editar todas las celdas de la tabla
return true;
}
/**
* Nos servira para limpiar la información de una fila
* @param row
*/
public void reset(int row) {
for (int i = 0; i < data[row].length - 1; i++) {
// Para las columnas con String
if (getColumnClass(i) == String.class) {
setValueAt("", row, i);
} else if(getColumnClass(i) == Boolean.class) {
setValueAt(false, row, i);
}
}
}
}
</pre>
Vamos a crear un <i>JTable </i>personalizado que heredará del <i>JTable </i>original, en esta clase vamos a ver como especificar que renderers y editors usaremos para cada columna dependiendo del tipo de objeto que contenga.
<br />
<pre class="brush: js">package tablaCompleja;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JTable;
import tablaCompleja.componentes.ButtonCellEditor;
import tablaCompleja.componentes.ButtonCellRenderer;
import tablaCompleja.componentes.MyTableModel;
public class MyTable extends JTable {
/**
* Constructor.
*/
public MyTable() {
this.setRowHeight(30);
JComboBox states = new JComboBox(new String[]
{"España",
"Argentina",
"EEUU"}
);
String [] columnNames = new String[]{ "Nombre", "email", "Fumador", "Nacionalidad", "" };
Object [][] data = new Object[][]{
{"Angel", "angelarcosheredia@gmail.com", false, "Click para elegir", new JButton("Reset")},
{"Juan", "juan@gmail.com", false, "Click para elegir", new JButton("Reset")},
{"Ana", "ana@hotmail.com", false, "Click para elegir", new JButton("Reset")}
};
MyTableModel model = new MyTableModel(columnNames, data);
// Establecemos el modelo
this.setModel(model);
// Establecemos el renderer y editor que usaremos para el boton
this.setDefaultRenderer(JButton.class, new ButtonCellRenderer());
this.setDefaultEditor(JButton.class, new ButtonCellEditor());
// Editores para cada tipo de objeto, estos nos permitirán darles el comportamiento adecuado
this.getColumn("Nacionalidad").setCellEditor(new DefaultCellEditor(states));
this.setDefaultEditor(JCheckBox.class, new DefaultCellEditor(new JCheckBox()));
}
}
</pre>
Como vemos en el código anterior los valores <i>boolean </i>se muestran automáticamente como un <i>JCheckBox</i>, y el <i>DefaultCellEditor </i>que es el editor por defecto que usa un <i>JTable </i>también se encargará de utilizar un <i>JComboBox </i>apropiadamente si se lo especificamos.
Para el renderizar y darle comportamiento a un <i>JButton </i>si tendremos que implementar nuestro propio renderer y editor. Aquí os dejo el código que, como podéis ver, no es nada complicado.
<br />
<pre class="brush: js">package tablaCompleja.componentes;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class ButtonCellRenderer implements TableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
// Devolvemos el botón tal cual
if (value instanceof JButton) {
return (JButton) value;
}
return null;
}
}
</pre>
<pre class="brush: js">package tablaCompleja.componentes;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {
/** Componente que estamos editando. */
private Component currentValue;
@Override
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) {
JButton button = null;
if (value instanceof JButton) {
button = (JButton) value;
// Action que permite "limpiar" los valores de una fila
button.setAction(new AbstractAction("Reset") {
@Override
public void actionPerformed(ActionEvent e) {
((MyTableModel) table.getModel()).reset(row);
}
});
}
currentValue = button;
return button;
}
@Override
public Object getCellEditorValue() {
return currentValue;
}
}
</pre>
Y ahora ya solo nos queda el fragmento de código para echar a andar nuestro ejemplo:
<br />
<pre class="brush: js">package tablaCompleja.componentes;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.TableCellEditor;
public class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {
/** Componente que estamos editando. */
private Component currentValue;
@Override
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) {
JButton button = null;
if (value instanceof JButton) {
button = (JButton) value;
// Action que permite "limpiar" los valores de una fila
button.setAction(new AbstractAction("Reset") {
@Override
public void actionPerformed(ActionEvent e) {
((MyTableModel) table.getModel()).reset(row);
}
});
}
currentValue = button;
return button;
}
@Override
public Object getCellEditorValue() {
return currentValue;
}
}
</pre>
<br />
Espero haberos aclarado un poco más como funciona un <i>JTable </i>y que todo esto os haya sido útil de alguna manera.<br />
<br />
Un saludo y hasta pronto.<br />
<br />Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com11tag:blogger.com,1999:blog-6677093975106556207.post-39260052966857571692011-12-19T17:23:00.000+01:002011-12-20T08:58:41.871+01:00RenderingHints, renderizados y operaciones de manipulación de imágenesHola otra vez, hoy vamos a profundizar un poco en las claves de la manipulación de imágenes y textos con <i>Graphics2D </i>y de como mejorar la resolución de los objetos u imágenes mostrados.<br />
Para ellos nos serviremos de la clase <i>RenderingHints </i>y le estableceremos los valores apropiados para los resultados que pretendemos obtener.<br />
<br />
La clase RenderingHints define y maneja una colección de claves y valores asociados que permite a una aplicación proporcionar entradas a las opciones de algoritmos usados por otras clases que realizan renderizados y manipulación de imágenes. La clase <i>Graphics2D</i>, y clases que implementan <i>BufferedImageOp</i> y <i>RasterOp</i> proporcionan métodos para obtener y establecer individualmente o grupos de claves RenderingHints y sus valores asociados. Cuando estas implementaciones realizan cualquier renderizado u operaciones de manipulación de imágenes deberían examinar estos valores que son requeridos por el llamante y adaptar los algoritmos usados en consecuencia y en la medida de su capacidad.<br />
<br />
A partir de aquí paso a explicar cada uno de los indicadores y como modifican el renderizado de los componentes.<br />
<br />
<b>KEY_ALPHA_INTERPOLATION </b><br />
La clave <b>ALPHA_INTERPOLATION </b>es una clave general que proporciona una recomendación de alto nivel para que haciendo uso de un algoritmo de mezcla de alpha elegir entre mayor velocidad o calidad al evaluar ventajas y desventajas en el renderizado.<br />
Esta clave controlaría la elección del factor alpha en los cálculos que sacrificarían algo de precisión para usar tablas de consulta rápida o reducir la precisión de la instrucciones <b>SIMD </b>(Single Instruction, Multiple Data). Esta clave también controlaría si un color y su valor alpha se convierten a un color linear durante los cálculos para un efecto visual mas lineal con el coste de hacer cálculos por pixel adicionales.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_ALPHA_INTERPOLATION_SPEED</li>
<li>VALUE_ALPHA_INTERPOLATION_QUALITY</li>
<li>VALUE_ALPHA_INTERPOLATION_DEFAULT</li>
</ul><div><br />
</div><br />
<b>KEY_ANTIALIASING </b><br />
Clave de suavizado. La clave <b>ANTIALIASING </b>controla si la representación geométrica en los métodos de un objeto <i>Graphics2D </i>intentará reducir el aliasing en los bordes de las formas.<br />
Un algoritmo de suavizado típico funciona fundiendo los colores existentes en la frontera de una forma con el color de relleno de acuerdo a la cobertura de pixeles parcial estimada de la forma.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_ANTIALIAS_ON</li>
<li>VALUE_ANTIALIAS_OFF</li>
<li>VALUE_ANTIALIAS_DEFAULT</li>
</ul><div><br />
</div><br />
<b>KEY_COLOR_RENDERING</b><br />
La clave <b>COLOR_RENDERING</b> controla la precisión de aproximaciones y conversiones al almacenamos colores en una imagen o superficie destino.<br />
Cuando al renderizar o realizar una operación de manipulación de imágenes se produce un valor de color que debe ser guardado en un destino, primero de debe convertir ese color en un tipo capaz de ser almacenado en la imagen o superficie destino. Como mínimo, las componentes del color deben ser convertidas a una representación de bits y ordenarse correctamente o un índice en una tabla de decisión de colores debe elegirse antes de que los datos sean guardados en la memoria destino. Si esta conversión mínima, los datos en el destino podrían perfectamente parecer aleatorios, incorrectos o incluso valores no soportados. Los algoritmos que se usan para convertir los resultados del renderizado rápidamente en el formato de color adecuado son muy conocidos y están bastante optimizados.<br />
Simplemente realizando las conversiones de formato de color más básicas para guardarlos en un destino puede ignorar una diferencia en el calibrado del <i>ColorSpace </i>del origen y destino u otros factores tales como la linealidad de la corrección gamma. A menos que el <i>ColorSpace </i>origen y destino sean idénticos, para realizar correctamente una operación de renderizado con teniendo el máximo cuidado en la precisión de los colores representados, los colores origen deben transformarse a un <i>ColorSpace </i>independiente del dispositivo donde se valla a mostrar y posteriormente convertirlos al <i>ColorSpace </i>destino. Aún más, si cálculos tales como la mezcla de múltiples colores origen se van a realizar durante la operación de renderizado, se puede obtener más claridad si el <i>ColorSpace </i>intermedio elegido tiene una relación lineal entre los valores que se están calculando y la percepción del ojo humano a las curvas de respuesta del dispositivo de salida.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_COLOR_RENDER_SPEED</li>
<li>VALUE_COLOR_RENDER_QUALITY</li>
<li>VALUE_COLOR_RENDER_DEFAULT</li>
</ul><br />
<br />
<b>KEY_DITHERING </b><br />
Clave de Dithering. La clave <b>DITHERING</b> controla como de cerca aproximar un color cuando lo almacenamos en un destino con una resolución de color limitada.<br />
Algunos destinos de renderizado pueden soportar un número limitado de colores lo cual puede que no permita representar el espectro completo de colores que podrían resultar durante las operaciones de renderizado. Para estos destinos, la clave <b>DITHERING </b>controla si el renderizado se realiza con un color de relleno sólido en un pixel específico que es de los colores permitido el mas cercano al que se solicita, o si las formas se rellenaran con un patrón de colores que se combinan para aproximarse lo máximo posible a este color deseado.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_DITHER_DISABLE</li>
<li>VALUE_DITHER_ENABLE</li>
<li>VALUE_DITHER_DEFAULT</li>
</ul><br />
<br />
<b>KEY_FRACTIONALMETRICS </b><br />
Clave de métricas fraccionadas en las fuentes. La clave <b>FRACTIONALMETRICS </b>controla si al posicionar los glifos de un carácter en particular se tiene en cuenta la precisión sub-pixel de los avances de carácter escalado de la fuente o si estos vectores de avance se redondean a un entero. Esta clave solo recomienda cuanta precisión debe usarse para posicionar los glifos y no especifica ni recomienda si la rasterización o las fronteras de pixel de un glifo deben modificarse para coincidir.<br />
Renderizar texto a un dispositivo de baja resolución como una pantalla necesariamente implicará una serie de operaciones de redondeo ya que la definición de alta calidad y muy precisa de la forma y métricas de los glifos de un carácter deben ajustarse a un número discreto de pixeles en el dispositivo. Idealmente el posicionado de los glifos durante la disposición del texto debería calcularse escalando las métricas diseñadas en la fuente de acuerdo al tamaño del punto, pero entonces el ancho del avance escalado no será necesariamente un número entero de pixeles. Si los glifos se posicionan con una precisión sub-pixel de acuerdo a estas métricas de diseño escaladas, entonces la rasterización idealmente necesitará ser ajustada para cada posible origen sub-pixel.<br />
Desafortunadamente, escalar cada glifo de manera personalizada a su origen sub-pixel exacto durante la disposición del texto sería prohibitivamente caro por lo que un sistema simplificado basado en las posiciones enteras de un dispositivo se usa para disponer el texto. La rasterización de un glifo y el ancho de avance escalado son ambos ajustados a la vez para conseguir que el texto se vea bien en la resolución del dispositivo y tenga distancias enteras de pixeles entre los glifos que ayude a que los glifos parezcan uniformes y consistentemente espaciados y legibles.<br />
Este proceso de redondeo del ancho del avance para los glifos rasterizados significa que la densidad de un carácter y la longitud promedia de una cadena de texto será diferente entre las medidas teóricas del diseño debido a la acumulación de una serie de pequeñas diferencias en los anchos ajustados de cada glifo. Cada diferencia específica será diferente en cada glifo, algunos siendo mas anchos y otros más estrechos que sus teóricos anchos de diseño. Así la diferencia global en la densidad de carácter y la longitud variará por un número de factores incluyendo la fuente, la resolución específica del dispositivo destino, y los glifos elegidos para representar la cadena que se está renderizando. Como resultado, renderizar la misma cadena en múltiples resoluciones puede arrojar métricas muy varadas sobre cadenas enteras.<br />
Cuando <b>FRACTIONALMETRICS </b>están habilitadas, las métricas de diseño originales se escalan a tamaño de punto y se usan para disponer con precisión sub-pixel. La densidad media de los glifos y la longitud total de una cadena larga de caracteres será por ello más aproximada al diseño teórico de la fuente, pero la legibilidad puede verse afectada ya que cada par individual de caracteres puede que no tengan distancias consistentes además dependiendo de como la acumulación sub-pixel de los orígenes de los glifos se engrane con la malla de pixeles del dispositivo. Habilitar esta indicación puede ser deseado cuando la disposición del texto que se realiza deba ser consistente a lo largo de una variedad de resoluciones de salida. Específicamente, esta indicación puede ser deseable en situaciones cuando la disposición del texto se previsualiza en dispositivos con baja resolución como una pantalla para salidas que serán eventualmente renderizadas en una impresora de alta resolución o dispositivo de composición.<br />
Cuando está deshabilitado, las métricas escaladas se redondean o ajustan a distancias enteras para disponerse. Las distancias entre cada par específico de glifos será mas uniforme en el dispositivo, pero la densidad y longitud total de cadenas largas puede que no coincida ya con las intenciones teóricas del diseñador de la fuente. Deshabilitar este indicador producirá normalmente resultados más legibles en dispositivos de baja resolución como monitores de ordenador.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_FRACTIONALMETRICS_OFF</li>
<li>VALUE_FRACTIONALMETRICS_ON</li>
<li>VALUE_FRACTIONALMETRICS_DEFAULT</li>
</ul><div><br />
</div><br />
<b>KEY_INTERPOLATION </b><br />
Clave de Interpolación. El indicador <b>INTERPOLATION </b>controla como los pixeles de las imágenes se filtran o remuestrean durante una operación de renderizado de imágenes.<br />
Implícitamente las imágenes se definen para proporcionar muestras de color en unas coordenadas enteras. Cuando las imágenes se renderizan tal cual sin escalado al destino, la elección de que pixeles de la imagen se mapean a que pixeles del dispositivo es obvio y las muestras en las coordenadas de la imagen se transfieren a los pixeles correspondientes en la rejilla de pixeles del destino uno a uno. Cuando las imágenes se renderizan en un sistema de coordenadas escalado, rotado o transformado de cualquier manera, entonces el mapeado de los pixeles del dispositivo con la imagen puede originar la pregunta de que muestra de color usar para las continuas coordenadas que existen entre las localizaciones enteras y las proporcionadas en las muestras de la imagen. Los algoritmos de interpolación definen funciones que proporcionan una muestra de color para una coordenada continua en una imagen basada en las muestras de color de las coordenadas colindantes.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_INTERPOLATION_NEAREST_NEIGHBOR → la muestra de color de la coordenada vecinas mas cercana en la imagen es la usada.</li>
<li>VALUE_INTERPOLATION_BILINEAR → la muestra de color se obtiene mediante interpolación lineal de las 4 coordenadas más cercanas.</li>
<li>VALUE_INTERPOLATION_BICUBIC → las muestras de color de 9 coordenadas cercanas en la imagen se interpolan usando una función cúbica en X e Y para producir la muestra de color.</li>
</ul><div><b>KEY_RENDERING</b></div><br />
Clave de renderizado. El indicador <b>RENDERING </b>es un indicador general que proporciona recomendaciones de alto nivel sobre como sesgar las opciones de un algoritmo hacia velocidad o calidad cuando evaluá pros y contras. El indicador puede ser consultado por cualquier renderizado u operación de manipulación de imágenes, pero las decisiones normalmente harán honor a otros indicadores mas específicos en relación a este indicador.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_RENDER_SPEED</li>
<li>VALUE_RENDER_QUALITY</li>
<li>VALUE_RENDER_DEFAULT</li>
</ul><br />
<br />
<b>KEY_STROKE_CONTROL </b><br />
Clave para normalización de trazo. El indicador <b>STROKE_CONTROL </b>controla si una implementación de renderizado debería o tiene permitido modificar la geometría de las formas renderizadas para varios fines.<br />
Algunas implementaciones podrían ser capaces de usar una librería optimizada de la plataforma que podría ser mas rápida que los algoritmos de renderizado software tradicionales en una plataforma dada, pero que podría no soportar coordenadas de punto flotante. Algunas implementaciones podrían también tener sofisticados algoritmos que perturban las coordenadas de un trazado de tal manera que las lineas anchas aparezcan mas uniformes en anchura y espaciado.<br />
Si una implementación realiza cualquier tipo de modificación o "normalización" de un trazado, debería mover las coordenadas mas de medio pixel en cada dirección.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_STROKE_NORMALIZE</li>
<li>VALUE_STROKE_PURE</li>
<li>VALUE_STROKE_DEFAULT</li>
</ul><br />
<br />
<b>KEY_TEXT_ANTIALIASING </b><br />
Clave de antialiasing de texto. El indicador <b>TEXT_ANTIALIASING </b>puede controlar el uso de algoritmos antialiasing para el texto independientemente de la elección para renderizado de formas. Muchas veces una aplicación puede querer usar antialiasing solo para texto y no para otras formas, Además, los algoritmos para reducir el solapamiento para texto suelen ser mas sofisticados que aquellos que se han desarrollado para renderizado general por lo que este indicador proporciona valores adicionales que pueden controlar las opciones de estos algoritmos específicos para texto. Si se deja en el valor <b>DEFAULT</b>, este indicador diferirá al valor del indicador general <b>KEY_ANTIALIASING</b>.<br />
Los posibles valores son:<br />
<br />
<ul><li>VALUE_TEXT_ANTIALIAS_ON → Antialiasing habilitado</li>
<li>VALUE_TEXT_ANTIALIAS_OFF → Antialiasing deshabilitado</li>
<li>VALUE_TEXT_ANTIALIAS_DEFAULT → El renderizado se realiza de acuerdo al valor del indicador <b>KEY_ANTIALIASING</b></li>
<li>VALUE_TEXT_ANTIALIAS_GASP → El renderizado requiere usar la información en el recurso de la fuente que especifica para cada tamaño de punto si usar o no los valores VALUE_TEXT_ANTIALIAS_ON o VALUE_TEXT_ANTIALIAS_OFF.</li>
<li>VALUE_TEXT_ANTIALIAS_LCD_HRGB → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de izquierda a derecha RGB, de tal manera que la resolución horizontal subpixel es tres veces la de la resolución de un pixel horizontal completo (HRGB).</li>
<li>VALUE_TEXT_ANTIALIAS_LCD_HBGR → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de izquierda a derecha BGR, de tal manera que la resolución vertical subpixel es tres veces la de la resolución de un pixel vertical completo (HBGR).</li>
<li>VALUE_TEXT_ANTIALIAS_LCD_VRGB → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de arriba a abajo RGB, de tal manera que la resolución horizontal subpixel es tres veces la de la resolución de un pixel horizontal completo (VRGB).</li>
<li>VALUE_TEXT_ANTIALIAS_LCD_VBGR → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de arriba a abajo BGR, de tal manera que la resolución vertical subpixel es tres veces la de la resolución de un pixel vertical completo (VBGR).</li>
</ul><br />
<br />
<b>KEY_TEXT_LCD_CONTRAST </b><br />
Clave de contraste de texto <b>LCD</b>. El valor es un valor <i>Integer </i>que se usa como un ajuste en el contraste del texto cuando se usa en conjunción con un indicador de antialiasing de texto <b>LCD </b>tal como <b>VALUE_TEXT_ANTIALIAS_LCD_HRGB</b>.<br />
Los valores deben ser enteros positivos en el rango 100 a 250.<br />
<br />
<ul><li>Un valor bajo (100) corresponde a texto con mayor contraste cuando se muestra texto oscuro en un fondo claro.</li>
<li>Un valor alto (200) corresponde a texto de bajo contraste cuando se muestra texto oscuro en un fondo claro.</li>
<li>Un valor típico esta en el estrecho rango 140-180.</li>
<li>Si no se especifica ningún valor, una implementación por defecto o del sistema será aplicada.</li>
</ul>El valor por defecto debería ser apropiado para la mayoría de los fines, por lo que los clientes raramente necesitan especificar un valor para este indicador a menos que tengan información concreta sobre un valor apropiado. Un valor más alto no significa mayor contraste, en realidad es al contrario. La corrección se aplica de una manera similar a un ajuste gamma para una respuesta de luminosidad de percepción no lineal de los sistemas de visualización, pero no indica una corrección total para esto.<br />
<br />
Y como siempre os dejo algunos ejemplos simples de la aplicación de estos indicadores.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH_wcxURWT5pmiqRhWnyF0F0a2Z0ufJFM2DXj1gZElITyhTvtYgsEm6ZbWYRIRg2tlSU4F82O6InZhEl8f743Tdzo9BrZDIiYEg8S9yRYE8kFzgBH5CDDqA_rM92rflCMsIsWiQciezTOO/s1600/rendering_hints.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH_wcxURWT5pmiqRhWnyF0F0a2Z0ufJFM2DXj1gZElITyhTvtYgsEm6ZbWYRIRg2tlSU4F82O6InZhEl8f743Tdzo9BrZDIiYEg8S9yRYE8kFzgBH5CDDqA_rM92rflCMsIsWiQciezTOO/s400/rendering_hints.png" width="400" /></a></div><br />
Y por aquí el código del ejemplo:<br />
<br />
<pre class="brush: js">package RenderingHintsSamples;
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class RenderingHintsSamples extends JPanel {
public RenderingHintsSamples() {
this.setLayout(new GridLayout(4, 2));
this.add(new JLabel("KEY_ANTIALIASING --> OFF"));
this.add(new AntialiasingPanel(false));
this.add(new JLabel("KEY_ANTIALIASING --> ON"));
this.add(new AntialiasingPanel(true));
this.add(new JLabel("KEY_TEXT_ANTIALIASING --> OFF"));
this.add(new TextAntialiasingPanel(false));
this.add(new JLabel("KEY_TEXT_ANTIALIASING --> ON"));
this.add(new TextAntialiasingPanel(true));
}
private class AntialiasingPanel extends JPanel {
boolean claveActiva = false;
public AntialiasingPanel(boolean claveActiva) {
this.claveActiva = claveActiva;
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
if (claveActiva) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
}
g2d.setStroke(new BasicStroke(5f));
g2d.drawOval(20, 20, 60, 60);
g2d.drawLine(80, 20, 150, 75);
}
}
private class TextAntialiasingPanel extends JPanel {
boolean claveActiva = false;
public TextAntialiasingPanel(boolean claveActiva) {
this.claveActiva = claveActiva;
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
if (claveActiva) {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
g2d.setFont(new Font("Serif", Font.ITALIC, 30));
g2d.drawString("TEXT_ANTIALIASING", 0, 40);
}
}
}
</pre><pre class="brush: js">package RenderingHintsSamples;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("RenderingHints: ejemplos");
RenderingHintsSamples ejemplos = new RenderingHintsSamples();
frame.getContentPane().add(ejemplos);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(565, 370);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Un saludo y hasta la próxima entrada.<br />Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com0tag:blogger.com,1999:blog-6677093975106556207.post-90488126335961168032011-11-22T17:34:00.001+01:002011-11-22T18:05:37.807+01:00Diálogos personalizados, bordes redondeados, quitar botones de los diálogos.Hola a todos.<br />
<br />
Hace un tiempo tuve que pelearme mucho para encontrar la solución a 2 problemas bastante comunes. Los diseñadores que se encargan de la interfaz gráfica de la aplicación que estábamos desarrollando insistían en eliminar los botones clásicos que aparecen en el marco de los diálogos, si, si, los de minimizar, maximizar y cerrar, y querían utilizar unos personalizados.<br />
Por si esto fuera poco, además pedían que los diálogos no tuviesen la forma cuadrada normal, si no que tuviesen bordes redondeados o formas específicas.<br />
<br />
Pues bien, después de mucho indagar dí con la solución a ambos problemas de un plumazo. Paso a detallaros como hacerlo.<br />
<br />
Un <i>JDialog</i> no es más que un <i>Frame</i> más de nuestra aplicación, como tal tiene los botones mencionados anteriormente, se le puede añadir un <i>JMenu</i> y demás parafernalia que muchas veces nos sobra en nuestros diseños.<br />
Para conseguir quitar el marco exterior de los diálogos y mostrar solo el contenido, es decir, quitarle la decoración, la única manera de conseguirlo es llamar al método <b>setUndecorated(true)</b>. Esto elimina estos botones y nos deja solo el contenido a la vista.<br />
<br />
Esta condición anterior es necesaria para conseguir nuestro segundo objetivo, darles una forma personalizada a nuestras ventanas. Para ello nos valdremos de la clase de utilidades <i>AWTUtilities</i>, esta clase además de permitir cambiar la forma de las ventanas permite aplicar ciertas clases de transparencia a las mismas aunque los resultados no son siempre los esperados dependiendo de la plataforma de desarrollo (aunque esto es un tema que no vamos a tratar de momento). Esta clase se distribuye a partir de la JRE|JDK 6u10, por lo que los usuarios de versiones anteriores no podréis hacer uso de ella :(<br />
<br />
Este sería el resultado que podríamos obtener haciendo uso de lo que os he comentado:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSQkYsSaH_uAr9k1Owx4N5ywEAzcmQaSGlCrV68D_6o3wj-pr3qoiOSBJixda1YFuWLC57OJTYBXuJNhpr_AlNPZhdiPxKZngs5cnBu5LIIcFToWPMj-xCW4EOfkS8CiKhLS0j0iTsAAb9/s1600/dialogoRedondeado.JPG" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="206" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSQkYsSaH_uAr9k1Owx4N5ywEAzcmQaSGlCrV68D_6o3wj-pr3qoiOSBJixda1YFuWLC57OJTYBXuJNhpr_AlNPZhdiPxKZngs5cnBu5LIIcFToWPMj-xCW4EOfkS8CiKhLS0j0iTsAAb9/s400/dialogoRedondeado.JPG" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ivARKFMDNJxq3quADn7obKSv7fHacnzmaT7edX90p_zGpruCdv2YFl_gIZY4MflGSnsmKiKNe7TSV_dO_5cw_MRp1ZNJMmr0s9bNvb-UQgBVM2TViy-p9u3gUr6c26LgZs1gHtbDH_yh/s1600/dialogoOvalado.JPG" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="215" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1ivARKFMDNJxq3quADn7obKSv7fHacnzmaT7edX90p_zGpruCdv2YFl_gIZY4MflGSnsmKiKNe7TSV_dO_5cw_MRp1ZNJMmr0s9bNvb-UQgBVM2TViy-p9u3gUr6c26LgZs1gHtbDH_yh/s400/dialogoOvalado.JPG" /></a></div><br />
Bien, así pues aquí os dejo el código para conseguir estos resultados.<br />
<br />
Primero la clase de nuestro diálogo personalizado, aquí simplemente heredamos de un <i>JDialog</i>, le quitaremos el marco y la botonera y en su método <i>paint(Graphics g)</i> haremos que se dibuje con la forma deseada.<br />
<pre class="brush: js">package dialogos;
import java.awt.Graphics;
import java.awt.Shape;
import javax.swing.JDialog;
import com.sun.awt.AWTUtilities;
public class ShapedDialog extends JDialog {
// La forma de nuestro dialogo
Shape dialogShape;
public ShapedDialog() {
super();
/* Con esta instruccion eliminamos la barra superior y los botones de
* minimizar, maximizar y cerrar.
*/
this.setUndecorated(true);
// Esta orden centra el dialogo en la pantalla
this.setLocationRelativeTo(null);
}
/**
* Establece la forma de la ventana.
* @param shape
*/
public void setShape(Shape shape) {
this.dialogShape = shape;
/* Imprescindible para mostrar el diálogo, hasta que no hagamos esto,
* la ventana permanece invisible
*/
this.setVisible(true);
}
@Override
public void paint(Graphics g) {
// Pintamos todo el contenido
super.paint(g);
// Establecemos la forma de la ventana
AWTUtilities.setWindowShape(this, dialogShape);
}
}
</pre><br />
Como veis ha sido bastante simple, a pesar de ello, a más de uno os habrá dolido la cabeza antes de llegar a este post, jeje.<br />
<br />
Y ahora la clase desde donde lanzaremos nuestra aplicación y crearemos los diálogos.<br />
<br />
<pre class="brush: js">package dialogos;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Ejemplos de dialogos");
final ShapedDialog dialog = new ShapedDialog();
// Este sera el contenido de nuestro dialogo
JPanel dialogContent = new JPanel(new BorderLayout());
dialogContent.add(new JLabel("Interior del dialogo", JLabel.CENTER), BorderLayout.CENTER);
// Dado que eliminamos el boton de cerrar el dialogo, tendremos que añadirle un boton para ello
JButton close = new JButton(new AbstractAction("Cerrar") {
@Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
dialogContent.add(close, BorderLayout.SOUTH);
dialog.setContentPane(dialogContent);
dialog.setSize(400, 200);
JButton openDialog = new JButton();
openDialog.setAction(new AbstractAction("Dialogo redondo") {
@Override
public void actionPerformed(ActionEvent e) {
Shape oval = new Ellipse2D.Float(0, 0, 400, 200);
dialog.setShape(oval);
}
});
JButton openDialog2 = new JButton();
openDialog2.setAction(new AbstractAction("Dialogo bordes redondeado") {
@Override
public void actionPerformed(ActionEvent e) {
Shape roundRectangle = new RoundRectangle2D.Float(0, 0, 400, 200, 20, 20);
dialog.setShape(roundRectangle);
}
});
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(openDialog);
frame.getContentPane().add(openDialog2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Bien, pues esto es todo por hoy, espero que os estén siendo de ayuda estos mini-tutoriales.<br />
<br />
Un saludo.<br />
<br />
PD: ahora también podéis seguirme en <a href="http://www.facebook.com/pages/Swing-Facil-en-espa%C3%B1ol/277416935626207">Facebook</a> y hacerme saber si os gusta lo que hago.Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com2tag:blogger.com,1999:blog-6677093975106556207.post-77647825889357125092011-11-14T10:13:00.001+01:002011-12-19T17:24:59.000+01:00Interfaz Stroke y lápices personalizadosHola de nuevo amigos desarrolladores, hoy os traigo cosas muy interesantes rescatadas de mi baúl de los recuerdos.<br />
Seguramente muchos os encontréis ante la necesidad de pintar texto siguiendo un trazado, queriendo pintar letras con un contorno hecho con figuras de formas o simplemente queriendo dibujar usando un trazo personalizado.<br />
<br />
Pues bien todo esto está permitido en Java gracias al uso de la interfaz <i>Stroke</i> y algunos truquillos que os paso a detallar.<br />
<br />
La interfaz <i>Stroke</i> permite que un objeto <i>Graphic2D</i> obtenga una forma que es el contorno, o representación estética del contorno, de una <i>Shape </i>(Forma) especificada.<br />
Dibujar una <i>Shape</i> es como trazar su contorno con un lápiz con la forma y tamaño apropiado.<br />
Así pues todo nuestro trabajo consistirá en decirle a la interfaz <i>Stroke</i> que <i>Shape</i> tiene que devolvernos para dibujar cualquier objeto gráfico con <i>Graphic2D</i>. Esto se consigue al sobreescribir el método <br />
<b>public Shape createStrokedShape(Shape shape)</b> para hacer que nos devuelva la forma que deseamos utilizar como lápiz.<br />
<br />
Las posibilidades que ofrece esta interfaz son muchas, este sería el resultado de aplicar algunos de estos lápices personalizados a la hora de dibujar una línea, un círculo y los caracteres "A B C". <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2QX4xMj-quvKRbMS4dnYeSedWKNoq77ZGC0bR6VLTT4DnQQZuMrcF0_8aG1arsoYg_5y1NeF7aI3tx2usd4fvv6Cc6eGPyhlItcc3luyoQYvu8exvK3HFPR4oo2nHAJVOMGMh7802tsm4/s1600/strokes.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2QX4xMj-quvKRbMS4dnYeSedWKNoq77ZGC0bR6VLTT4DnQQZuMrcF0_8aG1arsoYg_5y1NeF7aI3tx2usd4fvv6Cc6eGPyhlItcc3luyoQYvu8exvK3HFPR4oo2nHAJVOMGMh7802tsm4/s400/strokes.JPG" width="350" /></a></div>
<br />
Por ejemplo, vamos a crear un contorno formado por figuras geométricas, en nuestro ejemplo serán círculos y cuadrados que se repetirán a lo largo del trazado. En los comentarios del código intento explicar el funcionamiento del mismo.<br />
<br />
<pre class="brush: js">package strokes.samples;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
public class StrokeGeometrico implements Stroke {
// Formas a incluir en el stroke
private Shape shapes[];
private float advance;
// Valores necesarios para dibujar el Path (trazado)
private AffineTransform t = new AffineTransform();
/**
* Crea un trazo a partir de un array de formas.
* @param shapes Formas a dibujar
* @param advance separación entre las formas
*/
public StrokeGeometrico(Shape shapes[], float advance) {
this.advance = advance;
this.shapes = new Shape[shapes.length];
for ( int i = 0; i < this.shapes.length; i++ ) {
Rectangle2D bounds = shapes[i].getBounds2D();
t.setToTranslation(-bounds.getCenterX(), -bounds.getCenterY());
this.shapes[i] = t.createTransformedShape(shapes[i]);
}
}
@Override
public Shape createStrokedShape( Shape shape ) {
/* Proporciona implementaciones del trazado geométrico en general que soporta
* la funcionalidad de las clases Shape y PathIterator
*/
GeneralPath result = new GeneralPath();
// Usaremos este iterator para 'aplanar' el trazado
PathIterator it = new FlatteningPathIterator(shape.getPathIterator( null ), 1);
float points[] = new float[6];
float moveX = 0, moveY = 0;
float lastX = 0, lastY = 0;
float thisX = 0, thisY = 0;
int type = 0;
float next = 0;
int currentShape = 0;
int length = shapes.length;
/* Todas estas operaciones son necesarias para renderizar la forma del trazado.
* La interfaz PathIterator proporciona el mecanismo para que objetos que implementan
* la interfaz Shape devuelvan la geometria de sus formas, permitiendo que quien los llama
* recupere el trazado de esa forma segmento por segmeto.
*/
while (currentShape < length && !it.isDone()) {
type = it.currentSegment(points);
switch(type){
/* Una constante que indica que en un segmento indica que un
* punto debe comenzar un nuevo trazado.
*/
case PathIterator.SEG_MOVETO:
moveX = lastX = points[0];
moveY = lastY = points[1];
result.moveTo( moveX, moveY );
next = 0;
break;
/* Una constante que indica que el anterior trazado debe ser cerrado
* añadiendo una linea al segmento uniendo el punto correspondiente
* al anterior SEG_MOVETO.
*/
case PathIterator.SEG_CLOSE:
points[0] = moveX;
points[1] = moveY;
// Fall into....
/* La constante para un punto que indica el punto final de una linea que
* se dibuja desde el punto especificado con anterioridad.
*/
case PathIterator.SEG_LINETO:
thisX = points[0];
thisY = points[1];
float dx = thisX-lastX;
float dy = thisY-lastY;
float distance = (float) Math.sqrt(dx*dx + dy*dy);
if (distance >= next) {
float r = 1.0f / distance;
float angle = (float) Math.atan2(dy, dx);
while (currentShape < length && distance >= next) {
float x = lastX + next * dx * r;
float y = lastY + next * dy * r;
t.setToTranslation( x, y );
t.rotate(angle);
result.append(t.createTransformedShape(shapes[currentShape]), false);
next += advance;
currentShape++;
currentShape %= length;
}
}
next -= distance;
lastX = thisX;
lastY = thisY;
break;
}
it.next();
}
return result;
}
}
</pre>
<br />
Además podemos, por ejemplo, combinar varios <i>Strokes</i>. A continuación os muestro como crear un lápiz compuesto por otros 2 creados previamente. Basta con hacer que el nuevo <i>Stroke</i> devuelva una forma creada a partir de los trazados de los 2 previamente creados. Así pues, podemos crear un trazado compuesto por un trazado simple de 10px de grosor y otro de 0.5px de la siguiente manera.<br />
<br />
<br />
<pre class="brush: js">package strokes.samples;
import java.awt.Shape;
import java.awt.Stroke;
public class StrokeCompuesto implements Stroke {
// Trazos básicos
private Stroke stroke1;
private Stroke stroke2;
/**
* Crea un trazo compuesto por 2 trazos.
*/
public StrokeCompuesto(Stroke stroke1, Stroke stroke2) {
this.stroke1 = stroke1;
this.stroke2 = stroke2;
}
@Override
public Shape createStrokedShape(Shape shape) {
// Simplemente creamos el contorno del trazado usando otro trazado dado.
return stroke2.createStrokedShape(stroke1.createStrokedShape(shape));
}
}
</pre>
<br />
Otra cosa que me parece muy interesante y que a muchos os habrá dado quebraderos de cabeza es lo que indica el título de la entrada, dibujar texto siguiendo un camino. Los caracteres al fin y al cabo son formas también, por lo que podemos decirle a nuestra interfaz <i>Stroke</i> que nos devuelva un lápiz que pinte nuestra cadena de texto de una manera similar a como hicimos con las formas geométricas.<br />
<br />
<pre class="brush: js">package strokes.samples;
import java.awt.Font;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
public class StrokeTexto implements Stroke {
// Texto y fuente a utilizar
private String text;
private Font font;
// Valores necesarios para dibujar el Path (trazado)
private boolean stretchToFit = false;
private AffineTransform t = new AffineTransform();
/**
* Crearemos un trazado a partir de una cadena de texto.
* @param text
* @param font
* @param stretchToFit Indica si queremos que el texto ocupe todo el trazado
* @param repeat Indica si queremos que la cadena se repita
*/
public StrokeTexto( String text, Font font, boolean stretchToFit) {
this.text = text;
this.font = font;
this.stretchToFit = stretchToFit;
}
@Override
public Shape createStrokedShape(Shape shape) {
// Crearemos un vector con los caracteres dados, recordemos que cada uno de los caracteres (o glifos) son simples formas
FontRenderContext frc = new FontRenderContext(null, true, true);
GlyphVector glyphVector = font.createGlyphVector(frc, text);
GeneralPath result = new GeneralPath();
PathIterator it = new FlatteningPathIterator( shape.getPathIterator( null ), 1 );
float points[] = new float[6];
float moveX = 0, moveY = 0;
float lastX = 0, lastY = 0;
float thisX = 0, thisY = 0;
int type = 0;
float next = 0;
int currentChar = 0;
int length = glyphVector.getNumGlyphs();
if ( length == 0 )
return result;
// Si queremos que el texto se adapte al trazado que vamos a realizar, necesitaremos un factor que adapte las longitudes
float factor = stretchToFit ? measurePathLength(shape) / (float)glyphVector.getLogicalBounds().getWidth() : 1.0f;
float nextAdvance = 0;
/* Todas estas operaciones son necesarias para renderizar la forma del trazado.
* La interfaz PathIterator proporciona el mecanismo para que objetos que implementan
* la interfaz Shape devuelvan la geometria de sus formas, permitiendo que quien los llama
* recupere el trazado de esa forma segmento por segmeto.
*/
while (currentChar < length && !it.isDone()) {
type = it.currentSegment(points);
switch(type){
/* Una constante que indica que en un segmento indica que un
* punto debe comenzar un nuevo trazado.
*/
case PathIterator.SEG_MOVETO:
moveX = lastX = points[0];
moveY = lastY = points[1];
result.moveTo(moveX, moveY);
nextAdvance = glyphVector.getGlyphMetrics(currentChar).getAdvance() * 0.5f;
next = nextAdvance;
break;
/* Una constante que indica que el anterior trazado debe ser cerrado
* añadiendo una linea al segmento uniendo el punto correspondiente
* al anterior SEG_MOVETO.
*/
case PathIterator.SEG_CLOSE:
points[0] = moveX;
points[1] = moveY;
// Fall into....
/* La constante para un punto que indica el punto final de una linea que
* se dibuja desde el punto especificado con anterioridad.
*/
case PathIterator.SEG_LINETO:
thisX = points[0];
thisY = points[1];
float dx = thisX-lastX;
float dy = thisY-lastY;
float distance = (float)Math.sqrt( dx*dx + dy*dy );
if (distance >= next) {
float r = 1.0f/distance;
float angle = (float)Math.atan2( dy, dx );
while (currentChar < length && distance >= next) {
Shape glyph = glyphVector.getGlyphOutline( currentChar );
Point2D p = glyphVector.getGlyphPosition(currentChar);
float px = (float)p.getX();
float py = (float)p.getY();
float x = lastX + next*dx*r;
float y = lastY + next*dy*r;
float advance = nextAdvance;
nextAdvance = currentChar < length-1 ? glyphVector.getGlyphMetrics(currentChar+1).getAdvance() * 0.5f : 0;
t.setToTranslation( x, y );
t.rotate( angle );
t.translate( -px-advance, -py );
result.append( t.createTransformedShape(glyph), false );
next += (advance+nextAdvance) * factor;
currentChar++;
currentChar %= length;
}
}
next -= distance;
lastX = thisX;
lastY = thisY;
break;
}
it.next();
}
return result;
}
/**
* Mide la longitud del trazado.
* @param shape
* @return la longitud
*/
public float measurePathLength(Shape shape) {
PathIterator it = new FlatteningPathIterator(shape.getPathIterator( null ), 1);
float points[] = new float[6];
float moveX = 0, moveY = 0;
float lastX = 0, lastY = 0;
float thisX = 0, thisY = 0;
int type = 0;
float total = 0;
while (!it.isDone()) {
type = it.currentSegment( points );
switch(type){
case PathIterator.SEG_MOVETO:
moveX = lastX = points[0];
moveY = lastY = points[1];
break;
case PathIterator.SEG_CLOSE:
points[0] = moveX;
points[1] = moveY;
// Fall into....
case PathIterator.SEG_LINETO:
thisX = points[0];
thisY = points[1];
float dx = thisX-lastX;
float dy = thisY-lastY;
total += (float)Math.sqrt(dx * dx + dy * dy);
lastX = thisX;
lastY = thisY;
break;
}
it.next();
}
return total;
}
}
</pre>
<br />
<pre class="brush: js">package strokes;
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
import strokes.samples.StrokeCompuesto;
import strokes.samples.StrokeGeometrico;
import strokes.samples.StrokeTexto;
public class StrokesSamples extends JPanel {
private StrokeCompuesto compStroke;
private StrokeGeometrico geomStroke;
private StrokeTexto textStroke;
private Font font;
/**
* Constructor.
*/
public StrokesSamples() {
// Un trazo hecho compuesto por cuadrados y circulos
geomStroke = new StrokeGeometrico(
new Shape[] {
new Rectangle(5, 5),
new Ellipse2D.Float(0, 0, 4, 4)
}, 10.0f);
// Un trazo compuesto por 2 trazos.
compStroke = new StrokeCompuesto(new BasicStroke(10f), new BasicStroke(0.5f));
// Un trazo compuesto por una cadena de caracteres
font = new Font("Arial", Font.PLAIN, 12);
textStroke = new StrokeTexto("Esto es una cadena", font, false);
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
// Activamos el anti aliasing para que nuestros trazados se rendericen en condiciones optimas
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Esto lo hacemos para obtener el contorno de la cadena "A B C"
Font font = new Font("Arial", Font.PLAIN, 100);
g2d.setFont(font);
GlyphVector gv = font.createGlyphVector(g2d.getFontRenderContext(), "A B C");
// Así podremos dibujar esta forma con nuestros lápices
Shape shape = gv.getOutline();
// Dibujamos usando nuestro trazo con formas
g2d.setStroke(geomStroke);
g2d.drawLine(5, 10, 105, 25);
g2d.drawOval(5, 30, 75, 75);
// el método translate desplaza el origen de coordenadas al punto específicado
g2d.translate(105, 75);
g2d.draw(shape);
g2d.translate(-105, -75);
// Dibujamos usando el trazado compuesto
g2d.setStroke(compStroke);
g2d.drawLine(5, 120, 105, 135);
g2d.drawOval(5, 140, 75, 75);
g2d.translate(105, 185);
g2d.draw(shape);
g2d.translate(-105, -185);
// Dibujamos usando el trazo de cadenas de texto
g2d.setStroke(textStroke);
g2d.drawLine(5, 230, 105, 245);
g2d.drawOval(5, 250, 75, 75);
g2d.translate(105, 295);
g2d.draw(shape);
g2d.translate(-105, -295);
};
}
</pre>
<br />
Bien, solo queda dejaros el método Main que lanza nuestra aplicación de ejemplo. Un saludo y gracias a todos por leerme.<br />
<br />
<pre class="brush: js">package strokes;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Ejemplos de uso de strokes");
StrokesSamples ejemplos = new StrokesSamples();
frame.getContentPane().add(ejemplos);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre>
<br />Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com0tag:blogger.com,1999:blog-6677093975106556207.post-26919552357023455652011-10-19T11:29:00.000+02:002011-10-19T11:29:17.704+02:00Manipulacion y tratamiento de imagenes con Swing. Escala de grises, imagen espejo, imagen translucidaHola de nuevo amigos, hoy vamos a deleitarnos con algunas de las herramientas que nos ofrece Java2D para el tratamiento de imágenes.<br />
<br />
En primer lugar os presentaré una imagen original y sobre esta iremos aplicando diversas transformaciones para hacer que parezca una imagen totalmente distinta.<br />
<br />
En primer lugar os dejo el código para lanzar nuestra aplicación y a medida que vayamos avanzando, iremos explicando cada una de las transformaciones que hemos aplicado a nuestra imagen original.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitXAmzcTygN8OkRg4QThQwkhsOK_-PPBJh101EjN3IbwTck5ApvXGb7bgYLnaVxhmuZZ9E7v-WgeB41jRKOOdOxYj-Rby1TJ01lKgNII6IhaMenk-JZkn4zo1cQXbOofz_zOvp_xsrgNhq/s1600/imageTransform.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitXAmzcTygN8OkRg4QThQwkhsOK_-PPBJh101EjN3IbwTck5ApvXGb7bgYLnaVxhmuZZ9E7v-WgeB41jRKOOdOxYj-Rby1TJ01lKgNII6IhaMenk-JZkn4zo1cQXbOofz_zOvp_xsrgNhq/s1600/imageTransform.JPG" /></a></div><br />
<br />
<pre class="brush: js">package tratamientoImagenes;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Tratamiento de imágenes con Swing");
Expositor panel = new Expositor();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 534);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Este es nuestro panel expositor, mediante un GridLayout añadiremos 4 paneles, cada uno de ellos con una imagen de fondo y un aspecto distinto a pesar de ser la misma imagen de base.<br />
<br />
<pre class="brush: js">package tratamientoImagenes;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Expositor extends JPanel {
/**
* Constructor.
*/
public Expositor() {
/*
* Creamos un layout de 4 paneles, en cada uno mostraremos una imagen
* "aparentemente" distinta
*/
super(new GridLayout(2, 2));
setPreferredSize(new Dimension(800, 534));
// Los paneles con las imagenes
Original original = new Original();
EscalaDeGrises escalaDeGrises = new EscalaDeGrises();
Espejo espejo = new Espejo();
Translucida translucida = new Translucida();
Dimension photoDimension = new Dimension(400, 267);
original.setPreferredSize(photoDimension);
escalaDeGrises.setPreferredSize(photoDimension);
espejo.setPreferredSize(photoDimension);
translucida.setPreferredSize(photoDimension);
original.setOpaque(false);
escalaDeGrises.setOpaque(false);
espejo.setOpaque(false);
translucida.setOpaque(false);
// Etiquetas
JLabel originalLabel = new JLabel("ORIGINAL");
JLabel escalaDeGrisesLabel = new JLabel("ESCALA DE GRISES");
JLabel espejoLabel = new JLabel("ESPEJO");
JLabel translucidaLabel = new JLabel("TRANSLUCIDA");
originalLabel.setForeground(Color.WHITE);
escalaDeGrisesLabel.setForeground(Color.WHITE);
espejoLabel.setForeground(Color.WHITE);
translucidaLabel.setForeground(Color.WHITE);
original.add(originalLabel);
escalaDeGrises.add(escalaDeGrisesLabel);
espejo.add(espejoLabel);
translucida.add(translucidaLabel);
this.add(original);
this.add(escalaDeGrises);
this.add(espejo);
this.add(translucida);
}
/**
* Para recuperar una imagen de un archivo...
*
* @param path Ruta de la imagen relativa al proyecto
* @return una imagen
*/
public static ImageIcon createImage(String path) {
URL imgURL = Expositor.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
</pre><br />
Y ahora empezamos con los paneles, primero presentamos la imagen original para que podáis apreciar los cambios que iremos realizando, el como pintar un panel transparente con una imagen de fondo ya lo tratamos en una entrada anterior <a href="http://swing-facil.blogspot.com/2011/06/jpanel-transparente-jpanel-con-imagen.html">JPanel con imagen de fondo</a>.<br />
<br />
<pre class="brush: js">package tratamientoImagenes;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Original extends JPanel {
// Cargamos la imagen original
private ImageIcon photo = Expositor.createImage("imagenes/ER.jpg");
@Override
public void paint(Graphics g) {
g.drawImage(photo.getImage(), 0, 0, null);
// Pintamos el resto de componentes
super.paint(g);
}
}
</pre><br />
Una transformación que personalmente me gusta bastante, pasaremos la imagen original por uno de los filtros de RGBImageFilter, en este caso el filtro de escala de grises. Este tipo de filtro hará que los pixeles se vean mas claros para posteriormente aplicarle tonos grises a la imagen. Así es como lo hemos usado:<br />
<br />
<pre class="brush: js">package tratamientoImagenes;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import javax.swing.GrayFilter;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class EscalaDeGrises extends JPanel {
// Cargamos la imagen original
private ImageIcon photo = Expositor.createImage("imagenes/ER.jpg");
@Override
public void paint(Graphics g) {
// Imagen
Image img = photo.getImage();
// Filtro de escala de grises
ImageFilter filter = new GrayFilter(true, 50);
ImageProducer producer = new FilteredImageSource(img.getSource(), filter);
ImageIcon newIcon = new ImageIcon(this.createImage(producer));
newIcon.paintIcon(this, g, 0, 0);
// Pintamos el resto de componentes
super.paint(g);
}
}
</pre><br />
Cuando dibujamos una imagen, podemos aplicarle una transformada para girarla como nos apetezca, usamos para ello el método drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer); del objeto Graphics2D. Este método nos permite cosas como dibujar parte de una imagen en otra imagen, escalar una imagen y otras tantas. Tomamos la imagen y una serie de coordenadas del rectángulo destino (dx, dy) así como del rectángulo origen (sx, sy). Manipulando estas coordenadas podemos hacer que la imagen se voltee como queramos.<br />
<br />
En Java las coordenadas empiezan en la esquina superior izquierda y terminan en la inferior derecha, así pues para girar una imagen como si estuviésemos frente a un espejo modificamos las coordenadas del rectángulo origen para que empiecen en el borde superior derecho y terminen en el inferior izquierdo. <br />
<br />
En el ejemplo las modificamos para voltear la imagen 180 grados, es decir, como si viésemos un reflejo en un lago. Tomaremos entonces como origen la esquina inferior izquierda y terminamos en la superior derecha.<br />
<br />
<pre class="brush: js">package tratamientoImagenes;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Espejo extends JPanel {
// Cargamos la imagen original
private ImageIcon photo = Expositor.createImage("imagenes/ER.jpg");
@Override
public void paint(Graphics g) {
// Imagen
Image img = photo.getImage();
int width = photo.getIconWidth();
int height = photo.getIconHeight();
// Rotamos la imagen
g.drawImage(img, 0, 0, width, height, 0, height, width, 0, null);
// Pintamos el resto de componentes
super.paint(g);
}
</pre><br />
Y por último haremos translucida la imagen original, para ello deberemos cargar todos los pixeles de la imagen en una BufferedImage, y sobre esta aplicar un filtro modificando el componente alpha de cada pixel.<br />
<br />
<pre class="brush: js">package tratamientoImagenes;
import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class Translucida extends JPanel {
@Override
public void paint(Graphics g) {
// En este caso tendremos que trabajar con una BufferedImage
URL imgURL = Expositor.class.getResource("imagenes/ER.jpg");
BufferedImage img = null;
try {
img = ImageIO.read(imgURL);
} catch (IOException e) {
e.printStackTrace();
}
int w = img.getWidth(null);
int h = img.getHeight(null);
// Necesitaremos una imagen auxiliar a la que aplicar un filtro
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics gI = bi.getGraphics();
// Sobre esta imagen dibujaremos la imagen original
gI.drawImage(img, 0, 0, null);
Graphics2D g2d = (Graphics2D) g;
// Establecemos la componente alpha de nuestros graficos 50%
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
/* Draw the image, applying the filter */
g2d.drawImage(bi, null, 0, 0);
// Pintamos el resto de componentes
super.paint(g);
}
}
</pre><br />
Y así termina todo, espero que os haya resultado útil este mini-tutorial sobre tratamiento de imágenes.<br />
<br />
Un saludo y hasta pronto.<br />Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com5tag:blogger.com,1999:blog-6677093975106556207.post-23663155526733460752011-09-27T10:46:00.000+02:002011-09-27T10:46:47.748+02:00Reloj análogico con Swing, ejemplo Swing TimerHoy profundizaremos un poco en el Swing Timer, una instancia de Timer dispara una o varias acciones después de un retardo especificado.<br /><br />
<br /><br />
Se recomienda el uso de Swing timers para la realización de tareas relacionadas con la interfaz de usuario (GUI-task) ya que todos los timers comparten un mismo hilo y todas las tareas se ejecutan automáticamente en el hilo de despacho de eventos (event-dispatch thread).<br /><br />
<br /><br />
Su uso es muy fácil, cuando creamos el timer, especificamos un action listener que se notificará cuando el temporizador acaba. Es válido tanto para tareas repetitivas como para realizar una sola tarea transcurrido un cierto retraso, para este último fin podremos invocar setRepeats(false) en el timer.<br /><br />
Para inciarlo se llama a su método start(), para suspenderlo llamamos a stop().<br />
<br />
<br /><br />
<pre class="brush: js">//Timer
Timer timer = new Timer(TIMER_UPDATE, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Tareas repetitivas...
}
});
timer.start();
</pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWK-Cm0USXefhyWeC3PxEMTGjHHCUZzK4-_2lEZ8__UjxocZY9-LkwQvOiBccE8KhWN08Lj1elwTrLtxmYivEvQHcJERUdEDgaOZnyRWAqpmST5sOADmHOsBOSIt3q2sxQIMJU5ntxoY5p/s1600/reloj.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWK-Cm0USXefhyWeC3PxEMTGjHHCUZzK4-_2lEZ8__UjxocZY9-LkwQvOiBccE8KhWN08Lj1elwTrLtxmYivEvQHcJERUdEDgaOZnyRWAqpmST5sOADmHOsBOSIt3q2sxQIMJU5ntxoY5p/s320/reloj.JPG" width="304" /></a></div><br />
Como ejemplo de uso de un Swing timer, les presento la implementación de un reloj analógico hecho con Swing.<br />
<br />
<br /><br />
Este sería el resultado y aquí a continuación os dejo el código.<br />
<br />
<br /><br />
<br />
En primer lugar nuestra clase reloj que definirá y arrancará el Timer.<br />
<br />
<pre class="brush: js">package reloj;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Reloj extends JPanel {
/** Tiempo de actualizacion. */
private static final int TIMER_UPDATE = 1000;
/** Calendar. */
private Calendar calendar = null;
/**
* Constructor.
*/
public Reloj() {
setUI(new RelojUI());
//Inicializamos el calendario
calendar = Calendar.getInstance();
//Establecemos el tamaño a nuestro panel
setPreferredSize(new Dimension(295, 270));
//Timer para actualizar el calendario
Timer timer = new Timer(TIMER_UPDATE, new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Añadimos 1 segundo al calendario
calendar.add(Calendar.SECOND, 1);
// repintamos
repaint();
}
});
timer.start();
}
/**
* Recupera la instancia de Calendar
* @return calendar
*/
public Calendar getCalendar() {
return this.calendar;
}
}
</pre>Con cada iteración del Timer llamamos al método repaint() de nuestro reloj, repintando así las manecillas de acuerdo a la hora actual que nos devolvera la instancia de Calendar que hemos definido y actualizaremos también con cada iteración.<br />
<br />
A continuación el UI del reloj, que se encargará de redibujarlo cada segundo según establecimos en el retardo del Timer.<br />
<br />
<br /><br />
<pre class="brush: js">package reloj;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.net.URL;
import java.util.Calendar;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
public class RelojUI extends PanelUI {
private ImageIcon backgroundImage = null;
private BasicStroke handsStroke;
public static ComponentUI createUI(JComponent c) {
return new RelojUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
//Hacemos el panel transparente
c.setOpaque(false);
backgroundImage = createImage("imagenes/reloj.jpg");
// pincel que utilizaremos para las manecillas de los minutos y horas
handsStroke = new BasicStroke(2f);
}
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g;
// imagen de fondo
if (backgroundImage != null) {
g2d.drawImage(backgroundImage.getImage(), 0, 0, null);
}
Reloj reloj = (Reloj) c;
int hour = reloj.getCalendar().get(Calendar.HOUR);
int minute = reloj.getCalendar().get(Calendar.MINUTE);
int second = reloj.getCalendar().get(Calendar.SECOND);
// acotamos la parte donde dibujaremos las manecillas del reloj
Shape oval = new Ellipse2D.Double(0, 0, 167, 164);
int centerX = (int) (oval.getBounds().getWidth() / 2);
int centerY = (int) (oval.getBounds().getHeight() / 2);
// puntos donde acaban las manecillas del reloj
int xh, yh, xm, ym, xs, ys;
// calculamos la posicion de las manecillas del reloj
xs = (int) (Math.cos(second * Math.PI / 30 - Math.PI / 2) * 75 + centerX);
ys = (int) (Math.sin(second * Math.PI / 30 - Math.PI / 2) * 75 + centerY);
xm = (int) (Math.cos(minute * Math.PI / 30 - Math.PI / 2) * 60 + centerX);
ym = (int) (Math.sin(minute * Math.PI / 30 - Math.PI / 2) * 60 + centerY);
xh = (int) (Math.cos((hour * 30 + minute / 2) * Math.PI / 180 - Math.PI / 2) * 45 + centerX);
yh = (int) (Math.sin((hour * 30 + minute / 2) * Math.PI / 180 - Math.PI / 2) * 45 + centerY);
//offset, movemos el origen de las coordenadas usadas para dibujar
//al vertice superior izquierdo del rectángulo que contiene la esfera del reloj.
g.translate(48, 78);
//dibujamos los numeros y las manecillas
g.drawString("9", 10, centerY+5);
g.drawString("3", (int) (oval.getBounds().getWidth() - 10), centerY+5);
g.drawString("12", centerX-6, 20);
g.drawString("6", centerX-3, (int) (oval.getBounds().getHeight() - 10));
// segundos
g.drawLine(centerX, centerY, xs, ys);
// minutos
g2d.setStroke(handsStroke);
g.drawLine(centerX, centerY, xm, ym);
//horas
g.drawLine(centerX, centerY, xh, yh);
// - offset
g.translate(-47, -78);
}
/**
* Para recuperar una imagen de un archivo...
* @param path Ruta de la imagen relativa al proyecto
* @return una imagen
*/
public ImageIcon createImage(String path) {
URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
</pre>Y por último la clase main que lanzará la aplicación.<br />
<br />
<br /><br />
<pre class="brush: js">package reloj;
import javax.swing.JFrame;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Reloj con Swing");
Reloj reloj = new Reloj();
frame.getContentPane().add(reloj);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(302, 302);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Un saludo y hasta la próxima!Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com1tag:blogger.com,1999:blog-6677093975106556207.post-81485345550275971052011-08-11T10:11:00.001+02:002011-08-11T10:19:03.080+02:00Colspan JTable, expandir columnas en tablas de SwingHola de nuevo,<br />
<br />
Hoy vamos a intentar explicar como expandir las columnas de un JTable, esto es muy común y fácil cuando hablamos de código HTML con las propiedades colspan y rowspan de las tablas. Pero en Swing esta característica no está contemplada, por lo que tendremos que darle una vuelta a la gestión de las celdas de un JTable.<br />
<br />
En primer lugar necesitaremos un mapeo de las celdas que queremos expandir, para ello crearemos un mapa con las claves de fila y columna que indican la celda. Nos valdremos de la siguiente interfaz para gestionar nuestro mapa y la información que necesitamos.<br />
<br />
<br />
<pre class="brush: js">package colspanTable;
import java.util.HashMap;
public interface ColSpanMap {
/**
* Indica si la celda [row,column] esta expandida
* @param row celda logica de fila
* @param column celda logica de columna
* @return numero de columnas expandiodas por celda
*/
int span(int row, int column);
/**
* Devuelve el indice de las celda visibles.
* @param row celda logica de fila
* @param column celda logica de columna
* @return indice de la celda visible que cubre la celda logica
*/
int visibleCell(int row, int column);
/**
* Establece el mapeo de filas/columnas con celdas expandidas y su posicion.
* @param spanMap Mapa
*/
void setSpanMap(HashMap< Integer, Integer > spanMap);
}
</pre><br />
La implementación debería seguir un modelo similar a este que os presento a continuación.<br />
<br />
<br />
<pre class="brush: js">package colspanTable;
import java.util.HashMap;
class TableColSpanMap implements ColSpanMap {
/** Columnas a expandir por celda. */
private static final int CELLS_TO_SPAN = 5;
/** Mapeo de las celdas a expandir. */
private HashMap< Integer, Integer > spanMap;
@Override
public int span(int row, int column) {
if (spanMap != null && spanMap.containsKey(row)) {
if (spanMap.get(row) == column) {
return CELLS_TO_SPAN;
}
}
return 1;
}
@Override
public int visibleCell(int row, int column) {
if (spanMap != null && spanMap.containsKey(row)) {
if (column >= spanMap.get(row) && column < spanMap.get(row) + CELLS_TO_SPAN) {
return spanMap.get(row);
}
}
return column;
}
@Override
public void setSpanMap(HashMap< Integer, Integer > spanMap) {
this.spanMap = spanMap;
}
}
</pre><br />
Ahora en nuestra tabla, a la hora de consultar la posición, índice y anchura de las celdas de la tabla deberemos de tener en cuenta nuestro mapeo especial, para ello sobrescribimos los métodos getCellRect para el tamaño de celda y getColumnAtPoint para buscar los índices correctos a la hora de editarla, además al contruir nuestra tabla le pasaremos en el constructor el mapeo de las celdas expandidas. Los cambios los muestro a continuación:<br />
<br />
<pre class="brush: js">package colspanTable;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JTable;
import javax.swing.table.TableModel;
public class SpanTable extends JTable {
/** Map with expanded columns mapped. */
private ColSpanMap map;
/**
* Constructor.
* @param csm Mapa de celdas
* @param tbl Modelo de la tabla
*/
public SpanTable(ColSpanMap csm, TableModel tbl) {
super(tbl);
map = csm;
setUI(new ColSpanTableUI());
}
/**
* Nos devuelve el mapa de las celdas a expandir.
* @return map
*/
public ColSpanMap getSpanMap() {
return map;
}
@Override
public Rectangle getCellRect(int row, int column, boolean includeSpacing) {
// required because getCellRect is used in JTable constructor
if (map == null)
return super.getCellRect(row, column, includeSpacing);
// add widths of all spanned logical cells
int sk = map.visibleCell(row, column);
Rectangle r1 = super.getCellRect(row, sk, includeSpacing);
if (map.span(row, sk) != 1)
for (int i = 1; i < map.span(row, sk); i++) {
r1.width += getColumnModel().getColumn(sk + i).getWidth();
}
return r1;
}
@Override
public int columnAtPoint(Point p) {
int x = super.columnAtPoint(p);
// -1 is returned by columnAtPoint if the point is not in the table
if (x < 0)
return x;
int y = super.rowAtPoint(p);
return map.visibleCell(y, x);
}
}
</pre>
Por último solo nos quedaría cuidarnos de la parte gráfica, tendremos que establecerle un UI peculiar a la tabla que nos pinte la rejilla de las celdas especial que necesitamos donde tendremos en cuenta las partes visibles de cada celda.
<pre class="brush: js">package colspanTable;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.TableCellRenderer;
public class ColSpanTableUI extends BasicTableUI {
@Override
public void paint(Graphics g, JComponent c) {
Rectangle r = g.getClipBounds();
int firstRow = table.rowAtPoint(new Point(0, r.y));
int lastRow = table.rowAtPoint(new Point(0, r.y + r.height));
// -1 is a flag that the ending point is outside the table
if (lastRow < 0)
lastRow = table.getRowCount() - 1;
for (int i = firstRow; i <= lastRow; i++)
paintRow(i, g);
}
private void paintRow(int row, Graphics g) {
Rectangle r = g.getClipBounds();
for (int i = 0; i < table.getColumnCount(); i++) {
Rectangle r1 = table.getCellRect(row, i, true);
if (r1.intersects(r)) // at least a part is visible
{
int sk = ((SpanTable) table).getSpanMap().visibleCell(row, i);
paintCell(row, sk, g, r1);
// increment the column counter
i += ((SpanTable) table).getSpanMap().span(row, sk) - 1;
}
}
}
private void paintCell(int row, int column, Graphics g, Rectangle area) {
int verticalMargin = table.getRowMargin();
int horizontalMargin = table.getColumnModel().getColumnMargin();
Color c = g.getColor();
g.setColor(table.getGridColor());
g.drawRect(area.x, area.y, area.width - 1, area.height - 1);
g.setColor(c);
area.setBounds(area.x + horizontalMargin / 2, area.y + verticalMargin / 2, area.width - horizontalMargin, area.height - verticalMargin);
if (table.isEditing() && table.getEditingRow() == row && table.getEditingColumn() == column) {
Component component = table.getEditorComponent();
component.setBounds(area);
component.validate();
} else {
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component component = table.prepareRenderer(renderer, row, column);
if (component.getParent() == null)
rendererPane.add(component);
rendererPane.paintComponent(g, component, table, area.x, area.y, area.width, area.height, true);
}
}
}
</pre>
Bien, espero que todo este lo más claro posible. Como siempre os dejo un ejemplo funcionando :)
<pre class="brush: js">package colspanTable;
import java.util.HashMap;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
public class Test {
private static void createAndShowGUI() {
JFrame frame = new JFrame("Tabla con celdas expandidas");
ColSpanMap m = new TableColSpanMap();
HashMap< Integer, Integer > cellSpanMap = new HashMap<Integer, Integer>();
// Aqui los indices [fila,columna] de las celdas que queremos expandir
cellSpanMap.put(3, 3);
cellSpanMap.put(4, 7);
cellSpanMap.put(9, 5);
m.setSpanMap(cellSpanMap);
TableModel tm=new DefaultTableModel(15,20);
SpanTable table = new SpanTable(m,tm);
frame.getContentPane().add(new JScrollPane(table));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 295);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Espero que os siga siendo útil todo lo que aquí se dice, vuestros comentarios y dudas siempre son bienvenidos.<br />
<br />
Un saludo y hasta la próxima<br />
<br />
<br />
Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com8tag:blogger.com,1999:blog-6677093975106556207.post-51527672987038044552011-06-13T13:44:00.000+02:002011-06-13T13:44:56.271+02:00JPanel transparente, JPanel con imagen de fondoHola de nuevo, después de casi un mes sin Internet y sin poder pasaros contenido nuevo, volvemos con un ejemplo muy sencillo de algo que os puede resultar muy útil a muchos.<br />
<br />
Se trata de hacer que nuestro JPanel sea transparente y ponerle detrás una imagen de fondo. El resultado es muy bueno.<br />
En primer lugar haremos que nuestro panel sea transparente, esto es, básicamente haciendo que no sea opaco estableciéndole esta propiedad al crear el panel. Y en segundo lugar sobrescribiremos el método <i>paint(Graphics g)</i> de este panel para que antes de pintar todos los elementos nos dibuja la imagen de fondo que le hayamos establecido. ¿Fácil verdad?<br />
<br />
Primero el código del panel:<br />
<br />
<pre class="brush: js">package ejemplo7;
import java.awt.Graphics;
import java.awt.Image;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
/**
* TransparentPanel.
*/
public class TransparentPanel extends JPanel {
private Image bgImage;
public TransparentPanel() {
super();
// Hacemos que el panel sea transparente
this.setOpaque(false);
}
/**
* Lo utilizaremos para establecerle su imagen de fondo.
* @param bgImage La imagen en cuestion
*/
public void setBackgroundImage(Image bgImage) {
this.bgImage = bgImage;
}
/**
* Para recuperar una imagen de un archivo...
* @param path Ruta de la imagen relativa al proyecto
* @return una imagen
*/
public ImageIcon createImage(String path) {
URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
@Override
public void paint(Graphics g) {
// Pintamos la imagen de fondo...
if(bgImage != null) {
g.drawImage(bgImage, 0, 0, null);
}
// Y pintamos el resto de cosas que pueda tener el panel
super.paint(g);
}
</pre><br />
Y ahora como siempre el código de ejemplo:<br />
<br />
<pre class="brush: js">package ejemplo7;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* Ejemplo7.
*/
public class Ejemplo7 {
private static JFrame frame;
private static JPanel createExamplePanel() {
TransparentPanel panel = new TransparentPanel();
panel.setBackgroundImage(panel.createImage("images/bgImage.jpg").getImage());
JLabel label = new JLabel("Esto y todo lo que queramos se pinta encima de la imagen de fondo");
panel.add(label);
return panel;
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
frame = new JFrame("Panel with background image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Component contents = createExamplePanel();
frame.getContentPane().add(contents, BorderLayout.CENTER);
//Set window size
frame.setPreferredSize(new Dimension(700,525));
// Display the window.
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
</pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsQC1B3ZL58Ct46FzxVNF35QJaAoIo_oheiCFP1pR0O47mFw2FC9Qu86d43iYsLWeYBAS6ffTPNx1T0x0KlO8YhDELXgPC2kTxv6eAhqyw3FRb7YhdKI6O5n90NnwEhW9c7yI1aHamjy7t/s1600/ejemplo7.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsQC1B3ZL58Ct46FzxVNF35QJaAoIo_oheiCFP1pR0O47mFw2FC9Qu86d43iYsLWeYBAS6ffTPNx1T0x0KlO8YhDELXgPC2kTxv6eAhqyw3FRb7YhdKI6O5n90NnwEhW9c7yI1aHamjy7t/s320/ejemplo7.JPG" width="320" /></a></div>Así es como quedaría la cosa con la imagen que he elegido, obviamente el resultado dependerá de la imagen que carguéis vosotros.<br />
<br />
<br />
Un saludo y hasta pronto, espero :)Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com11tag:blogger.com,1999:blog-6677093975106556207.post-22330901496420772702011-05-09T11:53:00.000+02:002011-05-09T11:53:38.891+02:00Bordes redondeados, creando nuestro propio borde para los componentesHola de nuevo,<br />
<br />
Hoy vamos a profundizar un poco en el tema de los elementos <i>Border</i> de los componentes Swing.<br />
<br />
Todo componente al dibujarse lo hace en 2 partes, el contenido y su borde, así que hoy vamos a ver como personalizar un poco mas cualquiera de nuestros componentes añadiéndole un borde definido por nosotros mismos.<br />
<br />
Aquí os dejo la clase de nuestro borde, con los métodos mínimos que toda clase que herede de AbstractBorder debería implementar. Esta es la clase de la que parten todos los bordes utilizados en Swing.<br />
Ya sabéis que siempre pretendo dejaros un código auto-explicativo, pero para cualquier duda ya sabéis, dejadme un comentario y os contestaré en cuanto pueda.<br />
<br />
<pre class="brush: js">package ejemplo5;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.border.AbstractBorder;
/**
* RoundedBorder.
*/
public class RoundedBorder extends AbstractBorder {
private List<Color> colors;
private int thickness;
private int cornersArc;
private int borders;
/** Colores de los bordes. */
private List<GradientPaint> gradients;
/** Formas del bordes. */
private List<RoundRectangle2D> rectangles;
/**
* @param color
* @param thickness
* @param roundedCorners
*/
public RoundedBorder(List<Color> colors, int thickness, int cornersArc, int borders) {
this.colors = colors;
this.thickness = thickness;
this.cornersArc = cornersArc;
// Mínimo un borde
this.borders = borders > 0 ? borders : 1;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
createShapes(w, h, x, y);
createGradients(c);
Graphics2D g2d = ((Graphics2D) g);
// Set a higher-quality rendering
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
for (int i = 0; i < borders; i++) {
g2d.setPaint(gradients.get(i));
g2d.setStroke(new BasicStroke(thickness));
RoundRectangle2D auxRect = rectangles.get(i);
g2d.drawRoundRect((int) auxRect.getX(), (int) auxRect.getY(), (int) auxRect.getWidth(), (int) auxRect.getHeight(), (int) auxRect.getArcWidth(), (int) auxRect.getArcHeight());
}
}
/**
* Creamos los gradientes.
*
* @param c Component
*/
private void createGradients(Component c) {
gradients = new ArrayList<GradientPaint>();
for (int i = 0; i < borders; i++) {
Color color = colors.get(i);
GradientPaint gra = new GradientPaint(0, 0, color.darker(),
0, c.getHeight(), color.brighter(), false);
gradients.add(gra);
}
}
/**
* Creamos las formas del borde
*
* @param w ancho
* @param h alto
* @param x coordenada X
* @param y coordenada Y
*/
public void createShapes(int w, int h, int x, int y) {
rectangles = new ArrayList<RoundRectangle2D>();
int rectangleWidth = w, rectangleHeight = h;
int xCoord = x;
int yCoord = y;
for (int i = 0; i < borders; i++) {
if (i == 0) {
xCoord += thickness / 2;
yCoord += thickness / 2;
rectangleWidth -= thickness;
rectangleHeight -= thickness;
} else {
xCoord += thickness;
yCoord += thickness;
rectangleWidth -= 2 * thickness;
rectangleHeight -= 2 * thickness;
}
RoundRectangle2D rectangle = new RoundRectangle2D.Float(xCoord, yCoord,
rectangleWidth, rectangleHeight, cornersArc, cornersArc);
rectangles.add(rectangle);
}
}
/**
* Este método nos dice cuanto espacio necesita el borde para dibujarse.
*/
@Override
public Insets getBorderInsets(Component c) {
Insets insets = super.getBorderInsets(c);
insets.left = insets.top = insets.right = insets.bottom += thickness * borders;
return insets;
}
}</pre>Y aquí podéis ver un código de ejemplo que ilustrará el resultado obtenido: <br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivgYnyS2DVF62Zs4rqnifQW7VMjdBiHdfWpPcfc0Ax9ucUTefv9ebneI3aW5M4tyw6uLDZZJtCmUB2cRK3erN4_g8q1Rqn7SEo99bO2ntm4-ynQ8ItW2HCasupYak5poCQSjCTw0s9ZOz5/s1600/roundedBorder.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="127" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivgYnyS2DVF62Zs4rqnifQW7VMjdBiHdfWpPcfc0Ax9ucUTefv9ebneI3aW5M4tyw6uLDZZJtCmUB2cRK3erN4_g8q1Rqn7SEo99bO2ntm4-ynQ8ItW2HCasupYak5poCQSjCTw0s9ZOz5/s400/roundedBorder.JPG" width="400" /></a></div><br />
<br />
<pre class="brush: js">package ejemplo5;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* Ejemplo5
*/
public class Ejemplo5 {
private static JFrame frame;
private static JPanel createExamplePanel() {
JPanel panel = new JPanel();
// Componentes de prueba
JButton button = new JButton("Click");
button.setPreferredSize(new Dimension(100, 100));
button.setOpaque(false);
JTextField textField = new JTextField(25);
textField.setText("Escribe aqui...");
textField.setOpaque(false);
JTextArea textArea = new JTextArea(10, 25);
textArea.setText("Escribe aqui...");
textArea.setOpaque(false);
List<Color> colors = new ArrayList<Color>();
colors.add(Color.PINK);
colors.add(Color.RED);
button.setBorder(new RoundedBorder(colors, 5, 2, 2));
colors = new ArrayList<Color>();
colors.add(Color.PINK);
colors.add(Color.RED);
colors.add(Color.BLUE);
colors.add(Color.YELLOW);
textField.setBorder(new RoundedBorder(colors, 2, 5, 4));
colors = new ArrayList<Color>();
colors.add(Color.PINK);
colors.add(Color.RED);
colors.add(Color.BLUE);
textArea.setBorder(new RoundedBorder(colors, 4, 5, 3));
panel.add(button);
panel.add(textField);
panel.add(textArea);
return panel;
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
frame = new JFrame("RoundedBorder");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Component contents = createExamplePanel();
frame.getContentPane().add(contents, BorderLayout.CENTER);
// Display the window.
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre><br />
Un saludo y hasta pronto...Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com1tag:blogger.com,1999:blog-6677093975106556207.post-55203095835181323172011-04-25T12:16:00.000+02:002011-04-25T12:16:02.549+02:00Programa simple de dibujo con swing. Pintar en un lienzo usando MouseListener y MouseMotionListenerHola de nuevo.<br />
<br />
Hoy vamos a empezar a captar los eventos de ratón y a utilizarlos para crear un programa simple de dibujo. Básicamente añadiremos unos <i>listeners</i> a un JFrame para lograr captar los eventos de ratón y así identificar los puntos por los que desplazamos el puntero.<br />
<br />
Estos MouseAdapter y MouseMotionAdapter implementan las interfaces MouseListener y MouseMotionListener respectivamente, que se encargan de detectar eventos de ratón, como clicks, entradas y salidas del puntero en determinadas zonas, desplazamientos y arrastres de ratón. <br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNbK1l_kvXeK8k2YGOzslRlYQoRodFtyCI2KuKRCC0AsnAyTgaeobA91Pq_xBL3kFn28uIsC349tDt7nGmu4-nv4pW2q9S_mFSm_OzjtTLnhjE-nWxa-56b4NaoLxEKBUTt2zaHeEshfMM/s1600/programa_dibujo.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNbK1l_kvXeK8k2YGOzslRlYQoRodFtyCI2KuKRCC0AsnAyTgaeobA91Pq_xBL3kFn28uIsC349tDt7nGmu4-nv4pW2q9S_mFSm_OzjtTLnhjE-nWxa-56b4NaoLxEKBUTt2zaHeEshfMM/s320/programa_dibujo.JPG" width="320" /></a>En el ejemplo de hoy utilizaremos estos eventos para dibujar puntos sobre un lienzo, os dejo el código a continuación. Y ya sabéis, cualquier duda dejar un comentario y os responderé con la mayor brevedad posible.<br />
<br />
<br />
<pre class="brush: js">
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Painter extends JFrame {
private int cuentaPuntos = 0;
private JLabel j = new JLabel();
// arreglo de referencias a java.awt.Point
private int maxPoints = 1500;
private Point puntos[] = new Point[maxPoints];
// configurar GUI y registrar manejador de eventos de ratón
public Painter() {
super("Un programa simple de dibujo");
// crear una etiqueta y colocarla en la parte SOUTH del esquema
// BorderLayout
getContentPane().add(new JLabel("Arrastre el ratón para dibujar"), BorderLayout.SOUTH);
getContentPane().add(j, BorderLayout.NORTH);
// Ahora añadimos listeners propios para los eventos de ratón
addMouseMotionListener(
new MouseMotionAdapter() { // clase interna anónima
// almacenar coordenadas de arrastre de ratón y llamar a repaint
@Override
public void mouseDragged(MouseEvent evento) {
if (cuentaPuntos < puntos.length) {
puntos[cuentaPuntos] = evento.getPoint();
++cuentaPuntos;
repaint();
j.setText("Van: " + cuentaPuntos + " puntos, le quedan: " + (maxPoints - cuentaPuntos) + " puntos");
}
}
} // fin de la clase interna anónima
); // fin de la llamada a addMouseMotionListener
addMouseListener(
new MouseAdapter() { // clase interna anónima
// almacenar coordenadas de click de ratón
@Override
public void mouseClicked(MouseEvent evento) {
if (cuentaPuntos < puntos.length) {
puntos[cuentaPuntos] = evento.getPoint();
++cuentaPuntos;
repaint();
j.setText("Van: " + cuentaPuntos + " puntos, le quedan: " + (maxPoints - cuentaPuntos) + " puntos");
}
}
} // fin de la clase interna anónima
); // fin de la llamada a addMouseListener
setSize(400, 200);
setVisible(true);
} // fin del constructor de Pintor
// dibujar óvalo en un cuadro delimitador de 2 por 2 en ubicación
// especificada en ventana
@Override
public void paint(Graphics g) {
super.paint(g); // borra el área de dibujo
for (int i = 0; i < puntos.length && puntos[i] != null; i++)
g.fillOval(puntos[i].x, puntos[i].y, 2, 2);
}
public static void main(String args[]) {
Painter aplicacion = new Painter();
aplicacion.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
</pre>
<br />
Espero que os sea útil :)Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com1tag:blogger.com,1999:blog-6677093975106556207.post-56517582748872615952011-04-11T10:38:00.001+02:002011-12-20T13:33:41.126+01:00Botones bordes redondos y con forma, personalizar los JButtonDecíamos que una de las características de Swing es su facilidad para personalizar nuestros componentes mediante la modificación de su <i>ComponentUI</i>. Hoy vamos a ver como darle un aspecto personalizado a nuestros botones.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl2coMiS4magZhpxmWniN1qqEAXUIMtUpBLI-UObWneT9D3fh3bcA5v58Xs0WiE7W1RmR0QO-W3Bwmi6ySSeEOm2PB7k2HM8rNt0Pm_UUb6tlmRAh6SRGY_b7BJsXp45_cXMirEZm3Euab/s1600/shapedButton.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl2coMiS4magZhpxmWniN1qqEAXUIMtUpBLI-UObWneT9D3fh3bcA5v58Xs0WiE7W1RmR0QO-W3Bwmi6ySSeEOm2PB7k2HM8rNt0Pm_UUb6tlmRAh6SRGY_b7BJsXp45_cXMirEZm3Euab/s320/shapedButton.JPG" width="320" /></a></div>
Aquí os dejaré unas líneas generales de como hacerlo, pero el límite lo ponéis vosotros y vuestra imaginación. Crearemos una subclase de BasicButtonUI y sobrescribiremos su método paint() para darle un aspecto determinado a nuestros botones y así conseguir este aspecto:<br />
<br />
<pre class="brush: js">import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.plaf.basic.BasicButtonUI;
public class ShapedButton {
private static JFrame frame;
public Component createComponents() {
// Tres botones para probar diferentes efectos
JButton roundButton = new JButton("Redondo");
JButton squareButton = new JButton("Cuadrado");
JButton polygonButton = new JButton("Poligonal");
// Establecemos un UI específico
ShapedButtonUI roundUI = new ShapedButtonUI();
roundUI.setShape(ButtonShape.ROUND, roundButton);
roundButton.setUI(roundUI);
roundButton.setPreferredSize(new Dimension(100, 100));
ShapedButtonUI squareUI = new ShapedButtonUI();
squareUI.setShape(ButtonShape.SQUARE, squareButton);
squareButton.setUI(squareUI);
squareButton.setPreferredSize(new Dimension(100, 100));
ShapedButtonUI polygonUI = new ShapedButtonUI();
polygonUI.setShape(ButtonShape.POLYGON, polygonButton);
polygonButton.setUI(polygonUI);
polygonButton.setPreferredSize(new Dimension(100, 100));
// Añadimos nuestros componentes
JPanel panel = new JPanel();
panel.add(roundButton);
panel.add(squareButton);
panel.add(polygonButton);
return panel;
}
/**
* Definimos tres posibles formas para los botones
*/
public enum ButtonShape {
ROUND,
SQUARE,
POLYGON
}
private class ShapedButtonUI extends BasicButtonUI {
/** Button shape. */
private ButtonShape shape;
public ShapedButtonUI() {
super();
}
public void setShape(ButtonShape shape, JButton button){
// no pintamos el borde
button.setBorderPainted(false);
this.shape = shape;
}
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g;
// definamos las formas de nuestros botones
Shape buttonShape = null;
switch (shape) {
case ROUND:
buttonShape = new RoundRectangle2D.Double(0, 0, c.getWidth() - 1, c.getHeight() - 1, 50, 50);
break;
case SQUARE:
buttonShape = new Rectangle(0, 0, c.getWidth(), c.getHeight());
break;
case POLYGON:
int[] xPoints = {0, 0 + c.getWidth() / 3, 0 + 2 * (c.getWidth() / 3), c.getWidth(), 0 + 2 * (c.getWidth() / 3), 0 + c.getWidth() / 3};
int[] yPoints = {c.getHeight() / 2, 0, 0, c.getHeight() / 2, c.getHeight(), c.getHeight()};
buttonShape = new Polygon(xPoints, yPoints, 6);
break;
}
// establecemos un gradiente para el fondo del boton
GradientPaint gp = new GradientPaint(0, 0, Color.GREEN, c.getWidth(), c.getHeight(), Color.BLUE);
g2d.setPaint(gp);
g2d.fill(buttonShape);
super.paint(g2d, c);
}
@Override
protected void paintButtonPressed(Graphics g, AbstractButton b) {
Graphics2D g2d = (Graphics2D) g;
// definamos las formas de nuestros botones
Shape buttonShape = null;
switch (shape) {
case ROUND:
buttonShape = new RoundRectangle2D.Double(0, 0, b.getWidth() - 1, b.getHeight() - 1, 50, 50);
break;
case SQUARE:
buttonShape = new Rectangle(0, 0, b.getWidth(), b.getHeight());
break;
case POLYGON:
int[] xPoints = {0, 0 + b.getWidth() / 3, 0 + 2 * (b.getWidth() / 3), b.getWidth(), 0 + 2 * (b.getWidth() / 3), 0 + b.getWidth() / 3};
int[] yPoints = {b.getHeight() / 2, 0, 0, b.getHeight() / 2, b.getHeight(), b.getHeight()};
buttonShape = new Polygon(xPoints, yPoints, 6);
break;
}
// establecemos un gradiente para el fondo del boton
GradientPaint gp = new GradientPaint(0, 0, Color.BLUE, 0, b.getHeight(), Color.GREEN);
g2d.setPaint(gp);
g2d.fill(buttonShape);
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
frame = new JFrame("Shaped button");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ShapedButton app = new ShapedButton();
Component contents = app.createComponents();
frame.getContentPane().add(contents, BorderLayout.CENTER);
// Display the window.
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
</pre>Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com2tag:blogger.com,1999:blog-6677093975106556207.post-55580170251366286742011-04-08T10:10:00.000+02:002011-04-08T10:10:23.360+02:00El Look and Feel (L&F) de Swing, cambiar el look and feel de la aplicación<span class="Apple-style-span" style="font-family: inherit;">Tal y como está diseñado Swing, puedes cambiar el "look and feel" (L&F) de nuestras interfaces. "Look" se refiere a la apariencia de los componentes, "feel" se refiere a la manera en que se comportan estos.</span><br />
<span class="Apple-style-span" style="font-family: inherit;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: inherit;">Cada componente Swing se divide en dos clases distintas, una subclase de JComponent y otra subclase de ComponentUI. Por ejemplo un JButton tiene una implementación concreta de ButtonUI.</span><br />
<span class="Apple-style-span" style="font-family: inherit;"><br />
</span><br />
<span class="Apple-style-span" style="font-family: inherit;">Veamos ahora varios ejemplos de como cambiar el look and feel de nuestra aplicación:</span><br />
<span class="Apple-style-span" style="font-family: inherit;"><br />
</span><br />
<h4>Programáticamente</h4><span class="Apple-style-span" style="font-family: inherit;"> Para especificarlo haremos uso del método UIManager.setLookAndFeel()</span><span class="Apple-style-span" style="font-family: monospace;"> </span><span class="Apple-style-span" style="font-family: inherit;">con el nombre completo de una subclase de LookAndFeel y los argumentos apropiados. P ej.</span><br />
<pre class="brush: js">public static void main(String[] args) {
try {
// Establecemos el look and feel "Metal"
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
}
catch (UnsupportedLookAndFeelException e) {
// manejar excepción
}
catch (ClassNotFoundException e) {
// manejar excepción
}
catch (InstantiationException e) {
// manejar excepción
}
catch (IllegalAccessException e) {
// manejar excepción
}
new SwingApplication(); //Creamos y mostramos la interfaz de usuario
}
</pre><br />
<h4>Por línea de comandos</h4>Podemos especificar el L&F por línea de comandos usando el <i>flag </i>-D para establecer la propiedad swing.defaultlaf: P ej.<br />
<br />
<i>java -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel MyApp</i><br />
<br />
<h4>Archivo swing.properties</h4><div>Otra manera es cambiar el swing.properties, es posible que tengamos que crear este archivo. Suele estar ubicado en la carpeta <i>lib </i>de nuestro intérprete de Java.</div><br />
<pre class="brush: js"># Swing properties
swing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel
</pre><br />
<h4>Despues del inicio de la aplicación</h4><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrh_L9nlqfSNjUalsyAuycTnCLf16zwNpdRtePCJsI-nzw99QwCHU_f-P41Hmx8XLJrsH7lS_KArttzgbkpOqPso_TtWiAy9O3QvFEgaV4v-lGmKGZzG875_MDdagSrjdHJKHy1ZwzYd7w/s1600/CabioLaF.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrh_L9nlqfSNjUalsyAuycTnCLf16zwNpdRtePCJsI-nzw99QwCHU_f-P41Hmx8XLJrsH7lS_KArttzgbkpOqPso_TtWiAy9O3QvFEgaV4v-lGmKGZzG875_MDdagSrjdHJKHy1ZwzYd7w/s1600/CabioLaF.JPG" /></a>Se puede cambiar el aspecto de la aplicación incluso despues de haber hecho visible la ventana. Para ahcer efectivo el cambio, deberemos llamar al método updateComponentTreeUI de SwingUtilities por cada contenedor de alto nivel. P ej.<br />
<br />
<i>UIManager.setLookAndFeel(lnfName);</i><br />
<i>SwingUtilities.updateComponentTreeUI(frame);</i><br />
<i>frame.pack();</i><br />
<br />
Para hacer esto algo más gráfico aquí os dejo el código de una aplicación de ejemplo para cambiar el Look and Feel tras iniciar la aplicación.<br />
<br />
<pre class="brush: js">import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LookAndFeelDemo {
static JFrame frame;
JLabel label;
JComboBox combo;
public Component createComponents() {
label = new JLabel("Selecciona un L&F");
combo = new JComboBox();
// Añado elementos al combo
combo.addItem("Metal");
combo.addItem("Nimbus");
combo.addItem("Windows");
combo.addItem("Motif");
combo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
initLookAndFeel(combo.getSelectedItem().toString());
}
});
label.setLabelFor(combo);
JPanel pane = new JPanel(new GridLayout(0, 1));
pane.add(label);
pane.add(combo);
pane.setBorder(BorderFactory.createEmptyBorder(30, // top
30, // left
10, // bottom
30) // right
);
return pane;
}
private static void initLookAndFeel(String LaF) {
String lookAndFeel = null;
if (LaF != null) {
if (LaF.equals("Metal")) {
lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel";
} else if (LaF.equals("Nimbus")) {
lookAndFeel = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
} else if (LaF.equals("Windows")) {
lookAndFeel = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
} else if (LaF.equals("Motif")) {
lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
} else {
lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
}
try {
UIManager.setLookAndFeel(lookAndFeel);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
// Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
// Create and set up the window.
frame = new JFrame("Look And Feel Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
LookAndFeelDemo app = new LookAndFeelDemo();
Component contents = app.createComponents();
frame.getContentPane().add(contents, BorderLayout.CENTER);
// Display the window.
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event dispatch thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre>Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com3tag:blogger.com,1999:blog-6677093975106556207.post-20279350109985690422011-04-04T17:19:00.008+02:002012-02-20T17:37:27.634+01:00¿Qué es Java Swing?<span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">Empecemos por el principio, ¿que es java swing?</span><br />
<div><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">Pues bien, el paquete <span class="Apple-style-span" style="font-weight: bold;">javax.swing </span>nos proporciona una serie de componentes "ligeros<span class="Apple-style-span">" (todo en lenguaje Java) que, al máximo grado posible funcionan igual en todas las plataformas.</span></span></div><div><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">Swing nos permite dotar de una interfaz gráfica de usuario a nuestras aplicaciones, dotándolas de interactividad y riqueza visual.</span><br />
<span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"><br />
</span><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTb5ZKeuuXU9xX2kPv_QdK2dKyJFTqArdlHV1HTfAQXpl4Sw7UIgz8klp8MdCoIovDgkN9rp8BRHXh2NAcIv4nMl3yI4mV3gG3Lf6WNCXakd6P-FZuw5fojuquhJxlF51M05pcYrRDb5pK/s1600/hola_mundo.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTb5ZKeuuXU9xX2kPv_QdK2dKyJFTqArdlHV1HTfAQXpl4Sw7UIgz8klp8MdCoIovDgkN9rp8BRHXh2NAcIv4nMl3yI4mV3gG3Lf6WNCXakd6P-FZuw5fojuquhJxlF51M05pcYrRDb5pK/s320/hola_mundo.JPG" width="320" /></a><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">Veamos nuestro primer ejemplo de esta tecnología al alcance de todos. Para empezar os dejo con el típico ejemplo del "Hola Mundo" hecho con Swing. Copiar, pegar y ejecutar para ver el resultado...</span><br />
<span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"><br />
</span></div><br />
<br />
<br />
<br />
<pre class="brush: js">import javax.swing.JFrame;
import javax.swing.JLabel;
public class HolaMundoSwing extends JFrame {
private static void createAndShowGUI() {
// Crea y prepara la ventana.
JFrame frame = new JFrame(&quot;HolaMundoSwing&quot;);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// A&Atilde;&plusmn;ade la etiqueta &quot;Hola Mundo&quot;.
JLabel label = new JLabel(&quot;Hola Mundo en Swing&quot;);
frame.getContentPane().add(label);
// Mostramos la ventana.
frame.setSize(300, 100);
frame.setVisible(true);
}
public static void main(String[] args) {
// Programa un trabajo para el hilo de despacho de eventos:
// creando y mostrando la ventana de la aplicaci&Atilde;&sup3;n.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
</pre>Anonymoushttp://www.blogger.com/profile/07383456314986472985noreply@blogger.com4