2016-06-20 24 views
0

Mit einem JTabbedPane möchte ich den Moment erfassen, unmittelbar bevor die Änderung in der Auswahl eines neuen Tabs wirksam wird und eine Aktion ausführt. Es wäre etwas analog zu einem Fokus-verlorenen Ereignis für eine Schwungkomponente. Das Ziel besteht darin, den Text einiger JTextFields in einer externen Datei zu speichern, wenn die Registerkarte geändert wird. Wenn der Benutzer also auf eine andere Registerkarte klickt, werden die Werte der aktuellen Registerkarte in die externe Datei geschrieben.Java JTabbedPane - Aktion unmittelbar vor dem Ändern des ausgewählten Tabs

Ich habe den ChangeListener verwendet, um die Änderung von Tabs zu verfolgen, habe aber keine Möglichkeit gefunden, das zu tun, was ich brauche. Irgendwelche Ideen, wie man es im nächsten einfachen Beispiel erreichen kann?

import java.awt.BorderLayout; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JTabbedPane; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class TabSample { 
    static void add(JTabbedPane tabbedPane, String label) { 
     JButton button = new JButton(label); 
     tabbedPane.addTab(label, button); 
    } 

    public static void main(String args[]) { 
     JFrame frame = new JFrame("TabSample"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JTabbedPane tabbedPane = new JTabbedPane(); 

     String titles[] = { "Geometry", "Materials", "Analysis"}; 
     for (int i = 0, n = titles.length; i < n; i++) { 
      add(tabbedPane, titles[i]); 
     } 

     ChangeListener changeListener = new ChangeListener() { 
      public void stateChanged(ChangeEvent changeEvent) { 
       JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent.getSource(); 
       int index = sourceTabbedPane.getSelectedIndex(); 
       System.out.println("Tab changed to: " + sourceTabbedPane.getTitleAt(index)); 
     } 
     }; 
     tabbedPane.addChangeListener(changeListener); 
     frame.add(tabbedPane, BorderLayout.CENTER); 
     frame.setSize(400, 150); 
     frame.setVisible(true); 
    } 
} 

Antwort

4

One möglich Art und Weise, und ich bin nicht 100% sicher, dass dies akzeptabel ist, zu tun oder nicht, aber es ist Ihr eigenes Modell für die JTabbedPane, ein Modell zu schaffen, die SingleSelectionModel implementiert ist (siehe Info SingleSelectionModel API), das überschreibt die Methode setSelectedIndex(int index), die Methode, von der ich ziemlich sicher bin, dass Swing verwendet, wenn sie dem JTabbedPane mitteilen möchte, Tabs zu ändern. Wenn Sie eine Klasse erstellen, die sich von DefaultSingleSelectionModel erstreckt, einer konkreten Klasse, die die obige Schnittstelle implementiert und diese Methode überschreibt, können Sie Methodenaufrufe ausführen, bevor die Methode des Super-Aufrufs aufgerufen wird, und die GUI-Aufrufe vor ändern. Zum Beispiel Ihrer setSelectedIndex Methode könnte wie folgt aussehen:

@Override 
    public void setSelectedIndex(int index) { 
     if (activated) { 
      String text = String.format("Before change, old index: %d; new index: %d", super.getSelectedIndex(), index); 
      JOptionPane.showMessageDialog(gui, text); 
     } 
     super.setSelectedIndex(index); 
    } 

Und mit Ihrem Code oben könnte wie implementiert wird:

import java.awt.BorderLayout; 
import java.awt.Component; 

import javax.swing.DefaultSingleSelectionModel; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JTabbedPane; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

public class TabSample { 
    static void add(JTabbedPane tabbedPane, String label) { 
     JButton button = new JButton(label); 
     tabbedPane.addTab(label, button); 
    } 

    public static void main(String args[]) { 
     JFrame frame = new JFrame("TabSample"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     MySingleSelectionModel selectionModel = new MySingleSelectionModel(frame); 

     JTabbedPane tabbedPane = new JTabbedPane(); 
     tabbedPane.setModel(selectionModel); 

     String titles[] = { "Geometry", "Materials", "Analysis"}; 
     for (int i = 0, n = titles.length; i < n; i++) { 
      add(tabbedPane, titles[i]); 
     } 

     ChangeListener changeListener = new ChangeListener() { 
      public void stateChanged(ChangeEvent changeEvent) { 
       JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent.getSource(); 
       int index = sourceTabbedPane.getSelectedIndex(); 
       System.out.println("Tab changed to: " + sourceTabbedPane.getTitleAt(index)); 
     } 
     }; 
     tabbedPane.addChangeListener(changeListener); 
     frame.add(tabbedPane, BorderLayout.CENTER); 
     frame.setSize(400, 150); 
     frame.setVisible(true); 
     selectionModel.setActivated(true); 
    } 

    private static class MySingleSelectionModel extends DefaultSingleSelectionModel { 
     private Component gui; 
     private boolean activated = false; 

     public MySingleSelectionModel(Component gui) { 
      this.gui = gui; 
     } 

     public void setActivated(boolean activated) { 
      this.activated = activated; 
     } 

     @Override 
     public void setSelectedIndex(int index) { 
      if (activated) { 
       String text = String.format("Before change, old index: %d; new index: %d", 
         super.getSelectedIndex(), index); 
       JOptionPane.showMessageDialog(gui, text); 
      } 
      super.setSelectedIndex(index); 
     } 
    } 
} 

Bitte beachte, dass ich ein boolean-Feld verwenden, um activated die Verhaltensänderung zu aktivieren, so dass es nicht bei der GUI-Erstellung ausgelöst wird. Ich rufe setActivated(true) auf dem Modell nach mit der GUI.


In Bezug auf Ihre edit:

Ziel ist es, den Text von wenigen JTextFields in eine externe Datei zu speichern, wenn die Registerkarte geändert wird, so jedes Mal klickt der Benutzer auf eine andere Registerkarte, die Werte von Die aktuelle Registerkarte wird in die externe Datei geschrieben.

ich gewusst hätte, war es ein XY Problem nach allem, wo Sie fragen, wie einen spezifischen Code Problem zu lösen, wenn die beste Lösung, einen völlig anderen Ansatz zu verwenden ist. In der Zukunft geben Sie uns bitte alle relevanten Informationen mit der ursprünglichen Frage, so dass wir vermeiden können, Zeit mit unnötigen Lösungen zu verschwenden.

in der Tat gibt es hier keine Notwendigkeit, etwas vor die Registerkarte Änderungen zu tun, da es völlig in Ordnung ist, die Daten wenn die Registerkarten Änderung zu erhalten. Ihre Lösung besteht darin, einen ChangeListener zu verwenden, und es besteht keine Notwendigkeit, durch das Turnen dessen, was ich oben gepostet habe, zu gehen.

+0

Ich verstehe nicht, wie die Aktion ausgeführt werden kann, könnten Sie es erklären? Vielleicht war die Frage nicht klar genug, ich habe sie nur bearbeitet. – David

+0

@David: Siehe meine Änderungen oben. Bitte haben Sie Verständnis dafür, dass wir ehrenamtliche Mitarbeiter sind und dass jegliche Hilfe in unserer eigenen Zeit geleistet wird. Daher werden vollständige Fragen sehr geschätzt. –

+0

Ich entschuldige mich für die Unannehmlichkeiten. Ich wollte die Frage so einfach wie möglich vereinfachen, um Menschen, die helfen wollen, die Arbeit zu erleichtern. Dennoch sehe ich nicht, wie man es mit einem ChangeListener macht. – David