ProductoVista es un JFrame
Ya conocemos la herencia. Ahora vamos a usarla con una clase real de la biblioteca de Java. Nuestra clase ProductoVista será una especialización de JFrame.
import javax.swing.JFrame; public class ProductoVista extends JFrame { }
ProductoVista,
¿podrá usar métodos propios de JFrame?
ProductoVista
también puede utilizar los comportamientos que recibe de la jerarquía de JFrame.
La primera ventana… casi invisible
En Main creamos un objeto de nuestra clase y después le pedimos que se muestre.
public class Main { public static void main(String[] args) { ProductoVista v = new ProductoVista(); v.setVisible(true); } }
El constructor empieza a darle forma
Podemos aprovechar el constructor de ProductoVista para configurar
las características iniciales de cada ventana que creemos.
public ProductoVista() { setTitle("Gestión de productos"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
Una alternativa a setSize() es:
setBounds(100, 100, 800, 600);
| Setter | ¿Qué cambia? |
|---|---|
setTitle(...) | El texto de la barra superior. |
setSize(w,h) | El ancho y el alto. |
setBounds(x,y,w,h) | Posición y dimensiones a la vez. |
setDefaultCloseOperation(...) | Qué ocurre cuando se presiona ×. |
Las constantes de cierre
¿Por qué setBackground() parece no funcionar?
setBackground(Color.BLUE);
Podemos cambiar el color de fondo del JFrame, pero en la zona útil de la
ventana hay otro contenedor por delante: el content pane.
JFrame se organiza a través de su
content pane. Más adelante vamos a reemplazarlo por nuestro propio
JPanel panelPrincipal.
Experimento opcional
getContentPane().setBackground(Color.BLUE);
Ahora sí debería observarse el color en la zona interior, mientras todavía no agreguemos otros componentes que la cubran.
Agregar un JLabel
La vista va a necesitar componentes. Si un componente forma parte del estado de la vista, podemos declararlo como atributo privado.
private JLabel lblTitulo; public ProductoVista() { setTitle("Gestión de productos"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); lblTitulo = new JLabel("PRODUCTOS"); add(lblTitulo); }
JLabel, pruebe su alineación y modifique su fuente.
Ejecute después de cada cambio.
Los layouts organizan los componentes
Cada contenedor trabaja con un LayoutManager a la vez. Ese layout decide cómo se distribuyen los componentes que están directamente dentro de ese contenedor.
Algunos layouts que vamos a combinar
- BorderLayout: NORTH, SOUTH, EAST, WEST y CENTER.
- GridLayout: organiza componentes en filas y columnas de igual tamaño.
- FlowLayout: coloca los componentes uno junto a otro siguiendo un flujo.
GridLayout
FlowLayout
Dibujemos la ventana que queremos
Antes de escribir más código, hacemos un boceto. Nuestra vista de productos tendrá:
- Un título centrado.
- Cuatro datos: Código, Nombre, Precio y Stock.
- Un formulario distribuido en una grilla de 2 filas × 4 columnas.
- Tres botones: Aceptar, Eliminar y Cancelar.
- Una tabla que ocupe el espacio restante y muestre el listado de productos.
JLabel
Un sistema de contenedores dentro de contenedores
panelFormulario · BorderLayout
JScrollPane listado
lblTitulo
panelCampos · GridLayout(2,4)
panelBotones · FlowLayout
Mapa de responsabilidades visuales
| Contenedor | Layout | Qué contiene |
|---|---|---|
panelPrincipal | BorderLayout | Formulario arriba y listado en el centro. |
panelFormulario | BorderLayout | Título, campos y botones. |
panelCampos | GridLayout(2,4) | 4 etiquetas y 4 campos. |
panelBotones | FlowLayout | Aceptar, Eliminar y Cancelar. |
JScrollPane | gestión propia | La tabla de productos. |
El método privado crearVentana()
El constructor no debería convertirse en una larga lista de creación y configuración de componentes. Podemos delegar esa tarea a un método privado.
public ProductoVista() { crearVentana(); } private void crearVentana() { // 1. Configurar el JFrame // 2. Crear los paneles // 3. Crear los componentes // 4. Configurar componentes // 5. Agregar cada componente al contenedor correcto // 6. Definir el panel principal como content pane }
ProductoVista. Desde afuera necesitamos usar la vista, no indicarle paso a paso cómo construirse.
Una primera versión completa de ProductoVista
Esta versión construye toda la interfaz, pero todavía no define qué hacen los botones. Esa responsabilidad se incorporará más adelante.
import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.table.DefaultTableModel; public class ProductoVista extends JFrame { // Componentes que forman parte del estado de la vista private JLabel lblTitulo; private JLabel lblCodigo; private JLabel lblNombre; private JLabel lblPrecio; private JLabel lblStock; private JTextField txtCodigo; private JTextField txtNombre; private JTextField txtPrecio; private JTextField txtStock; private JButton btnAceptar; private JButton btnEliminar; private JButton btnCancelar; private JTable tablaProductos; public ProductoVista() { crearVentana(); } private void crearVentana() { // ------------------------------------------------- // 1. Configuración general de la ventana // ------------------------------------------------- setTitle("Gestión de productos"); setSize(850, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); // ------------------------------------------------- // 2. Panel principal // ------------------------------------------------- JPanel panelPrincipal = new JPanel(new BorderLayout(10, 10)); panelPrincipal.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); // ------------------------------------------------- // 3. Panel del formulario // ------------------------------------------------- JPanel panelFormulario = new JPanel(new BorderLayout(10, 10)); // Título lblTitulo = new JLabel("PRODUCTOS"); lblTitulo.setHorizontalAlignment(SwingConstants.CENTER); lblTitulo.setFont(new Font("SansSerif", Font.BOLD, 22)); panelFormulario.add(lblTitulo, BorderLayout.NORTH); // ------------------------------------------------- // 4. Panel de campos: 2 filas x 4 columnas // ------------------------------------------------- JPanel panelCampos = new JPanel(new GridLayout(2, 4, 10, 10)); lblCodigo = new JLabel("Código:"); lblNombre = new JLabel("Nombre:"); lblPrecio = new JLabel("Precio:"); lblStock = new JLabel("Stock:"); txtCodigo = new JTextField(); txtNombre = new JTextField(); txtPrecio = new JTextField(); txtStock = new JTextField(); panelCampos.add(lblCodigo); panelCampos.add(txtCodigo); panelCampos.add(lblNombre); panelCampos.add(txtNombre); panelCampos.add(lblPrecio); panelCampos.add(txtPrecio); panelCampos.add(lblStock); panelCampos.add(txtStock); panelFormulario.add(panelCampos, BorderLayout.CENTER); // ------------------------------------------------- // 5. Panel de botones // ------------------------------------------------- JPanel panelBotones = new JPanel(new FlowLayout(FlowLayout.CENTER)); btnAceptar = new JButton("Aceptar"); btnEliminar = new JButton("Eliminar"); btnCancelar = new JButton("Cancelar"); panelBotones.add(btnAceptar); panelBotones.add(btnEliminar); panelBotones.add(btnCancelar); panelFormulario.add(panelBotones, BorderLayout.SOUTH); // ------------------------------------------------- // 6. Tabla y JScrollPane // ------------------------------------------------- String[] columnas = {"Código", "Nombre", "Precio", "Stock"}; DefaultTableModel modeloTabla = new DefaultTableModel(columnas, 0); tablaProductos = new JTable(modeloTabla); JScrollPane scrollListado = new JScrollPane(tablaProductos); // ------------------------------------------------- // 7. Componer el panel principal // ------------------------------------------------- panelPrincipal.add(panelFormulario, BorderLayout.NORTH); panelPrincipal.add(scrollListado, BorderLayout.CENTER); // Nuestro JPanel pasa a ser el content pane del JFrame setContentPane(panelPrincipal); } }
public class Main { public static void main(String[] args) { ProductoVista v = new ProductoVista(); v.setVisible(true); } }
Mapa mental de la construcción
- Una vista Swing sigue siendo una clase y sus controles siguen siendo objetos.
ProductoVistapuede usar métodos heredados deJFrame.- Los setters cambian el estado/configuración de la ventana.
- Los componentes deben pertenecer a un contenedor para aparecer.
- Cada contenedor usa un layout para organizar a sus hijos directos.
- Una interfaz compleja puede construirse combinando varios contenedores simples.
crearVentana()encapsula el trabajo interno de construcción de la vista.