sábado, 19 de mayo de 2012

Deployment o despliegue y distribución de aplicaciones

votar


Llega un momento, en la vida de todo programador principiante, en el que éste quiere enseñar a sus amigos/as el programa tan genial que ha hecho (aunque sólo sea ese en el que sale por la consola la frase “Hola, mundo”). En ese momento, los susodichos amigos/as, hermanos/as, primos/as o padres le dirán algo así como: “Ah, bien. Pero, ¿cada vez que quieras hacer eso tienes que abrir Eclipse/NetBeans/cmd?. ¿No puedes hacer que funcione dándole doble clic a un icono?.” Y nuestro pobre programador novel se queda chafado.

Hoy os vamos a explicar cómo hacer para desplegar vuestras aplicaciones para poder distribuirlas después, o para poder iniciarlas desde el escritorio. Lo vamos a hacer a través de la línea de comandos, porque cada IDE viene con su propio botoncito para hacer esta tarea, y aquí no podemos cubrirlos todos. Además, un poco de MS-Dos o Shell nunca viene mal. Si lo necesitáis, seguro que googleando encontráis un tutorial específico para la IDE que utilizéis vosotros.

Para empezar, lo primero que hay que hacer es crear un fichero .jar. Un fichero .jar no es más que un archivador de java (jar = java archive) para guardar todos los archivos que necesites para ejecutar el programa.

Por ejemplo, supongamos que con tu Bloc de Notas has escrito un programa llamado miPrograma.java. Al compilarlo, verás que automáticamente Java crea miPrograma.class. Supongamos también que has escrito otro programa más complicado que necesita varias clases más y otros archivos de imágenes para funcionar. A este lo llamaremos miOtroPrograma.java. Todos estos archivos los hemos guardado en MisProgramas dentro de nuestro disco duro.

Vamos ahora al cmd para crear los archivos .jar donde guardar estos programas. Para no liarnos con Windows o con Linux, voy a poner simplemente los comandos. Eso sí, recordad que en Windows para ir a algún directorio es:
cd C:\MisProgramas con la barra\
y en Linux es:
$ /MisProgramas con la barra/

Al crear un .jar, Java automáticamente construye un manifiesto MANIFEST.MF donde pone algunos datos sobre el mismo. Nosotros vamos a cambiar este manifiesto para señalar cuál es la clase principal, es decir, dónde está el método main, imprescindible para que todo funcione.
Esto es muy sencillo de hacer. Simplemente abrimos nuestro editor de texto o bloc de notas y escribimos:

Main-Class: miPrograma

Podemos añadir otra línea para que quede bien claro dónde va a estar este programa, poniendo el nombre del fichero que vamos a crear:

Path: .\ficheroUno.jar

Es imprescindible que dejéis un espacio después de los dos puntos. Ahora guardamos este manifiesto con la extensión .txt o .mf en MisProgramas.

A continuación, en cmd, dentro del directorio MisProgramas, tecleamos:

jar -cmf manifiesto.mf ficheroUno.jar miPrograma.class

Y ya está creado el fichero.Es muy importante que sigamos el orden del comando, es decir, si la m de manifiesto va antes que la f de fichero, así es como debemos escribirlos, si no se producirá un error.
Si ahora quisiésemos ver el contenido del fichero basta con teclear:

jar tf ficheroUno.jar

También podemos visualizar el proceso si en lugar de teclear -cmf tecleamos -cvmf.

Pero , ¿qué ocurre con el otro programa, el que tenía varias clases y archivos?. Bueno, puedes crear un fichero .jar colocando todos los archivos uno detrás de otro después de miPrograma.class, pero la verdad es que eso es muy pesado. Lo más cómodo es manejarse con paquetes. Tú ya sabes (o deberías) que para crear un paquete basta que la primera línea de tu clase principal sea algo así:

package miPaquete;

Ordenadito que tú eres, has creado el directorio miPaquete y allí has metido todos los archivos de este paquete. Lo único que tienes que hacer es añadir el paquete entero al fichero, así:

jar -cmf manifiesto ficheroDos.jar miPaquete

Eso sí, manifiesto, que deberás guardar en el mismo directorio en el que esté miPaquete, quedaría así:

Main-Class: miPaquete.miOtroPrograma

para evitar el famoso error de que el fichero de la clase principal no se encuentra o no ha sido cargado.

Ahora puedes ejecutar el programa de varias maneras:
-desde el cmd, si no has modificado el manifiesto, con

java -cp ficheroUno.jar miPrograma
java -cp ficheroDos.jar miPaquete.miOtroPrograma

-desde el cmd, si has modificado el manifiesto, con

java -jar ficheroUno.jar
java -jar ficheroDos.jar

-o simplemente, en Windows, yendo al fichero .jar que se ha creado en MisProgramas y cliqueando sobre él dos veces (esto es cierto sólo a partir de Java 1.5, aunque se puede modificar Windows para que también lo haga con versiones anteriores, pero, vamos, ya es hora de que actualices tu Java). También puedes crear un acceso directo en el escritorio, para lucirte más.

