T.A.P.

Técnicas Actuales de Programación

Curso: 2019/20

Calendario

Septiembre
LMMJV
[1]910111213
[2]1617181920
[3]2324252627
[4]30    
Octubre
LMMJV
[4] 1234
[5]7891011
[6]1415161718
[7]2122232425
[8]28293031 
Noviembre
LMMJV
[8]    1
[9]45678 *
[10]111213lab *1415
[11]18lab *19lab *20 *2122
[12]252627lab2829
Diciembre
LMMJV
[13]23456
[14]91011 *1213
[15]161718lab1920
 N  no lectivo,  N  fiesta,  N  estudio,  N  exámenes, N N clase, N clase anulada

* 8 nov. Cedemos la segunda hora a la asignatura DEO. Se recupera el 13 nov.
* 13 nov. De 10:40 a 11:30 recuperamos la hora cedida el 8 nov a la asignatura DEO.
* 20 nov., 11 dic.: Las sesiones de laboratorio se han cambiado a lunes 18 nov. (AI.4) y martes 19 nov. (AI.1)

(he hecho esta paginilla de ayuda para localizar aula informática que puede ejemplificar lo que puede hacerse con 20 lineas de Java: lanzar 11 peticiones a un servidor web que hace de front-end de una base de datos, procesar su respuesta -una tabla en HTML- y extraer toda la información, combinandola de la manera requerida para generar la respuesta HTML que necesitamos.)

