2012-09-12 14 views
6

Estoy tratando de evitar que el usuario cambie una pestaña cuando la pestaña actual no es válida. Entonces, cuando hace clic en una pestaña, quiero verificar si la actual es "válida", y si no, permanezca en la pestaña actual. He intentado utilizar un VetoableChangeListener que no funcionaba, el código no va dentro del método vetoableChange:Prohibir el cambio de tabulación en un JTabbedPane

jTabbedPane.addVetoableChangeListener(new VetoableChangeListener() { 

    @Override 
    public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { 
    if (!isCurrentTabValid()) { 
     throw new PropertyVetoException("test", evt); 
    } 
    } 
}); 

¿Cómo se puede hacer esto correctamente I?

Gracias!

Respuesta

14

Un VetoableChangeListener es útil solo si la clase con la que está registrado dispara un propertyChange vetoable. La mayoría de las propiedades de JComponents y subclases (todas? Nunca se encontraron con una) no son vetables. Además, la selección se maneja con un SingleSelectionModel, no con el componente en sí.

Ese modelo es el gancho para apoyar vetoable cambia

  • implementar un modelo personalizado que dispara un vetoablePropertyChange al cambiar la selección
  • si ninguno de sus oyentes objeto, seguir adelante con el cambio, de lo contrario no hacer nada
  • establecer el modelo personalizado a la tabbedPane
  • implementar un VetoablePropertyChangeListener que contiene la lógica de validación
  • registrar el vetoableList ener al modelo

en el código, algo así como

public static class VetoableSingleSelectionModel extends 
     DefaultSingleSelectionModel { 

    private VetoableChangeSupport vetoableChangeSupport; 

    @Override 
    public void setSelectedIndex(int index) { 
     if (getSelectedIndex() == index) 
      return; 
     try { 
      fireVetoableChange(getSelectedIndex(), index); 
     } catch (PropertyVetoException e) { 
      return; 
     } 
     super.setSelectedIndex(index); 
    } 

    private void fireVetoableChange(int oldSelectionIndex, 
      int newSelectionIndex) throws PropertyVetoException { 
     if (!isVetoable()) 
      return; 
     vetoableChangeSupport.fireVetoableChange("selectedIndex", 
       oldSelectionIndex, newSelectionIndex); 

    } 

    private boolean isVetoable() { 
     if (vetoableChangeSupport == null) 
      return false; 
     return vetoableChangeSupport.hasListeners(null); 
    } 

    public void addVetoableChangeListener(VetoableChangeListener l) { 
     if (vetoableChangeSupport == null) { 
      vetoableChangeSupport = new VetoableChangeSupport(this); 
     } 
     vetoableChangeSupport.addVetoableChangeListener(l); 
    } 

    public void removeVetoableChangeListener(VetoableChangeListener l) { 
     if (vetoableChangeSupport == null) 
      return; 
     vetoableChangeSupport.removeVetoableChangeListener(l); 
    } 

} 

// usage 
JTabbedPane pane = new JTabbedPane(); 
VetoableSingleSelectionModel model = new VetoableSingleSelectionModel(); 
VetoableChangeListener validator = new VetoableChangeListener() { 

    @Override 
    public void vetoableChange(PropertyChangeEvent evt) 
      throws PropertyVetoException { 
     int oldSelection = (int) evt.getOldValue(); 
     if ((oldSelection == -1) || isValidTab(oldSelection)) return; 

     throw new PropertyVetoException("change not valid", evt); 

    } 

    private boolean isValidTab(int oldSelection) { 
     // implement your validation logic here 
     return false; 
    } 
}; 
model.addVetoableChangeListener(validator); 
pane.setModel(model); 
pane.addTab("one", new JLabel("here we are and stay")); 
pane.addTab("other", new JLabel("poor me, never shown")); 
+0

Esto funciona muy bien para el cambio de pestaña, pero ¿cómo veto el cierre de pestañas? 'vetoableChange' se invoca después de que se cierra la pestaña y cuando se selecciona la pestaña anterior. Busqué en Internet vetoableClose, pero no hits. –

+0

suena no relacionado/extendido - por favor, publique una pregunta con un SSCCE – kleopatra

+0

Está bien, lo resolví. Tengo un componente de botón agregado en cada pestaña para cerrarlos. Invoca 'JTabbedPane.remove (tabIndex)'. Me las arreglé para evitarlo. Estoy seleccionando la pestaña anterior antes de cerrar la actual para que se invoque el método 'valueChanged'. –

0

Parece que vetoableChange es parte del paquete java.beans. Intente agregar un javax.swing.event.ChangeListener.

bodyTabbedPane.addChangeListener(new javax.swing.event.ChangeListener() { 
     public void stateChanged(javax.swing.event.ChangeEvent evt) { 
      bodyTabbedPaneStateChanged(evt); 
     } 
    }); 


private void bodyTabbedPaneStateChanged(javax.swing.event.ChangeEvent evt) { 
    if (!isCurrentTabValid()) {    
     throw new PropertyVetoException("test", evt);   
    } 
} 
+4

supongo que no se intenta que ;-) En el momento de la notificación de cambio de la selección de la selección ya _es_ cambiado, por lo que el único Lo que podría hacer es revertir el cambio, pero el bebé ya está muerto después de caer en el pozo. – kleopatra

1

Parece que quiere desactivar la pestaña primero. Luego, cuando la página actual sea válida, habilite la pestaña. También parece que es posible que desee considerar un CardLayout en lugar de pestañas. Luego use un botón "Siguiente" o "Continuar" cuando la página actual sea válida.

+1

La desactivación de la segunda pestaña puede no ser intuitiva para el usuario. Pero el diseño de la tarjeta puede hacer el trabajo. No olvide agregar algunos consejos para que el usuario vea por qué no puede pasar a la siguiente pantalla. – svz

+0

No quiero deshabilitar ninguna pestaña. Significaría que necesito verificar que la pestaña sea válida después de cada acción realizada por el usuario, lo que no es posible. – Nanocom

Cuestiones relacionadas