Recuerda además que puedes ver el contenido de tu fichero con WinZip o WinRar. Este mismo fichero se ejecutará sin problemas en cualquier ordenador que tenga instalada la JVM. ¿Y si no?. Bueno, en ese caso hay varias soluciones.

Se puede crear una carpeta en la que que se guarde el archivo jar, una carpeta con el JRE (Java Runtime Environment) y un archivo .bat (o .sh en Unix) que tenga el siguiente texto:

jre\bin\java.exe -jar installer.jar

Yo no lo he probado, así que no sé si funciona. Si alguno lo ha hecho, por favor que nos lo comente.

Otra opción , pensada sobre todo para los usuarios de Windows, son los programas que convierten los archivos .jar en .exe. Algunos de estos programas, como JSmooth o launch4j son gratuítos y puedes configurarlos a tu gusto. Podéis encontrar tutoriales sobre el tema incluso en YouTube.


En fin, espero que esta entrada os haya servido al menos para poder poner en vuestro escritorio esa aplicación tan chula que habéis hecho. :-)










sábado, 12 de mayo de 2012

Manejo de BufferedReader: convertirlo a ArrayList o Array

votar
   La entrada de hoy va a ser más breve, por su temática mayormente práctica. La clase BufferedReader es una de las más usadas en java, pero su utilización se aprende más a través de ejemplos que enrollándonos con un montón de teoría.

   Aún así, para los que no la conozcáis, os diré que BufferedReader pertenece al paquete java.io  y se utiliza para "leer"  archivos. Pero no se le puede pasar un archivo directamente como argumento al constructor, por que no lo admite, así que primero hay que crear un FileReader, que admite tanto archivos como Strings, y luego este FileReader será el argumento del constructor del BufferedReader. Si esto os parece muy lioso, veréis como se entiende mejor con un ejemplo.

   Supongamos que tenéis un archivo que queréis leer, y no sólo eso, si no que después queréis trabajar con él y para ello necesitáis convertirlo en un ArrayList o un Array, o incluso separarlo en partes. Todo eso lo veremos con el siguiente ejemplo.

    Yo he creado un mini-archivo para utilizar aquí, pero vosotros podéis usar alguno vuestro, todo lo amplio que queráis. El mío consiste en unas definiciones de unas palabras gallegas tomadas de un diccionario (no pasa nada si no entendéis gallego, lo importante es que comprendáis el código que viene luego ;) ).

lercho, -a: (de lercha<prerrom.*liscola<*lisca<celta *vlisca = vara).adx. 1.Lingoreteiro, insolente. 2.Dise da persoa que fala máis do debido. 3.Indecente. 4.Lacazán, preguiceiro. 5.Dise da persoa que come e bebe demasiado.
leria: (lat.lerias<gr.leros).s.f. 1.Conversa informal(estanche de leria). 2.Chanza, broma (tes moita gana de leria). 3.Conto, enredo, chisme, maraña, lío (déixate de lerias).
leriante: (de leria). adx. e s. 1.Lercho. 2.Dise da persoa que é moi bromista ou da que ten moita labia.
lerio: (de leria). s.m. 1.Asunto no que hai algunha complicación (andar metido nun lerio). 2.Lío, maraña, enredo (non se decataron do lerio). 3.Caso (o peor do lerio é que entre eles non se entenden). 4.Chisme, cousa sen importancia.



import java.io.*;
import java.util.*;
import java.util.regex.*;

public class Archivos{
   public static void main(String[] args){
      try{
         //El constructor de BufferedReader no admite directamente un archivo
         //por eso usamos FileReader
         BufferedReader reader = new BufferedReader(new FileReader("voc.txt"));
       
         //Vamos ahora a convertir el reader en un ArrayList.
         //  Nunca inicializéis String linea = reader.readLine() o dentro de 
         //  while se producirá un bucle infinito (puesto que linea nunca será nul
         String linea;
         List<String> arlist = new ArrayList<String>();
         while((linea=reader.readLine())!= null){ 
            arlist.add(linea);
          } 
            System.out.println(arlist);
         
        //Si ahora quisiésemos convertir ese ArrayList en un Array,
        //  haremos lo siguiente
         String[] s1 = arlist.toArray(new String[arlist.size()]);
         

        //Para separar el texto en dos array distintos
          String[] palabras;
          String[] definiciones;
          for (String st : arlist){
             Pattern  patrón = Pattern.compile("[(].+$");
             palabras = patrón.split(st);
             System.out.println(palabras[0]);
             }
           for (String str : arlist){
             Pattern patrón2 = Pattern.compile("[\\w]+:");
             definiciones = patrón2.split(str);
             System.out.println(definiciones[1]);
            }
          
        //Nunca olvidéis cerrar el BufferedReader. 
          reader.close();
        
       }catch(IOException ioe){
         System.out.println("Oh,oh");
       }catch(PatternSyntaxException pse){
         System.out.println("Oh,oh");
       }
     }
    }

   Como podéis ver, hemos utilizado también el paquete java.util.regex, que utiliza expresiones regulares para el manejo de texto. Conocer estas expresiones regulares es casi como aprenderse un lenguaje de programación nuevo. Para los que no sepáis nada del tema, podéis echar un ojo al tutorial de Oracle


   En este ejemplo, con el uso de las clases de regex hemos separado por un lado las palabras y por otro sus definiciones.


   Espero que esta entrada os haya sido útil.

