2012-09-12 11 views
6

Ich versuche zu verhindern, dass der Benutzer eine Registerkarte ändert, wenn die aktuelle Registerkarte nicht gültig ist. Also, wenn er auf einen Tab klickt, möchte ich überprüfen, ob der aktuelle "gültig" ist, und wenn nicht, auf dem aktuellen Tab bleiben. Ich versuchte, einen VetoableChangeListener zu verwenden, die nicht funktioniert hat, geht der Code nie in der vetoableChange Methode:Tabulatorwechsel in einem JTabbedPane verbieten

jTabbedPane.addVetoableChangeListener(new VetoableChangeListener() { 

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

Wie kann ich dies richtig tun?

Danke!

Antwort

14

Ein VetoableChangeListener ist nur dann nützlich, wenn die Klasse, für die er registriert ist, eine vetoable propertyChange auslöst. Die meisten Eigenschaften von JComponents (und alle wurden nie gefunden) und Unterklassen sind nicht abdingbar. Außerdem wird die Auswahl von einem SingleSelectionModel und nicht von der Komponente selbst vorgenommen.

Dieses Modell ist der Haken zu unterstützen vetoable ändert

  • ein benutzerdefiniertes Modell implementieren, die eine vetoablePropertyChange auf Auswahl ändern feuert
  • wenn keiner seiner Zuhörer Objekt, mit dem Wechsel vorangehen, sonst nichts tun
  • das benutzerdefinierte Modell zum tabbedPane
  • eine VetoablePropertyChangeListener implementieren, die die Logik Validierung enthält
  • registrieren vetoableList ener zum Modell

in Code, so etwas wie

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

Dies funktioniert hervorragend für das Wechseln von Tabs, aber wie können Sie das Schließen von Tabs verhindern? 'vetoableChange' wird aufgerufen, nachdem die Registerkarte geschlossen wurde und wenn die vorherige Registerkarte ausgewählt wurde. Ich suchte im Internet nach vetoableClose, aber keine Treffer. –

+0

klingt nicht verwandt/erweitert - bitte posten Sie eine Frage mit einem SSCCE – kleopatra

+0

Es ist in Ordnung, ich habe es gelöst. Ich habe eine Schaltfläche Komponente auf jeder Registerkarte hinzugefügt, um sie zu schließen. Es ruft 'JTabbedPane.remove (tabIndex)' auf. Ich habe es geschafft, es zu umgehen. Ich wähle die vorherige Registerkarte, bevor ich die aktuelle schließt, damit die 'valueChanged' Methode aufgerufen wird. –

0

Es sieht so aus, als ob vetoableChange Teil des Pakets java.beans ist. Versuchen Sie, eine javax.swing.event.ChangeListener hinzuzufügen.

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

erraten Sie nicht das Sie versuchen, dass ;-) Im Moment der Benachrichtigung Auswahl Änderung der Auswahl bereits _is_ geändert, so dass die einzige Dings wäre es möglich, die Änderung rückgängig zu machen - aber das Baby ist bereits tot, nachdem es in den Brunnen gefallen ist. – kleopatra

1

Klingt, als ob Sie die Registerkarte zuerst deaktivieren möchten. Wenn die aktuelle Seite gültig ist, aktivieren Sie die Registerkarte. Klingt auch so, als ob Sie ein CardLayout anstelle von Tabs in Betracht ziehen sollten. Verwenden Sie dann die Schaltfläche "Weiter" oder "Fortfahren", wenn die aktuelle Seite gültig ist.

+1

Das Deaktivieren der zweiten Registerkarte ist für den Benutzer möglicherweise nicht intuitiv. Aber Kartenlayout kann die Aufgabe erledigen. Vergessen Sie nicht, dem Benutzer einige Tipps hinzuzufügen, um zu erfahren, warum er nicht zum nächsten Bildschirm wechseln kann. – svz

+0

Ich möchte keine Registerkarte deaktivieren. Das würde bedeuten, dass ich überprüfen muss, ob die Registerkarte nach jeder Aktion des Benutzers gültig ist, was nicht möglich ist. – Nanocom