1 Swing¶
Introducción¶
Java Swing es un conjunto de bibliotecas de interfaz gráfica de usuario que forman parte de la plataforma Java Foundation Classes (JFC). Introducido por primera vez en la versión 1.2 de Java, Swing proporciona una rica colección de componentes gráficos que permiten a los desarrolladores crear interfaces de usuario sofisticadas y altamente personalizables para aplicaciones Java.
Al usar Swing, podemos encontrar una serie de ventajas:
- Personalización: Uno de los puntos fuertes de Swing es su capacidad para ser altamente personalizable. A diferencia de AWT, la biblioteca de GUI anterior en Java, Swing es una biblioteca de componentes ligeros, lo que significa que no depende directamente del sistema operativo subyacente para representar sus componentes. Esto permite que los componentes de Swing sean más flexibles y portables. Por ejemplo, es posible cambiar la apariencia de los componentes (look-and-feel) para que se asemejen a diferentes sistemas operativos o para crear un look-and-feel completamente personalizado.
- Independencia de la plataforma: Debido a que Swing es una biblioteca pura de Java, es completamente independiente de la plataforma. Las aplicaciones de Swing se comportan de la misma manera en cualquier sistema operativo que soporte Java, como Windows, macOS y Linux, lo que facilita la creación de aplicaciones multiplataforma.
- Modelo de eventos: Swing utiliza un modelo de eventos robusto que permite gestionar interacciones del usuario de manera eficiente. Los eventos en Swing se basan en la interfaz
ActionListener
y otras interfaces relacionadas que permiten a los desarrolladores definir cómo las aplicaciones deben responder a acciones del usuario como clics de botón, movimientos de ratón y teclas presionadas.
Un aspecto a considerar es que, debido a su flexibilidad y riqueza de características, las aplicaciones de Swing pueden ser más pesadas en términos de uso de memoria y CPU en comparación con aplicaciones desarrolladas con bibliotecas de GUI más ligeras o específicas de la plataforma. Sin embargo, con un manejo adecuado y técnicas de optimización, es posible crear aplicaciones Swing con buen desempeño.
Con la introducción de JavaFX, una biblioteca más moderna y rica para la construcción de interfaces de usuario, Swing ha pasado a un segundo plano en el desarrollo de nuevas aplicaciones Java GUI. JavaFX ofrece una mejor integración multimedia, gráficos acelerados por hardware y una sintaxis más moderna mediante FXML para definir interfaces de usuario.
Sin embargo, Swing sigue siendo ampliamente utilizado, especialmente en aplicaciones empresariales existentes que requieren mantenimiento y en entornos donde la migración a JavaFX no es práctica. Además, muchos desarrolladores todavía aprecian la robustez y la madurez de Swing.
Swing sigue el patrón Modelo-Vista-Controlador, aunque no lo implemente estrictamente, ciertos componentes es´tan diseñados con una separación entre el modelo y la vista.
Patrón MVC¶
El patrón de diseño Modelo-Vista-Controlador (MVC) es una arquitectura ampliamente utilizada en el desarrollo de aplicaciones que separa la lógica de la aplicación en tres componentes interrelacionados: el Modelo, la Vista y el Controlador. Este patrón ayuda a organizar el código de una manera que promueve la reutilización, la escalabilidad y el mantenimiento.
El Modelo es la parte de la aplicación que maneja la lógica de negocio y los datos subyacentes. Es responsable de gestionar la información y las reglas de negocio de la aplicación. En el contexto de una base de datos, el Modelo también es responsable de interactuar con ella, incluyendo operaciones de consulta y actualización. Los principales aspectos del Modelo incluyen:
- Gestión de Datos: Almacena los datos de la aplicación y garantiza su consistencia.
- Reglas de Negocio: Implementa la lógica de negocio que define cómo se manejan y procesan los datos.
- Notificación de Cambios: Proporciona mecanismos para notificar a la Vista y al Controlador sobre los cambios en los datos, a menudo mediante el uso de patrones de diseño como Observer o eventos.
La Vista es la representación visual de los datos del Modelo. Es responsable de mostrar la información al usuario y capturar la entrada del usuario, pero no contiene lógica de negocio. La Vista es lo que el usuario ve e interactúa directamente. Los principales aspectos de la Vista incluyen:
- Renderización de Datos: Muestra los datos del Modelo de una manera adecuada para el usuario.
- Captura de Eventos de Usuario: Recoge las interacciones del usuario, como clics de botón y entradas de teclado.
- Actualización Dinámica: Cambia dinámicamente en respuesta a las actualizaciones del Modelo para reflejar el estado actual de los datos.
El Controlador actúa como intermediario entre la Vista y el Modelo. Recibe la entrada del usuario a través de la Vista, procesa esa entrada (a menudo invocando métodos del Modelo), y luego devuelve los resultados a la Vista. Los principales aspectos del Controlador incluyen:
- Gestión de la Entrada del Usuario: Interpreta las acciones del usuario y las traduce en operaciones en el Modelo.
- Actualización del Modelo: Modifica el estado del Modelo en respuesta a las acciones del usuario.
- Actualización de la Vista: Ordena a la Vista que se actualice cuando los datos en el Modelo cambian.
La interacción entre los componentes es sencilla. En primer lugar, el usuario interactúa con la vista realizando una acción (por ejemplo, presionando un botón). Posteriormente, la vista informa al controlador, y éste a su vez se lo comunica al modelo. El modelo realiza la acción pertinente en la base de datos (o en la lógica del negocio), devolviéndola así al controlador el resultado de la operación, y éste a su vez se lo retorna a la vista para actualizar el resultado al usuario.
El uso de este patrón de diseño tiene ciertas ventajas:
- Separación de Preocupaciones: Divide la aplicación en componentes independientes, lo que facilita el mantenimiento y la escalabilidad.
- Reutilización de Código: Los componentes del Modelo pueden reutilizarse en diferentes partes de la aplicación o incluso en diferentes aplicaciones.
- Facilidad de Pruebas: Permite probar cada componente de manera aislada, mejorando la capacidad de realizar pruebas unitarias y de integración.
- Desarrollo Colaborativo: Permite que diferentes desarrolladores trabajen en la Vista, el Modelo y el Controlador simultáneamente sin interferir en el trabajo de los demás.
Proyecto MVC¶
En este proyecto, se va a desarrollar una aplicación, haciendo uso del patrón de diseño Modelo-Vista-Controlador. En primer lugar, se crea el modelo con la lógica de negocio.
public class UserModel {
private final List<String> users = List.of("Ana", "Sofía", "Marcus", "Andres");
public List<String> getUsers(){
return users;
}
public String getUserById(String name){
return users.stream().filter(x -> x.equals(name)).findFirst().orElse("No existe");
}
}
Una vez creado el modelo, se crea la vista con la que se va a trabajar. En esta vista se va a crear un botón y un label con el nombre de usuario:
public class UserView {
private final Frame frame;
private final Button button;
private final Label label;
public UserView(){
frame = new Frame("MVC");
frame.setSize(300, 200);
frame.setLayout(new FlowLayout());
label = new Label("");
button = new Button("Click me!");
frame.add(label);
frame.add(button);
}
public void show(){
frame.setVisible(true);
}
public void setUsername(String name){
label.setText(name);
}
public void onClickButton(ActionListener listener){
button.addActionListener(listener);
}
}
Por último, creamos el controlador, inyectándole tanto la vista como el modelo:
public class UserController {
private final UserModel model;
private final UserView view;
public UserController(UserModel model, UserView view) {
this.model = model;
this.view = view;
view.onClickButton(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateUsername();
}
});
}
private void updateUsername() {
String username = model.getUserById("Ana");
view.setUsername(username);
}
}
Otra forma de hacerlo, es inyectar el controlador en la vista, y desde ahí realizar las interacciones.
En nuestro Main
, creamos instancias de nuestros componentes: