Java JTabbedPane - Action immediately before changing the selected Tab

非 Y 不嫁゛ 提交于 2019-12-12 03:37:53

问题


Using a JTabbedPane, I'd like to capture the moment just immediately before the change in the selection of a new tab is effective and perform an action. It'd be something analogous to a focus-lost event for a swing component. The aim is to save the text of a few JTextFields into an external file when the tab is changed, so everytime the user clicks a different tab, the values of the current tab are written into the external file.

I've been using the ChangeListener to track the change of tabs, but haven't found a way to do what I need. Any ideas in how to achieve it in the next simple example?

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

回答1:


One possible way, and I'm not 100% sure that this is acceptable to do or not, but is to create your own model for the JTabbedPane, a model which implements SingleSelectionModel (check the SingleSelectionModel API), that overrides the setSelectedIndex(int index) method, the method that I'm pretty sure Swing uses when it wants to tell the JTabbedPane to change tabs. If you create a class that extends from the DefaultSingleSelectionModel, a concrete class that implements the above interface and override this method, you could make method calls before the super's method is called, and thus make GUI calls before the tab changes. For example, your setSelectedIndex method could look like this:

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

And using your code above could be implemented like:

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

Note that I use a boolean field, activated to activate the behavior change so that it doesn't fire on GUI creation. I call setActivated(true) on the model after displaying the GUI.


Regarding your edit:

The aim is to save the text of a few JTextFields into an external file when the tab is changed, so everytime the user clicks a different tab, the values of the current tab are written into the external file.

I should have known, it was an XY Problem after all, where you ask how to solve a specific code problem when the best solution is to use a completely different approach. In the future, please give us all pertinent information with the original question so we can avoid wasting time with unnecessary solutions.

There is in fact no need here to do anything before the tab changes since it is perfectly fine to get the data when the tabs change. Your solution is to use a ChangeListener, and there's no need to go through the gymnastics of what I posted above.



来源:https://stackoverflow.com/questions/37913932/java-jtabbedpane-action-immediately-before-changing-the-selected-tab

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!