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); + } +} +