====== Anexo: IntelliJ IDEA ======
En este apartado se explican diferentes cuestiones y formas de trabajo con el IDE IntelliJ:
===== Versión del JDK =====
* File -> Project Structure -> Project
En IntelliJ, como en cualquier otro IDE, podemos indicar qué JDK vamos a utilizar para desarrollar nuestra aplicación. Para ello debo añadir la ruta del directorio del JDK instalado en mi sistema.
Además IntelliJ me permite indicar la versión en la que quiero compilar el código de mi aplicación. Por ejemplo, si tengo el JDK 17 y quiero que mi aplicación sea compatible con Java8, debo reducir en valor de **"Language Level"** a Java 8.
{{ :anexos:language-level-intellij.png?500 |}}
Siempre deberé indicar una versión igual o inferior al JDK que esté utilizando.
===== Diseñador de GUIs: UI Designer =====
Es la herramienta para diseñar interfaces gráficas de usuario (GUI's). Utiliza las librerías gráficas de Swing, que son unas librerías nativas existentes en la API de Java.
{{ :anexos:uidesigner.png?500 |}}
> Vista del diseñador Swing UI Designer de IntelliJ
====Crear GUI Form====
Para crear utilizar el Diseñador de IntelliJ para crear una interfaz gráfica:
* Click derecho sobre el //package// donde quiera crear la GUI
* Selecciono //New -> Swing UI Designer -> GUI Form//
* Dar nombre a la clase y seleccionar un //Layout//
Se crean dos elementos, un archivo //form// que contiene el aspecto de la ventana y una clase de java, que contiene los atributos de la clase.
//UI Designer// nos permite diseñar el contenido de un elemento ''JPanel'' principal. Para poder visualizarlo en una ventana necesito añadirlo a un objeto ''JFrame''. El primer requisito es asegurarme que el elemento ''JPanel'' principal de mi GUI es un atributo de la clase. Basta con asegurarse de que el JPanel principal tiene nombre, como se ve en la siguiente imagen:
{{ :anexos:mainjpanel-name.png?600 |}}
De este modo en la clase vinculada a ese //form// aparecerá el objeto JPanel como un atributo.
import javax.swing.*;
public class Vista {
private JPanel panel1; //Atributo JPanel que he diseñado
private JTextField txtTiempo;
private JButton btnIniciar;
IntelliJ nos permite crear un método //main// para iniciar nuestra interfaz gráfica de forma sencilla. Basta con hacer:
* click derecho en la clase vinculada a mi //form//
* Generate -> Form main()
IntelliJ nos genera un método ''main()'' en el que se crea un JFrame que contiene al panel que hemos diseñado:
public class Vista {
private JPanel panel1;
private JTextField txtTiempo;
private JButton btnIniciar;
public static void main(String[] args) {
JFrame frame = new JFrame("Vista");
frame.setContentPane(new Vista().panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Ahora puede ejecutar esta clase y nos desplegará la ventana.
Como consejo, siempre será más fácil crear un constructor para la clase que corresponde a la ventana. El código anterior quedaría así:
public class Vista {
private JPanel panel1;
private JTextField txtTiempo;
private JButton btnIniciar;
public Vista(){
JFrame frame = new JFrame("Vista");
//En la siguiente linea me aseguro de no llamar al constructor new Vista().
frame.setContentPane(panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Vista();
}
}
==== Listeners====
Para añadir manejadores de eventos a los componentes de mi interfaz gráfica:
* click derecho sobre el componente -> Create Listener
* indico el tipo de listener que deseo crear (Action listener si es un botón)
* selecciono los métodos del listener y acepto
Y acto seguido se creará un clase anónima para implementar el listener:
. . .
btnIniciar.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//Tareas a realizar
}
});
. . .
====Separación de GUI y Listener====
Es útil separar las clases que contienen componentes gráficos de las clases que gestionan los eventos sobre esos componentes. Cuando consigo que las clases tengan funcionalidades independientes, estoy //desacoplando// las clases de mi programa, basándome en el [[https://es.wikipedia.org/wiki/Principio_de_responsabilidad_%C3%BAnica|principio de responsabilidad única]], el cual forma parte de los tan importantes principios [[https://es.wikipedia.org/wiki/SOLID|SOLID]] para el diseño de programas orientados a objetos.
Para ello, en lugar de crear los listeners en la clase vinculada al GUI Form, lo voy a hacer en una clase distinta.
**1: ** En la clase Java vinculada a mi GUI, añado un constructor para crear la ventana. Puedo aprovechar el código generado por mi método main (Generate -> Form main() ).
public class Vista {
private JPanel panel1;
JTextField txtTiempo;
JButton btnIniciar;
public Vista() {
JFrame frame = new JFrame("Vista");
//Eliminar la llamada recursiva al contructor "new Vista().panel1"
frame.setContentPane(panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Debo recordar dos cosas importantes:
* Me facilita el acceso a los componentes de la GUI, eliminar el modificador de visibilidad ''private'' de los atributos con los que quiera interactuar cuando capture //eventos//.
* En la linea //frame.setContentPane(new Vista().panel1)// generada por el //Form main()//, debo eliminar la llamada recursiva al constructor de la clase ( Vista() ).
**2: ** Crear una clase que ejerza de listener. Una clase puede implementar todas las ''interfaces'' que queramos por lo que una sola clase puede ser un listener de diferentes tipos. En el siguiente caso la clase es un listener de tipo ''ActionListener'':
public class Controlador implements ActionListener {
private Vista vista;
public Controlador(Vista vista){
this.vista = vista;
/* Al crear un objeto de la clase Controlador,
vincularé esta propia clase con los componentes de la GUI
sobre los que quiero capturar eventos de este tipo */
vincularManejadoresAComponentes(this);
}
private void vincularManejadoresAComponentes(Controlador listener) {
vista.btnIniciar.addActionListener(listener);
}
@Override
public void actionPerformed(ActionEvent e) {
// Tareas a realizar cuando se capture el evento
. . .
}
}
Si en el método ''actionPerformed()'' necesito capturar eventos originados en diferentes componentes (p.e. tengo varios botones) puedo usar los métodos ''e.getSource()'' ó ''e.getActionCommand()'' del objeto ''ActionEvent'' que recibe el método como parámetro para saber dónde se produjeron.
Por último creo un método ''main()'' en alguna clase para iniciar mi aplicación en una tercera clase:
public class Principal {
public static void main(String[] args) {
Vista vista = new Vista();
Controlador controlador = new Controlador(vista);
}
}
===== Archivos JAR=====
Los ficheros Jar (Java Archive) son archivos comprimidos en los que podemos empaquetar clases (.class) y otros recursos. En IntelliJ los JAR se denominan //artifacts//.
==== Utilizar librerías externas====
Para utilizar librerías en formato JAR en mis proyectos de IntelliJ, es útil almacenarlas primero en un directorio dentro de mi proyecto. Para ello creo un directorio en la estructura de mi proyecto:
{{ :anexos:vista-proyecto.png?300 |}}
* Click derecho sobre el proyecto -> new -> directory
* Copiar y pegar los archivos JAR que necesite en el directorio creado
A continuación:
* File -> Project Structure -> Libraries -> boton (+) -> Java Library
* Busco en el explorador de archivos que se abre, la ruta del directorio que he creado en mi proyecto. Lo selecciono, y aceptar todo.
{{ :anexos:libs-intellij.png?500 |}}
Ahora puedo utilizar las clases contenidas en esos paquetes JAR.
====Crear libreria de clases====
Desde la sección ''Project Structure'' dentro del menu ''File'', nos situamos sobre ''Artifacts''.
{{ :anexos:newartifact-intellij.png?direct&400 |}}
Ahí pulsamos sobre el boton (+) para crear un nuevo //artifact Jar// vacio.
En el siguiente cuadro de dialogo, podemos indicar un nombre para el fichero , indicar si queremos que se cree cuando hagamos un //Build// del proyecto, y en la sección inferior, si queremos que nuestras librería de clases esté organizada en directorios (del mismo modo que los //packages//), podemos pulsar sobre el botón crear directorio:
{{ :anexos:createdirectory-jar.png?direct&400 |}}
y después pulsando sobre el símbolo (+) debemos seleccionar los archivos //.class// que queremos que incluya:
{{ :anexos:newartifact2-intellij.png?direct&800 |}}
Ahí en el selector de ficheros, buscamos los archivo **.class** que queramos incluir en nuestro Jar. Una vez indicamos pulsamos sobre aceptar finalizando la creación del //artifact//.
Para generarlo el fichero Jar iremos al menú Build de IntelliJ, y pulsaremos sobre ''build project'' en caso de que a la hora de configurar el artifact marcaramos el checkbox que indicamos en esta sección. En caso contrario, pulsamos sobre ''build artifacts''.
{{ :anexos:build-artifacts-intellij.png?direct&400 |}}
==== Crear JAR ejecutable ====
Una vez que tengo mi aplicación con GUI diseñada, puedo exportarla en un fichero ejecutable, que se podrá arrancar en cualquier equipo que tenga la versión de Java con la que se diseño, o una posterior.
Para exportar mi aplicación como JAR ejecutable haré lo siguiente:
* //Menú File -> Project Structure//
* //Artifacts -> Add Jar -> From modules with dependencies//
{{ :anexos:jar-artifact.png?400 |}}
* //Seleccionar la clase que contiene el método ''main()'' y aceptar//
* En la última ventana se indica donde se creará el JAR. Aceptar
{{ :anexos:create-jar-artifact.png?300 |}}
Una vez que tengo la configuración de //JAR Artifact//, tan solo me queda crearlo:
* Menú Build -> Build Artifacts...
El fichero JAR se creará en la ruta especificada.
{{ :anexos:out-artifact.png?300 |}}
===== GUI Dinámica =====
Se conoce como GUI dinámica a una interfaz gráfica que permite crear o eliminar componentes gráficos en una misma ventana en tiempo de ejecución, en lugar de tenerlos en la ventana desde el inicio.
La idea es diferente a construir nuevas ventanas (JFrame o JDialog) en tiempo de ejecución. Se busca añadir o eliminar componentes a una misma ventana.
Podemos añadir componentes existentes en la API de Swing, pero en ciertas ocasiones puede que nos interese diseñar componentes personalizados que cumplan una finalidad concreta.
====Crear componentes====
Para crear componentes personalizados que podamos añadir a otras ventanas, podemos hacerlos de dos formas:
* Diseñando el componente directamente mediante código Java
* Diseñando el componente con el //UI Designer// de IntelliJ
Para diseñarlo con el //UI Designer//, debemos tener en cuenta que la clase que vinculada al //GUI Form// que crea IntellJ, no es un componentes gráfico de Java en sí, es decir, no es una clase que extienda de JComponent, u otro componente gráfico.
Pero como hemos visto, el diseñador basa el diseño de las GUI en un objeto ''JPanel'' principal al que sí puedo acceder, y sí es un componente gráfico de Java. Si quiero utilizar mi clase para añadirla a algún otro panel de otra ventana, puedo crear un método ''getter()'' que me permita acceder al ''JPanel'' que he diseñado:
public class Vista {
private JPanel panel1;
private JTextField txtTiempo;
private JButton btnIniciar;
public void JPanel getPanel1(){
return panel1;
}
. . .
}
==== Añadir componentes de forma dinámica ====
=== Crear contenedor ===
Para emplazar de forma dinámica estos nuevos componentes debo tener otro //GUI Form// que contenga un panel donde desee añadir dinámicamente, los nuevos componentes diseñados anteriormente.
Para ello el ''JPanel'' que escoja para alojar dinámicamente otros "paneles" debe tener un //Layout// que me permita que se ordenen correctamente al añadirlos (p.e. verticalmente). ''BoxLayout'' y [[https://tips4java.wordpress.com/2008/11/06/wrap-layout/|WrapLayout]] son //layouts// que se adaptan a este propósito.
IntelliJ me permite personalizar la creación de los objetos de mi GUI. Para ello tan solo debo marcar el checkbox que dice "Custom Create" en las propiedades de los componentes que aparece a la izquierda en el //UI Designer//. Al pulsar sobre ese checkbox me aparece un método en la clase vinculada, donde indicaré el código de creación de los objetos:
{{ :anexos:uidesigner-customcreate.png?300 |}}
private void createUIComponents() {
// TODO: place custom component creation code here
panelDinamico = new JPanel();
BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS)
panelDinamico.setLayout(layout);
}
=== Añadir y eliminar componentes ===
Una vez que tengo el panel contenedor, ahora tan solo debo crear componentes y añadirlos, por ejemplo al pulsar un botón.
. . .
@Override
public void actionPerformed(ActionEvent e) {
JPanel panelComponente = new MiClase().getPanel1()
panelDinamico.add(panelComponente);
panelDinamico.revalidate();
//Y para eliminarlo
panelDinamico.remove(panelComponente);
panelDinamico.repaint();
panelDinamico.revalidate();
}
. . .
{{ vimeo>770531646?medium }}
> Creación de GUI dinámica
{{ vimeo>772557531?medium }}
> GUI dinámica: Manejar componentes
----
(c) {{date> %Y}} Fernando Valdeón