diff --git a/eventapp/nb-configuration.xml b/eventapp/nb-configuration.xml
new file mode 100644
index 0000000..4005d49
--- /dev/null
+++ b/eventapp/nb-configuration.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ JDK_25
+
+
diff --git a/eventapp/nbactions.xml b/eventapp/nbactions.xml
new file mode 100644
index 0000000..eb1f80d
--- /dev/null
+++ b/eventapp/nbactions.xml
@@ -0,0 +1,55 @@
+
+
+
+ run
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:3.1.0:exec
+
+
+
+ ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}
+
+ com.mycompany.eventapp.Eventapp
+ java
+
+
+
+ debug
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:3.1.0:exec
+
+
+ -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}
+ ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}
+
+ com.mycompany.eventapp.Eventapp
+ java
+ true
+
+
+
+ profile
+
+ jar
+
+
+ process-classes
+ org.codehaus.mojo:exec-maven-plugin:3.1.0:exec
+
+
+
+ ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}
+ com.mycompany.eventapp.Eventapp
+ java
+
+
+
+
diff --git a/eventapp/pom.xml b/eventapp/pom.xml
new file mode 100644
index 0000000..f93867e
--- /dev/null
+++ b/eventapp/pom.xml
@@ -0,0 +1,13 @@
+
+
+ 4.0.0
+ com.mycompany
+ eventapp
+ 1.0-SNAPSHOT
+ jar
+
+ UTF-8
+ 25
+ com.mycompany.eventapp.Eventappa
+
+
\ No newline at end of file
diff --git a/eventapp/src/main/java/com/mycompany/eventapp/Eventapp.java b/eventapp/src/main/java/com/mycompany/eventapp/Eventapp.java
new file mode 100644
index 0000000..b4fb245
--- /dev/null
+++ b/eventapp/src/main/java/com/mycompany/eventapp/Eventapp.java
@@ -0,0 +1,25 @@
+
+package com.mycompany.eventapp;
+
+import controlador.Controlador;
+import modelo.Modelo;
+import vista.Vista;
+
+import javax.swing.*;
+
+
+
+
+
+public class Eventapp
+ {
+ public static void main(String[] args)
+ {
+ // Buenas prácticas: iniciar Swing en el EDT
+ SwingUtilities.invokeLater(() -> {
+ Modelo modelo = new Modelo();
+ Vista vista = new Vista();
+ new Controlador(modelo, vista).iniciar(); // cableado MVC
+ });
+ }
+ }
diff --git a/eventapp/src/main/java/controlador/Controlador.java b/eventapp/src/main/java/controlador/Controlador.java
new file mode 100644
index 0000000..7111f48
--- /dev/null
+++ b/eventapp/src/main/java/controlador/Controlador.java
@@ -0,0 +1,312 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package controlador;
+
+import modelo.Modelo;
+import vista.DialogoNombre;
+import vista.Vista;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+/**
+ * CONTROLADOR:
+ * - Registra listeners sobre la Vista.
+ * - Llama al Modelo y actualiza la Vista según corresponda.
+ * - Contiene toda la lógica de interacción.
+ */
+public class Controlador implements
+ ActionListener, ItemListener, ChangeListener,
+ KeyListener, MouseListener, MouseMotionListener,
+ WindowListener, ListSelectionListener, PropertyChangeListener {
+
+ private final Modelo modelo;
+ private final Vista vista;
+
+ // Para el área de dibujo
+ private Point ultimoPunto = null;
+
+ public Controlador(Modelo modelo, Vista vista) {
+ this.modelo = modelo;
+ this.vista = vista;
+ }
+
+ public void iniciar() {
+ // === Suscripción a eventos de VISTA ===
+
+ // Menú
+ vista.getMiNuevo().addActionListener(this);
+ vista.getMiSalir().addActionListener(this);
+
+ // Botones
+ vista.getBtnMas().addActionListener(this);
+ vista.getBtnMenos().addActionListener(this);
+ vista.getBtnAdd().addActionListener(this);
+ vista.getBtnRemove().addActionListener(this);
+ vista.getBtnTareaLarga().addActionListener(this);
+
+ // ItemListener (checkbox y combobox)
+ vista.getChkHabilitarTexto().addItemListener(this);
+ vista.getCboOpciones().addItemListener(this);
+
+ // Slider (ChangeListener)
+ vista.getSldValor().addChangeListener(this);
+
+ // DocumentListener para cambios en texto de nombre
+ vista.addNombreDocumentListener(new DocumentListener() {
+ @Override public void insertUpdate(DocumentEvent e) { actualizarNombreDesdeVista(); }
+ @Override public void removeUpdate(DocumentEvent e) { actualizarNombreDesdeVista(); }
+ @Override public void changedUpdate(DocumentEvent e) { actualizarNombreDesdeVista(); }
+ });
+
+ // Teclado sobre el canvas
+ vista.getCanvas().setFocusable(true);
+ vista.getCanvas().addKeyListener(this);
+
+ // Ratón sobre el canvas
+ vista.getCanvas().addMouseListener(this);
+ vista.getCanvas().addMouseMotionListener(this);
+
+ // Selección en la lista
+ vista.getLstElementos().addListSelectionListener(this);
+
+ // Cambio de pestañas
+ vista.getTabs().addChangeListener(this);
+
+ // WindowListener
+ vista.addWindowListener(this);
+
+ // === Suscripción a cambios del MODELO ===
+ modelo.addPropertyChangeListener(this);
+
+ // Pinta estado inicial
+ vista.getLblContador().setText(String.valueOf(modelo.getContador()));
+ vista.getLblHora().setText(modelo.getHora());
+ vista.getListModel().clear();
+ modelo.getElementos().forEach(vista.getListModel()::addElement);
+
+ // Mostrar la ventana al final
+ vista.setVisible(true);
+ }
+
+ // ================== ActionListener ==================
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Object src = e.getSource();
+
+ if (src == vista.getBtnMas()) {
+ modelo.incrementar();
+ vista.getLblEstado().setText("Se incrementó el contador.");
+ } else if (src == vista.getBtnMenos()) {
+ modelo.decrementar();
+ vista.getLblEstado().setText("Se decrementó el contador.");
+ } else if (src == vista.getBtnAdd()) {
+ String txt = vista.getTxtNuevo().getText().trim();
+ if (!txt.isEmpty()) {
+ modelo.addElemento(txt);
+ vista.getTxtNuevo().setText("");
+ vista.getLblEstado().setText("Elemento añadido.");
+ }
+ } else if (src == vista.getBtnRemove()) {
+ int idx = vista.getLstElementos().getSelectedIndex();
+ modelo.removeElemento(idx);
+ vista.getLblEstado().setText("Elemento eliminado (si había selección).");
+ } else if (src == vista.getMiNuevo()) {
+ // Abrimos un diálogo modal controlado desde el controlador
+ DialogoNombre dlg = new DialogoNombre(vista);
+ // Listeners del diálogo
+ dlg.getBtnOk().addActionListener(ev -> {
+ modelo.setNombre(dlg.getTxt().getText());
+ dlg.dispose();
+ });
+ dlg.getBtnCancel().addActionListener(ev -> dlg.dispose());
+ dlg.setVisible(true);
+ } else if (src == vista.getMiSalir()) {
+ solicitarSalida();
+ } else if (src == vista.getBtnTareaLarga()) {
+ ejecutarTareaLarga();
+ }
+ }
+
+ // ================== ItemListener ==================
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ Object src = e.getSource();
+
+ if (src == vista.getChkHabilitarTexto()) {
+ boolean habilitar = vista.getChkHabilitarTexto().isSelected();
+ vista.getTxtNombre().setEnabled(habilitar);
+ vista.getLblEstado().setText(habilitar ? "Texto habilitado." : "Texto deshabilitado.");
+ } else if (src == vista.getCboOpciones() && e.getStateChange() == ItemEvent.SELECTED) {
+ String color = (String) vista.getCboOpciones().getSelectedItem();
+ vista.getLblEstado().setText("Color favorito: " + color);
+ }
+ }
+
+ // ================== ChangeListener ==================
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ Object src = e.getSource();
+
+ if (src == vista.getSldValor()) {
+ vista.getLblEstado().setText("Slider: " + vista.getSldValor().getValue());
+ } else if (src == vista.getTabs()) {
+ vista.getLblEstado().setText("Pestaña: " + vista.getTabs().getTitleAt(vista.getTabs().getSelectedIndex()));
+ // Dar foco al canvas si entramos a su pestaña para poder usar teclas
+ if (vista.getTabs().getSelectedComponent() == vista.getCanvas().getParent()) {
+ vista.getCanvas().requestFocusInWindow();
+ }
+ }
+ }
+
+ // ================== DocumentListener helper ==================
+ private void actualizarNombreDesdeVista() {
+ if (vista.getTxtNombre().isEnabled()) {
+ // Actualizamos solo la VISTA (placeholder en estado), el modelo se cambia con el diálogo o podrías sincronizar aquí
+ vista.getLblEstado().setText("Nombre (vista) editándose: " + vista.getTxtNombre().getText());
+ }
+ }
+
+ // ================== KeyListener (canvas) ==================
+ @Override public void keyTyped(KeyEvent e) {}
+ @Override public void keyPressed(KeyEvent e) {
+ // Cambiar color de fondo del canvas con teclas numéricas
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_1 -> vista.getCanvas().setBackground(Color.PINK);
+ case KeyEvent.VK_2 -> vista.getCanvas().setBackground(Color.LIGHT_GRAY);
+ case KeyEvent.VK_3 -> vista.getCanvas().setBackground(new Color(220, 240, 255));
+ }
+ vista.getLblEstado().setText("Tecla: " + KeyEvent.getKeyText(e.getKeyCode()));
+ }
+ @Override public void keyReleased(KeyEvent e) {}
+
+ // ================== MouseListener / MouseMotionListener (canvas) ==================
+ @Override public void mouseClicked(MouseEvent e) {
+ vista.getLblEstado().setText("Clic en: " + e.getPoint());
+ }
+ @Override public void mousePressed(MouseEvent e) {
+ ultimoPunto = e.getPoint();
+ }
+ @Override public void mouseReleased(MouseEvent e) {
+ ultimoPunto = null;
+ }
+ @Override public void mouseEntered(MouseEvent e) {
+ vista.getCanvas().requestFocusInWindow(); // Para captar teclas
+ }
+ @Override public void mouseExited(MouseEvent e) {}
+
+ @Override public void mouseDragged(MouseEvent e) {
+ // “Dibujar” una línea simple con borde (realmente pintamos un borde temporal usando un icono)
+ if (ultimoPunto != null) {
+ Graphics g = vista.getCanvas().getGraphics();
+ g.setColor(Color.DARK_GRAY);
+ g.drawLine(ultimoPunto.x, ultimoPunto.y, e.getX(), e.getY());
+ ultimoPunto = e.getPoint();
+ }
+ }
+ @Override public void mouseMoved(MouseEvent e) {
+ vista.getLblEstado().setText("Mouse: " + e.getPoint());
+ }
+
+ // ================== WindowListener ==================
+ @Override public void windowOpened(WindowEvent e) {}
+ @Override public void windowClosing(WindowEvent e) { solicitarSalida(); }
+ @Override public void windowClosed(WindowEvent e) {}
+ @Override public void windowIconified(WindowEvent e) {}
+ @Override public void windowDeiconified(WindowEvent e) {}
+ @Override public void windowActivated(WindowEvent e) {}
+ @Override public void windowDeactivated(WindowEvent e) {}
+
+ private void solicitarSalida() {
+ int r = JOptionPane.showConfirmDialog(vista,
+ "¿Desea salir?", "Confirmación",
+ JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+ if (r == JOptionPane.YES_OPTION) {
+ vista.dispose();
+ System.exit(0);
+ }
+ }
+
+ // ================== ListSelectionListener (lista) ==================
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ if (!e.getValueIsAdjusting()) {
+ int idx = vista.getLstElementos().getSelectedIndex();
+ vista.getLblEstado().setText(idx >= 0 ? "Seleccionado índice " + idx : "Sin selección");
+ }
+ }
+
+ // ================== PropertyChangeListener (modelo) ==================
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ switch (evt.getPropertyName()) {
+ case "contador" -> {
+ int valor = (int) evt.getNewValue();
+ vista.getLblContador().setText(String.valueOf(valor));
+ }
+ case "nombre" -> {
+ // Reflejamos el nombre de modelo en la vista (si está habilitado para editar)
+ if (!vista.getTxtNombre().isFocusOwner()) {
+ vista.getTxtNombre().setText((String) evt.getNewValue());
+ }
+ vista.getLblEstado().setText("Nombre (modelo) = " + evt.getNewValue());
+ }
+ case "elementos" -> {
+ vista.getListModel().clear();
+ for (String s : modelo.getElementos()) {
+ vista.getListModel().addElement(s);
+ }
+ }
+ case "hora" -> {
+ vista.getLblHora().setText((String) evt.getNewValue());
+ }
+ }
+ }
+
+ // ================== Ejemplo SwingWorker (tarea larga) ==================
+ private void ejecutarTareaLarga() {
+ vista.getBtnTareaLarga().setEnabled(false);
+ vista.getProgress().setValue(0);
+ vista.getLblEstado().setText("Procesando...");
+
+ SwingWorker worker = new SwingWorker<>() {
+ @Override
+ protected Void doInBackground() throws Exception {
+ // Simulación de trabajo (100 pasos)
+ for (int i = 1; i <= 100; i++) {
+ Thread.sleep(15); // simula carga
+ setProgress(i); // dispara PropertyChange "progress"
+ }
+ return null;
+ }
+
+ @Override
+ protected void process(java.util.List chunks) {
+ // No usamos publish() en este ejemplo, usamos progress
+ }
+
+ @Override
+ protected void done() {
+ vista.getLblEstado().setText("Tarea terminada.");
+ vista.getBtnTareaLarga().setEnabled(true);
+ }
+ };
+
+ // Escucha de progreso
+ worker.addPropertyChangeListener(evt -> {
+ if ("progress".equals(evt.getPropertyName())) {
+ int p = (int) evt.getNewValue();
+ vista.getProgress().setValue(p);
+ }
+ });
+
+ worker.execute();
+ }
+}
+
diff --git a/eventapp/src/main/java/modelo/Modelo.java b/eventapp/src/main/java/modelo/Modelo.java
new file mode 100644
index 0000000..2b0f329
--- /dev/null
+++ b/eventapp/src/main/java/modelo/Modelo.java
@@ -0,0 +1,102 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package modelo;
+
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.Timer;
+
+/**
+ * MODELO:
+ * - Mantiene el estado (contador, nombre, lista, hora).
+ * - Lanza eventos de cambio (PropertyChangeSupport) para notificar a la Vista/Controlador.
+ * - No conoce nada de Swing (salvo el Timer para ejemplo simple).
+ */
+public class Modelo {
+
+ private int contador = 0;
+ private String nombre = "Sin nombre";
+ private final List elementos = new ArrayList<>();
+
+ private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+ private final Timer reloj; // actualiza propiedad "hora"
+
+ private String hora = LocalTime.now().withNano(0).toString();
+
+ public Modelo() {
+ // Reloj que actualiza cada segundo la propiedad "hora"
+ reloj = new Timer(1000, e -> {
+ String old = this.hora;
+ this.hora = LocalTime.now().withNano(0).toString();
+ pcs.firePropertyChange("hora", old, this.hora);
+ });
+ reloj.start();
+
+ // Datos iniciales
+ elementos.add("Elemento A");
+ elementos.add("Elemento B");
+ elementos.add("Elemento C");
+ }
+
+ public int getContador() {
+ return contador;
+ }
+
+ public void incrementar() {
+ int old = contador;
+ contador++;
+ pcs.firePropertyChange("contador", old, contador);
+ }
+
+ public void decrementar() {
+ int old = contador;
+ contador--;
+ pcs.firePropertyChange("contador", old, contador);
+ }
+
+ public String getNombre() {
+ return nombre;
+ }
+
+ public void setNombre(String nombre) {
+ String old = this.nombre;
+ this.nombre = nombre;
+ pcs.firePropertyChange("nombre", old, nombre);
+ }
+
+ public List getElementos() {
+ return new ArrayList<>(elementos);
+ }
+
+ public void addElemento(String txt) {
+ elementos.add(txt);
+ // Notificamos cambio en la lista completa para mantenerlo simple
+ pcs.firePropertyChange("elementos", null, getElementos());
+ }
+
+ public void removeElemento(int index) {
+ if (index >= 0 && index < elementos.size()) {
+ elementos.remove(index);
+ pcs.firePropertyChange("elementos", null, getElementos());
+ }
+ }
+
+ public String getHora() {
+ return hora;
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ pcs.addPropertyChangeListener(l);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ pcs.removePropertyChangeListener(l);
+ }
+}
+
diff --git a/eventapp/src/main/java/vista/DialogoNombre.java b/eventapp/src/main/java/vista/DialogoNombre.java
new file mode 100644
index 0000000..8b45cce
--- /dev/null
+++ b/eventapp/src/main/java/vista/DialogoNombre.java
@@ -0,0 +1,39 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package vista;
+
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Pequeño diálogo modal para demostrar control desde el Controlador.
+ */
+public class DialogoNombre extends JDialog {
+
+ private final JTextField txt = new JTextField(20);
+ private final JButton btnOk = new JButton("Aceptar");
+ private final JButton btnCancel = new JButton("Cancelar");
+
+ public DialogoNombre(JFrame owner) {
+ super(owner, "Cambiar nombre", true); // modal
+ setLayout(new BorderLayout(8,8));
+ JPanel center = new JPanel(new FlowLayout());
+ center.add(new JLabel("Nuevo nombre:"));
+ center.add(txt);
+ add(center, BorderLayout.CENTER);
+ JPanel south = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+ south.add(btnCancel);
+ south.add(btnOk);
+ add(south, BorderLayout.SOUTH);
+ pack();
+ setLocationRelativeTo(owner);
+ }
+
+ public JTextField getTxt() { return txt; }
+ public JButton getBtnOk() { return btnOk; }
+ public JButton getBtnCancel() { return btnCancel; }
+}
+
diff --git a/eventapp/src/main/java/vista/Vista.java b/eventapp/src/main/java/vista/Vista.java
new file mode 100644
index 0000000..c2bb7f4
--- /dev/null
+++ b/eventapp/src/main/java/vista/Vista.java
@@ -0,0 +1,175 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package vista;
+
+
+import javax.swing.*;
+import javax.swing.event.DocumentListener;
+import java.awt.*;
+
+/**
+ * VISTA:
+ * - Solo define y organiza componentes Swing.
+ * - Expone getters para que el Controlador se suscriba a eventos.
+ * - No contiene lógica de negocio.
+ */
+public class Vista extends JFrame {
+
+ // Menú
+ private final JMenuItem miNuevo = new JMenuItem("Nuevo");
+ private final JMenuItem miSalir = new JMenuItem("Salir");
+
+ // Panel principal con pestañas
+ private final JTabbedPane tabs = new JTabbedPane();
+
+ // Pestaña 1: Controles básicos
+ private final JButton btnMas = new JButton("+1");
+ private final JButton btnMenos = new JButton("-1");
+ private final JLabel lblContador = new JLabel("0", SwingConstants.CENTER);
+ private final JCheckBox chkHabilitarTexto = new JCheckBox("Habilitar texto");
+ private final JTextField txtNombre = new JTextField(15);
+ private final JComboBox cboOpciones = new JComboBox<>(new String[]{"Rojo", "Verde", "Azul"});
+ private final JSlider sldValor = new JSlider(0, 100, 50);
+
+ // Pestaña 2: Lista y acciones
+ private final DefaultListModel listModel = new DefaultListModel<>();
+ private final JList lstElementos = new JList<>(listModel);
+ private final JButton btnAdd = new JButton("Añadir");
+ private final JButton btnRemove = new JButton("Eliminar");
+ private final JTextField txtNuevo = new JTextField(12);
+
+ // Pestaña 3: Área de dibujo simple (Mouse/Key)
+ private final JLabel canvas = new JLabel("Haz clic o arrastra aquí", SwingConstants.CENTER);
+
+ // Barra inferior
+ private final JLabel lblEstado = new JLabel("Listo.");
+ private final JProgressBar progress = new JProgressBar(0, 100);
+ private final JButton btnTareaLarga = new JButton("Tarea larga (SwingWorker)");
+
+ // Hora (propiedad enlazada del modelo)
+ private final JLabel lblHora = new JLabel("--:--:--");
+
+ public Vista() {
+ setTitle("Demo MVC + Eventos (Swing)");
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // Controlado por WindowListener
+ setSize(800, 600);
+ setLocationRelativeTo(null);
+
+ // Menú
+ JMenuBar mb = new JMenuBar();
+ JMenu menuArchivo = new JMenu("Archivo");
+ menuArchivo.add(miNuevo);
+ menuArchivo.addSeparator();
+ menuArchivo.add(miSalir);
+ mb.add(menuArchivo);
+ setJMenuBar(mb);
+
+ // --- Pestaña 1 ---
+ JPanel p1 = new JPanel(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(6,6,6,6);
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ lblContador.setFont(lblContador.getFont().deriveFont(Font.BOLD, 28f));
+ c.gridx = 0; c.gridy = 0; c.gridwidth = 2;
+ p1.add(lblContador, c);
+
+ c.gridwidth = 1; c.gridy = 1; c.gridx = 0;
+ p1.add(btnMenos, c);
+ c.gridx = 1;
+ p1.add(btnMas, c);
+
+ c.gridy = 2; c.gridx = 0;
+ p1.add(new JLabel("Nombre:"), c);
+ c.gridx = 1;
+ p1.add(txtNombre, c);
+
+ c.gridy = 3; c.gridx = 0; c.gridwidth = 2;
+ p1.add(chkHabilitarTexto, c);
+
+ c.gridy = 4; c.gridx = 0; c.gridwidth = 1;
+ p1.add(new JLabel("Color favorito:"), c);
+ c.gridx = 1;
+ p1.add(cboOpciones, c);
+
+ c.gridy = 5; c.gridx = 0;
+ p1.add(new JLabel("Valor:"), c);
+ c.gridx = 1;
+ p1.add(sldValor, c);
+
+ // --- Pestaña 2 ---
+ JPanel p2 = new JPanel(new BorderLayout(8,8));
+ lstElementos.setVisibleRowCount(10);
+ p2.add(new JScrollPane(lstElementos), BorderLayout.CENTER);
+ JPanel p2South = new JPanel();
+ p2South.add(new JLabel("Nuevo:"));
+ p2South.add(txtNuevo);
+ p2South.add(btnAdd);
+ p2South.add(btnRemove);
+ p2.add(p2South, BorderLayout.SOUTH);
+
+ // --- Pestaña 3 ---
+ JPanel p3 = new JPanel(new BorderLayout());
+ canvas.setOpaque(true);
+ canvas.setBackground(new Color(245,245,245));
+ canvas.setPreferredSize(new Dimension(400, 300));
+ p3.add(canvas, BorderLayout.CENTER);
+
+ // Añadir pestañas
+ tabs.addTab("Controles", p1);
+ tabs.addTab("Lista", p2);
+ tabs.addTab("Canvas", p3);
+
+ // Barra inferior de estado
+ JPanel south = new JPanel(new BorderLayout(8,8));
+ JPanel right = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+ right.add(new JLabel("Hora:"));
+ right.add(lblHora);
+ right.add(btnTareaLarga);
+ right.add(progress);
+ south.add(lblEstado, BorderLayout.WEST);
+ south.add(right, BorderLayout.EAST);
+
+ add(tabs, BorderLayout.CENTER);
+ add(south, BorderLayout.SOUTH);
+
+ // Estado inicial
+ txtNombre.setEnabled(false);
+ progress.setStringPainted(true);
+ progress.setValue(0);
+ }
+
+ // === Getters para el Controlador ===
+ public JMenuItem getMiNuevo() { return miNuevo; }
+ public JMenuItem getMiSalir() { return miSalir; }
+
+ public JButton getBtnMas() { return btnMas; }
+ public JButton getBtnMenos() { return btnMenos; }
+ public JCheckBox getChkHabilitarTexto() { return chkHabilitarTexto; }
+ public JTextField getTxtNombre() { return txtNombre; }
+ public JComboBox getCboOpciones() { return cboOpciones; }
+ public JSlider getSldValor() { return sldValor; }
+
+ public DefaultListModel getListModel() { return listModel; }
+ public JList getLstElementos() { return lstElementos; }
+ public JButton getBtnAdd() { return btnAdd; }
+ public JButton getBtnRemove() { return btnRemove; }
+ public JTextField getTxtNuevo() { return txtNuevo; }
+
+ public JLabel getCanvas() { return canvas; }
+ public JTabbedPane getTabs() { return tabs; }
+
+ public JLabel getLblContador() { return lblContador; }
+ public JLabel getLblEstado() { return lblEstado; }
+ public JLabel getLblHora() { return lblHora; }
+ public JProgressBar getProgress() { return progress; }
+ public JButton getBtnTareaLarga() { return btnTareaLarga; }
+
+ // Ayuda para conectar DocumentListener fácilmente
+ public void addNombreDocumentListener(DocumentListener dl) {
+ txtNombre.getDocument().addDocumentListener(dl);
+ }
+}
+