sábado, 5 de mayo de 2012

Redimensionamiento de imágenes en componentes de JFrame

votar
   En la entrada de esta semana vamos a tratar de cómo añadir imágenes en una interfaz gráfica de usuario o GUI.
   Como este blog esta pensado para ayudar a los que empiezan, vamos a partir de cero y crear dicha interfaz. Los que ya seáis expertos podéis saltaros esta parte.

   En Java, la creación de ventanas, botones, campos de texto, etc. se hace a través de las apis de java.awt. y javax.swing. No vamos ahora a ver la jerarquía ni los aspectos teóricos de estas clases, porque es un tema muy extenso, pero os recomiendo que echéis un ojo a los docs de Oracle.

   Yendo a lo práctico, si queréis hacer una ventana hay que crear primero un marco (frame) en el que pondremos un panel (panel) y en él todos los demás objetos que queramos añadir. Un ejemplo muy sencillo sería:


import java.awt.*;
import javax.swing.*;
import javax.swing.JFrame;

public class DemosFrame extends JFrame{
    //Vamos a crear componentes
    private JButton botón = new JButton("Esto es un botón");
    private JLabel label = new JLabel("Esto es una etiqueta");
    private JTextField textfield = new JTextField("Esto es un campo de texto");
    private JTextArea textarea = new JTextArea("Esto es un área de texto");
   //Podríamos añadir más cosas, pero como muestra vale.

   DemosFrame(){ //constructor de DemosFrame
      JPanel panel = new JPanel(); //creamos el panel
      //Ahora añadimos todo al panel
      panel.add(botón);
      panel.add(label);
      panel.add(textfield);
      panel.add(textarea);
      setContentPane(panel); //añadimos el panel al marco
   }

   public static void main(String[] args){
      DemosFrame frame = new DemosFrame(); //creamos el marco
      
      frame.setSize(400,400); //le ponemos las medidas que queramos
      frame.setLayout(new FlowLayout()); //colocamos los componentes según la disposición que mejor nos convenga
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //para salir del programa al cerrar la ventana
      frame.setLocationRelativeTo(null); //para centrar la ventana en la pantalla
      frame.setVisible(true); //¡Nunca hagáis visible el marco antes de añadirle todo lo demás!
   }
}

   Recordad que los componentes se colocan en el panel, no en el marco.

   Ahora bien, supongamos que ahora queremos añadir una imagen. ¿Cómo lo hacemos? Lo habitual es utilizar ImageIcon, una implementación de la interfaz Icon que nos permite añadir archivos de imágenes con extensiones GIF, JPEG o PNG para colocarlas en botones, etiquetas o paneles.

   Suponed que tenéis una imagen que queréis añadir a un botón. La forma de hacerlo es muy sencilla: 

    ImageIcon icon = new ImageIcon("imagen.gif");

si la imagen está en el mismo directorio, o bien

   ImageIcon icon = new ImageIcon("ruta/imagen.gif");

si la imagen está en otro.
(Notad que en Unix el path se separa con "/", mientras que en Windows podéis usar "/" o "\\")

   Y a continuación:

   JButton botón = new JButton(icon);

   Pero si la imagen no la tenéis en vuestro equipo, si no que queréis descargarla de internet, tenéis que hacer lo siguiente:

   java.net.URL sitio = new URL("http://www.sitio.com/imagen.gif");
   ImageIcon icon = new ImagenIcon(sitio);

  Y luego añadirlo a donde queráis. Tened en cuenta que lanza una MalformedURLException que hay que declarar o manejar.

   Pero, ¿qué ocurre si la imagen es demasiado grande? Por ejemplo, tenemos una foto y queremos colocarla en un botón, pero no nos cabe porque ocupa toda la pantalla. Bueno, ni Icon ni ImageIcon tienen un método para redimensionar imágenes, pero la clase Image sí, e ImageIcon tiene un constructor que acepta instancias de Image como parámetros. Así que, esto es lo que haremos: 


/*Método mostrado por Gregg Bolinger en JavaRanch*/ImageIcon icon = new ImageIcon("miimagen.jpeg");
Image img = icon.getImage(); //convertimos icon en una imagen
Image otraimg = img.getScaledInstance(115,230,java.awt.Image.SCALE_SMOOTH); //creamos una imagen nueva dándole las dimensiones que queramos a la antigua
ImageIcon otroicon = new ImageIcon(otraimg);
JButton botón = new JButton(otroicon);


   Y eso es todo lo que hay que hacer para ajustar el tamaño de la imagen a nuestras necesidades. Fijaos en que el primer número de getScaled() corresponde al ancho y el segundo al alto de la imagen.


   Esperamos que os haya sido útil. :-)