Clases: {aula: 0.20S} {horario: jueves 10:40-11:30, viernes 9:40-11:30
Laboratorios: {aula: AI.4 -excepto día 19N: AI.1-} {horario: 15:00-17:30}
Tutorias: {con las excepciones que se indiquen en GAUR, JV 8:00..9:30, J 11:30..13:00, V 12:00..13:30}

Programa

El programa de la asignatura se corresponde casi en su totalidad con un curso de Java, puesto que es posiblemente el lenguaje que mejor soporta las técnicas actuales de programación. A lo largo del desarrollo del curso se irán destacando las técnicas que Java incluye o facilita.

Temario

Desde que apareció Java, allá por 1995, la secuencia de versiones ha sido muy llevadera y "considerada" con los usuarios (compatibilidades absolutas en todos los sentidos). Desde hace poco tiempo el modelo ha cambiado para dar respuesta más rápida a las nuevas características que se hacen necesarias (es algo que está sucediendo en multitud de desarrollos, no sólo en Java). Esto supone la capacidad de estar mucho mas "al día", pero es una incomodidad ya que requiere cambios muy frecuentes (cada 6 meses). (ver esto)

La última versión estable de Java es la 12, y será sustituida por la 13 en cuento comencemos el curso. No obstante, para el contenido del curso es suficiente con la versión 7. Las capacidades añadidas desde la versión 8 van más allá de lo que es un curso inicial de Java, aunque algunas cuestiones aportadas por dichas versiones serán comentadas en clase.

Por otro lado, a la par de la introducción de la versión 9 de Java, el mantenimiento del entorno de desarrollo que utilizaremos (Netbeans) pasó de manos de Oracle (la empresa propietaria de Java) a Apache (fundación para desarrollo de software libre), y después de algo más de un año parece que la versión actual (11.1) ha terminado por implantar todas las características que se encontraban en la que nos resultaba adecuada anteriormente (la 8).(La versión 11.1 no es LTS, pero carece de cierta capacidad que puede ser interesante para algunos alumnos que quieren avanzar un poco más de lo estrictamente incluido en el curso)

Con todo ello nos quedamos con que:
        * Instalaremos Java 12 y Netbeans 11.1 (con lo que tenemos plataforma e IDE "más que de sobra")
        * comentaremos algunas características interesantes de versiones posteriores

Documentación de utilidad (más documentación en el apartado "Extras"):
* La referencia definitiva del lenguaje Java {suficiente: versión 7} {actual: versión 12}
* La documentación de la plataforma SE{suficiente: versión 7} {actual: versión 12}
* Los "tutoriales" de Java

Evaluación

Convocatoria ordinaria

Acceso al estado de evaluación personalizado

Nota: antes de entregar cualquier ejercicio hay que, por lo menos, "adecentar" el código. Lo correcto sería incluso escribir la documentación, pero por lo menos hay que dejarlo "listo para revista": eliminar ficheros abandonados, lineas de código de prueba, etc...

Convocatoria extraordinaria

Desarrollo

SEPTIEMBRE

Jueves 12 de septiembre de 2019
  • Presentación usando como apoyo esta misma página web
Viernes 13 de septiembre de 2019

//Hablamos de evaluación, que ayer quedó pendiente.

1 - INTRODUCCIÓN

//Nos quedamos en "Java en contexto" -->La máquina virtual.

Jueves 19 de septiembre de 2019

//Continuamos donde lo dejamos...
...y terminamos con "Java en contexto"

Viernes 20 de septiembre de 2019

TEMA 2 - USO DEL ENTORNO DE DESARROLLO

//Paramos tras ver la estructura d ela biblioteca de clases.

  • CORRECCIÓN DE ERROR: Al salir de clase me vino a la cabeza la idea de que os mencioné el "prototipado blando y duro". Creo que estuve diciendo "eso", y es algo totalmente erroneo en lo que a la terminología se refiere. Os hablaba de "tipado" (determinación/especificación de los tipos)... no de prototipado, que es otra cosa en desarrollo software. Por otro lado no se habla de duro/blando, sino de fuerte/debil (del inglés strong/weak). A veces lo que quiero decir y lo que digo son cosas distintas... espero no confundiros "demasiado".

  • SOBRE HERRAMIENTAS UML: Os comenté que no disponemos de buenas herramientas para trabajar con UML, y que en todo caso se puede encontrar alguna que supuestamente funciona, pero que son extremadamente caras (las usan algunas grandes corporaciones). Quiero dejar claro que me refiero a herramientas para generar código y hacer ciclo cerrado UML->código->UML, no meramente para dibujar diagramas. Para dibujar sí que existen algunas aplicaciones, y cada vez van apareciendo más, sobre todo últimamente con soporte en la web (online). Evidentemente tienen la misma función de ayuda al desarrollo (particularmente en equipo, donde se comparten ideas y realizan presentaciones), pero a lo que me refería era, como os digo, a su integración con el resto de herramientas.

    Las herramientas definitivas pudieron ser las de Rational Software, empresa desde la que se creo UML, pero fue comprada en 2008 por IBM que parece no tener mucho interés en su mantenimiento aunque las siga comercializando. En el tweet de al lado vemos a Grady Booch, uno de los padres de UML y director científico de desarrollo de software de IBM, diciendo que usa StarUML, (en combinación con el IDE CLion para C/C++, y no sé si podrá integrarse con Netbeans -hace 10 años sí, pero todo ha cambiado mucho-).

    Una herramienta bastante potente que se integra con los diferentes IDEs (no de modo sencillo) es Visual Paradigm. Sin ser excsivamente cara, tampoco es barata.

    En este momento me parece particularmente interesante Modelio por ser un desarrollo en código abierto que ha dado lugar a un "store" en el que presumiblemente se iran encontrando utilidades interesantes (al parecer ahora mismo existe una que permite la generación de código Java, aunque es de pago dentro de una versión comercial de Modelio).

Jueves 26 de septiembre de 2019

//Continuamos donde lo dejamos... recalcando la importancia de los comentarios y la documentación; los "TODO"; identificadores: convenio de nombrado, idoneidad; refactoring;

Viernes 27 de septiembre de 2019

Adelanto de los puntos 1 y 2 del
TEMA 6 - INTERFACES GRÁFICOS

Construir un interfaz de calculadora simple.
A modo de ejemplo, este mismo:
interfaz de calculadora estrecho    interfaz de calculadora ancho

(Recibidos en cursos anteriores..., más...)

OCTUBRE

Jueves 3 de octubre de 2019
  • Sabemos usar Netbeans para montar GUIs, pero no hemos visto Swing a fondo. Echamos un vistazo a la demo
  • A raíz del código generado para la calculadora... algunas observaciones:
    • MVC y el JFrame en nuestra aplicación.
    • refactoring, búsquedas, ...
    • identificadores a todos los niveles (convenio de nombrado, idoneidad, ...) espacios de nombres (ejemplos aquí)
Viernes 04 de octubre de 2019

TEMA 3 - ELEMENTOS BÁSICOS DEL LENGUAJE

//Nos quedamos a punto de ver "Otros operadores"

Jueves 10 de octubre de 2019

//Continuamos donde lo dejamos...
// ...nos quedamos a punto de ver "rupturas de secuencia II"

Viernes 11 de octubre de 2019

//Continuamos donde lo dejamos y terminamos el tema

Vemos el siguiente ejercicio propuesto con Netbeans. Medimos el tiempo de ejecución de diferentes soluciones. Observamos que la puede parecer más rápida es similar a la anterior. Para concluir algo al respecto deberíamos lanzar una batería de repeticiones con cada caso y comparar los resultados estadísticos (valores medios de ambos tiempos con un intervalo de confianza dado). En todo caso, si son muy parecidos, cabe plantearse cual es la intervencion en nuestro código del compilador (desensamblando el .class) y de la JVM (perfilando la ejecución).

La solución que se presenta aquí está minimamenta más depurada que la mejor de las vistas en clase

Obtención del número Pi mediante aproximación por serie.

Se trata de calcular el número π con precisión de cuatro decimales mediante la serie:

La especificación de cuatro decimales hace referencia al criterio de parada en la suma de términos de la serie, no a la presentación de la solución, que se hará normalmente mediante System.out.println(.) y que nos mostrará un número de decimales que no podemos controlar por ahora.

Una solución:
private static double pi() {
        double piCuartos = 0.0;
        for (int n = -1; i <= 100_000_000; )  piCuartos += 2.0/(n+=2)/(n+=2);
        return piCuartos * 4;
    }

Los programas que se utilizan para calcular PI con un número de decimales extremadamente alto utilizan series evolucionadas a partir de la sorprendente fórmula descubierta por Ramanujan ("El hombre que conocía el infinito") en 1910 y demostrada no hace mucho tiempo:

Su convergencia es exponencial y ya el primer término aporta 6 decimales. Puede ser un buen ejercicio utilizar esta fórmula para el cálculo de PI, aunque enseguida se verá que es "demasiado buena" para lo que podemos hacer con variables primitivas (e incluso con otros recursos que nos aporta Java).

Obtención de números Perfectos

Escriba una RUTINA que determine si un número dado es perfecto o no.

static boolean isPerfect(long n) {
                //TODO hacer lo necesario para que "isPerfect" retorne "true" o "false" si n es perfecto o no.
                }

Un número perfecto es un entero positivo igual a la suma de sus divisores propios. Los divisores propios de un entero positivo son todos sus divisores a excepción de sí mismo. (Ejemplo de número perfecto: el 6, porque sus divisores propios son 1, 2 y 3 y 6=1+2+3.)

Utilizando dicha rutina debera obtener una lista de números perfectos entre el 1 y el 100.000

Resultado de la ejecución:
6 = 1+2+3
28 = 1+2+4+7+14
496 = 1+2+4+8+16+31+62+124+248
8128 = 1+2+4+8+16+32+64+127+254+508+1016+2032+4064

Listado de Números Perfectos [wikipedia]

Una solución: TBD
Jueves 17 de octubre de 2019

TEMA 4 - ELEMENTOS RELACIONADOS CON LA ORIENTACIÓN A OBJETOS

//Terminamos a ver la herencia, a falta de comentar la extensión por defecto y hablar de sobre-escritura.

Viernes 18 de octubre de 2019

//Continuamos donde lo dejamos...
...y terminamos en encapsulamiento a falta de ver dónde usar los atributos y probar con Netbeans, y dejando pendiente volver al tema 6 para ver la atención a eventos.

Jueves 24 de octubre de 2019

//Continuamos donde lo dejamos...
...y terminamos en "static" a falta de verlo como inicializador de clase. Aún sigue pendiente volver al tema 6 para ver la atención a eventos.

Viernes 25 de octubre de 2019

//Continuamos donde lo dejamos... y terminamos el tema 4.

Jueves 31 de octubre de 2019

Intercalamos el punto 3 del
TEMA 6 - INTERFACES GRÁFICOS

NOVIEMBRE

Jueves 7 de noviembre de 2019

//Continuamos donde lo dejamos... revisaremos con un poco de calma el ejemplo hecho a mano y veremos cómo resuelve Netbeans con la ayuda para montar GUIs.

  • Hablamos un poco de "debug"
Viernes 8 de noviembre de 2019
  • Hablaremos un poco de clases de test
  • Antes de avanzar, volveremos un momento al ejercicio pendiente de los números Perfectos

TEMA 5 - MECANISMO DE TRATAMIENTO DE EXCEPCIONES Y ERRORES

Miércoles 13 de noviembre de 2019 [clase de recuperación: 10:40-11:30; LABO AI.1: 15:00-17:30]
  • por la mañana: //Continuamos donde lo dejamos...
  • por la tarde: Calculadora [pdf]
Jueves 14 de noviembre de 2019
  • //Continuamos donde lo dejamos... y terminamos.
  • Vemos cómo resolver el ejercicio de la calculadora.
Lunes 18 de noviembre de 2019 [LABO AI.1: 15:00-17:30]
Martes 19 de noviembre de 2019 [LABO AI.1: 15:00-17:30]

Finalizamos con el punto 4 del
TEMA 6 - INTERFACES GRÁFICOS

Jueves 21 de noviembre de 2019

Hemos dedicado la hora a resolver dudas ‎👍

Viernes 22 de noviembre de 2019
  • Primera hora: examen de test.

TEMA 7 - EL CONTENIDO DE LA BIBLIOTECA DE CLASES

Los primeros apartados de este tema consisten en el estudio de diversas clases imprescindibles por diversos motivos. Usaremos la versión 7 de la documentación, porque la 8 se complica en exceso en determinados puntos (principalmente Colecciones) y se sale de lo que podemos hacer en un curso con el tiempo disponible y en que no vemos programación funcional. (ni qué decir de la versión 13, aunque para este tema no se complica en exceso la API frente a la versión 8)

Miercoles 27 de noviembre de 2019 [LABO AI.4: 15:00-17:30]
Jueves 28 de noviembre de 2019

//Continuamos donde lo dejamos...
...y vemos hasta Java.lang a falta de profundizar en StringBuffer/StringBuilder

Viernes 29 de noviembre de 2019

DICIEMBRE

Jueves 5 de diciembre de 2019

TEMA 8 - Entrada y salida de datos

Jueves 12 de diciembre de 2019
  • Continuamos con IO
  • Probamos con netbeans
    • copia byte a byte sin buffer y con buffer
    • lectura y escritura de texto con codificación por defecto y con control de la codificación
    • cómo imprimir una traza de error en un GUI // Esto ha quedado sin ver

Aquí el proyecto desarrollado en clase para comprobar el funcionamiento de las clases de IO. He añadido al final un método en el que se ve cómo, aparte de los origenes y destinos vistos, determinados objetos pueden proporcionarnos streams que permiten accesos a otros recursos siguiendo el mismo modelo. En este caso un objeto URL (Universe Resource Locator) nos proporciona un InputStream conectado a un fichero en un servidor web. La misma rutina para copiar un fichero nos sirve para hacer una copia local del fichero remoto con la única diferencia de ese stream de entrada.

Viernes 13 de diciembre de 2019

// Vemos el ejemplo que quedó ayer sin ver

TEMA 9 - Hilos

  • Hilos [pdf]. // Llegamos a ver productores y consumidores. tenemos que ver el cubículo y la ejecución
Miercoles 27 de diciembre de 2019 [LABO AI.4: 15:00-17:30]
Jueves 19 de diciembre de 2019

// Volveremos por un momento a I/O para ver el uso de Serializable y la palabra reservada transient (actualizado el proyecto del día 12)
//Seguimos con hilos, viendo el cubículo y la ejecución del ejemplo

Viernes 20 de diciembre de 2019

// Veremos la rutina "findMostSimilars" de la última práctica. aquí el proyecto desarrollado en clase

TEMA 10 - Programación en red

En este apartado veremos un ejemplo simple de aplicación cliente-servidor. Se tratará simplemente, en primer lugar, de establecer la conexión y enviar Strings desde el cliente al servidor, para, más adelante, completar este ejemplo con la posibilidad de atender a multiples clientes y establecer el la comunicación de Strings en ambos sentidos.

En el siguiente recuadro tenemos el código de un servidor mínimo. En la línea 6 se instancia un objeto ServerSocket "escuchando" al puerto 6000, y posteriormente se entra en un ciclo infinito. La primera acción de este ciclo es esperar a un cliente (línea 8). Cuando surje, el método accept nos devuelve una conexión ("s") con él (un socket). Al objeto "s" le pedimos los streams de entrada y de salida en las líneas 11 y 12, que después recubrimos convenientemente a nuestras necesidades actuales como un BufferedReader y un PrintStream en 13 y 14 (podríamos haber prescindido de todo lo referente a salida puestoq ue este ejemplo no hara uso de ella, pero lo ponemos para mostrar el procedimiento habitual).

Una vez que disponemos de los streams podemos "leer" lo que nos envie el cliente e igualmente "escribirle". En este ejemplo nos limitamos a un bucle de lectura (líneas 17-19) del Reader sin que exista ninguna particularidad por el hecho de que el origen de los datos sea una máquina diferente. En el ejemplo se consulta si el contenido de la String recibida es "exit" para terminar el ciclo de lectura. En tal caso se cierra el Socket (línea 21) terminando el código del ciclo general y volviendo por tanto al punto de espera a un nuevo cliente (línea 8).

Observesé que en este ejemplo la conexión termina por cierre del Socket por parte del servidor. Lo mismo podría haberse hecho desde el cliente, lo que resultaría en una excepción en la lectura del Reader. Podía haberse establecido éste como mecanismo de terminación. En todo caso en una aplicación correcta habría de tenerse en cuenta esta posibilidad de cierre de la conexión or parte del cliente, de modo que habrá de atenderse a la excepción que aquí se arroja.

 1 import java.io.*;
 2 import java.net.*;
 3
 4 public class Server {
 5   public static void main(String[] args)throws IOException{
 6     ServerSocket ss=new ServerSocket(6000);
 7     do {
 8       Socket s=ss.accept();
 9       System.out.println("\n\n***Conexion establecida con: "+s);
10
11       InputStream is=s.getInputStream();
12       OutputStream os=s.getOutputStream();
13
14       BufferedReader br=new BufferedReader(new InputStreamReader(is));
15       PrintStream ps=new PrintStream(os);
16       String query;
17       while (!(query=br.readLine()).equals("exit")) {
18         System.out.println("He recibido: "+query);
19       }
20       System.out.println("***Cerrando conexion con: "+s+"\n\n");
21       s.close();
22     } while (true);
23   }
24 }

El cliente, para establecer una conexión con el servidor conocido, instancia directamente un Socket indicando la dirección de la máquina del servidor (como texto) y el número de puerto (línea 7). Del mismo modo que en el caso del servidor, el Socket permite acceder a los streams de entrada y salida que, a continuación, son recubiertos adecuadamente (9-10, 12-13).

Este cliente se limita a leer el teclado línea a línea y enviar la String al servidor, para lo cual recubre el System.in con un BufferedReader y en un ciclo infinito lee de teclado, escribe en el PrintStream que recubre al stream de salida del Socket y controla si el texto es "exit" para terminar en tal caso.

 1 import java.io.*;
 2 import java.net.*;
 3
 4 public class Client {
 5
 6     public static void main(String[] args) throws UnknownHostException, IOException {
 7     Socket s=new Socket("127.0.0.1",6000);
 8
 9     InputStream is=s.getInputStream();
10     OutputStream os=s.getOutputStream();
11
12     BufferedReader br=new BufferedReader(new InputStreamReader(is));
13     PrintStream ps=new PrintStream(os);
14
15     BufferedReader teclado=new BufferedReader(new InputStreamReader(System.in));
16     String q;
17     do {  q=teclado.readLine();
18       ps.println(q);
19       if (q.equals("exit")) System.exit(0);
20     } while (true);
21   }
22 }

Una vez vistos el servidor y el cliente anteriores, vamos a añadir un par de características necesarias para que sean minimamente de utilidad.

En primer lugar, el servidor sólo es capaz de servir a un cliente, de modo que si un segundo cliente pretende conectar, como el servidor no se encuentra en el accept, no obtiene respuesta. Para ello es necesario que el servidor tenga capacidad para llevar a cabo un hilo de ejecución asociado a cada cliente, de modo que lo que hacemos es instanciar un nuevo objeto cada vez que se retorna del accept, dándole el Socket y delegando en él toda la relación con el cliente.

La clase ThreadedSocket extiende Thread y en su método run se encarga de obtener los streams, recubrirlos adecuadamente y mantener el ciclo de comunicación con el cliente.

 1 import java.io.*;
 2 import java.net.*;
 3
 4 public class ThreadedServer {
 5   public static void main(String[] args)throws IOException{
 6     ServerSocket ss=new ServerSocket(6000);
 7     do {
 8       Socket s=ss.accept();
 9       new ThreadedSocket(s);
10     } while (true);
11   }
12 }
13
14 class ThreadedSocket extends Thread {
15   Socket s;
16   ThreadedSocket(Socket s){super(); this.s=s; start();}
17
18   public void run() {
19       System.out.println("\n\n***Conexion establecida con: "+s);
20
21     try{
22       InputStream is=s.getInputStream();
23       OutputStream os=s.getOutputStream();
24
25       BufferedReader br=new BufferedReader(new InputStreamReader(is));
26       PrintStream ps=new PrintStream(os);
27       ps.println("OK");
28       String query;
29       while (!(query=br.readLine()).equals("exit")) {
30         System.out.println("He recibido: "+query);
31         ps.println("OK");
32       }
33       System.out.println("***Cerrando conexion con: "+s+"\n\n");
34       s.close();
35     } catch (Exception e) {
36     }
37   }
38 }

En nuestro ejemplo inicial, el cliente sólo era capaz de enviar lineas de texto al servidor, pero normalmente un cliente también tendrá que recibir información, de modo que en este caso también hay tareas a llevar a cabo en paralelo: la que ya llevabamos a cabo -copiar del teclado al servidor- y la nueva -copiar del servidor a la salida estándar-.

Para llevar a cabo la nueva tarea definimos una clase (lo hacemos de modo local a la rutina main) que se encargará automáticamente de realizar el "eco" de lo recibido del servidor en la salida estándar. De este modo la simple instanciación de un objeto de esta clase nos basta para completar la funcionalidad buscada.

 1 import java.io.*;
 2 import java.net.*;
 3
 4 public class ThreadedClient {
 5
 6   public static void main(String[] args) throws UnknownHostException, IOException {
 7     Socket s=new Socket("127.0.0.1",6000);
 8
 9     InputStream is=s.getInputStream();
10     final BufferedReader br=new BufferedReader(new InputStreamReader(is));
11     class Echo extends Thread{
12         Echo(){setDaemon(true);start();}
13         public void run(){
14           try {while (true)System.out.println(br.readLine());}catch (IOException e){}}
15         }
16     Echo e=new Echo();
17
18     PrintStream ps=new PrintStream(s.getOutputStream());
19     BufferedReader teclado=new BufferedReader(new InputStreamReader(System.in));
20     String q;
21     do {q=teclado.readLine();
22         ps.println(q);
23         if (q.equals("exit")) System.exit(0);
24     } while (true);
25   }
26 }

Se ha visto un ejemplo mínimo y se han añadido las dos funcionalidades necesarias para que tengamos la posibilidad de mantener un intercambio de frases entre un conjunto indeterminado de clientes y el servidor. Esto ha sido muy sencillo entre otras cosas porque no ha sido necesario establecer sincronismos entre hilos (no hay cooperación) ni un protocolo de comunicación (sólo se han cruzado cadenas de texto, no mensajes con diferentes contenidos).

Un modo muy sencillo de establecer comunicaciones cliente-servidor mediante un protocolo consiste en intercambiar objetos (en lugar de textos) recubriendo los streams con ObjectInputStream y ObjectOutputStream, de modo que la complejidad del protocolo queda embebida en la estructura de los objetos.

Extras

Páginas con ejercicios en la Web (aportaciones realizadas por varios alumnos -un agradecimiento general a ellos-).
Directamente relacionados con el curso
Cusiosidades sobre lenguajes e ingeniería del software
No son pocos los alumnos con inquietudes relacionadas con el desarrollo de video juegos

Java Magazine

2011: premiere, nov.-dic.
2012: ene.-feb., mar.-abr., may.-jun., jul.-ago., sep.-oct., nov.-dic.
2013: ene.-feb., mar.-abr., may.-jun., jul.-ago., sep.-oct., nov.-dic.
2014: ene.-feb., mar.-abr., may.-jun., jul.-ago., sep.-oct., nov.-dic.
2015: ene.-feb., mar.-abr., may.-jun., jul.-ago., sep.-oct., nov.-dic.
2016: ene.-feb., mar.-abr., may.-jun., jul.-aug., sep.-oct., nov.-dic.
2017: ene.-feb., mar.-abr., may.-jun., jul.-ago., sep.-oct., nov.-dec.
2018: ene.-feb., mar.-abr., may.-jun., jul.-ago., sep.-oct. nov.-dic.
2019: jan.-feb. no publicado, mar.-abr. may.-jun.
Ya no es descargable como pdf. Pueden localizarse online

"Not So Frequently Asked Questions"

En ocasiones alguna pregunta nada habitual puede ser de interés general....

He diseñado mi propio tipo de letra. ¿Cómo puedo incluirlo en mi aplicación?

El mundo del diseño de "Fonts" (cosa de las Bellas Artes) y su uso en computadoras no es trivial. Todo lo necesario para el uso con Java se encuentra en el correspondiente tutorial de Oracle. Como respuesta concreta a cómo contar con un tipo de letra propio, se puede entresacar del mismo este sencillo código:

try { GraphicsEnvironment. getLocalGraphicsEnvironment(). registerFont(Font.createFont(Font.TRUETYPE_FONT, new File("A.ttf")); } catch (IOException|FontFormatException e) { /*Handle exception*/ }

donde se añade al entorno gráfico una nueva "font" que, en concreto, es de tipo "trueType" y se lee de un fichero (puede ser de otro tipo y en general leerse de cualquier "Stream" -véase documentación de Font.createFont-)

Quiero hacer un GUI de calculadora que pueda cambiar entre estándar y científica. ¿Cómo lo hago?

La manera más razonable puede ser agrupar en un par de paneles los botones que deben aparecer y desaparecer en cada caso para proceder a quitar y poner dichos paneles cuando se seleccione un modo u otro.

La siguiente imagen muestra una estructura sencilla de ejemplo: el "frame" lleva un "menuBar" donde se encuentran las dos opciones de paso de un modo a otro. Además hay un panel ("contenedorComun") para los botones que no varian entre ambos modos (componentes no visibles en la imagen) y un contenedor para intercambiar botoneras ("contenedorParaIntercambios"). Inicialmente este contenedor lleva dentro el panel de la calculadora estandar, pero se podrá intercambiar con el contenedor de la botonera cientifica que está "aparcado" en la sección "Other Components".

El modo de hacer el intercambio es extremadamente sencillo: basta con asociar a cada opción de menú su acción correspondiente como se ve en la siguiente imagen. No es otra cosa que sacar todo lo que haya en el panel (la botonera actual) y meter la botonera seleccionada. Una vez hecho esto terminamos con un "pack()" que le dice al "layoutManager" que haga su labor (que "empaquete" convenientemente el contenido)

(nota.- en sentido estricto el panel "contenedorParaIntercambios" es innecesario, pero se ha puesto por clarificar el ejemplo.)

Estoy dibujando histogramas en un JPanel... ¿Cómo puedo centrar el texto de una etiqueta?

Para esto hay que manejar la "métrica" de la fuente de texto que se usa en cada momento. La métrica de una fuente tiene que ver con una serie de conceptos medibles. En el método paint(Graphics g) se puede acceder a la fuente a través g.getFont() / g.setFont(), y la métrica se obtiene mediante g.getFontMetrix().

Es sencillo conocer la anchura de una String con la metrica activa en un momento dado: simplemente basta con usar g.getFontMetrics.stringWidth("Texto a dibujar"), que nos da el número de pixels que ocupará. El siguiente ejemplo muestra una String centrada en un punto (200,100) -con la coordenada Y en su línea base- y unas líneas cruzadas en dicho punto para comprobar que "funciona" correctamente.