Java JTabbedPane - 在更改所选选项卡之前立即执行操作

时间:2016-06-20 02:37:18

标签: java swing jtabbedpane changelistener

使用JTabbedPane,我想在选择新选项卡的更改生效之前立即捕捉这一时刻并执行操作。它类似于摆动组件的焦点丢失事件。目的是在更改选项卡时将几个JTextField的文本保存到外部文件中,因此每次用户单击其他选项卡时,当前选项卡的值都会写入外部文件。

我一直在使用ChangeListener跟踪标签的更改,但还没有找到一种方法来完成我需要的工作。在下一个简单的例子中如何实现它的任何想法?

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 个答案:

答案 0 :(得分:4)

一种可能的方式,并且我不能100%确定这是否可以接受,而是为JTabbedPane创建自己的模型,JTabbedPane是一个实现SingleSelectionModel的模型(检查SingleSelectionModel API),这会覆盖setSelectedIndex(int index)方法,我非常确定Swing在告知JTabbedPane更改标签时使用的方法。如果您创建一个从DefaultSingleSelectionModel扩展的类,一个实现上述接口并覆盖此方法的具体类,您可以在调用super方法之前进行方法调用,从而进行GUI调用< em>在标签更改之前。例如,您的setSelectedIndex方法可能如下所示:

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

使用上面的代码可以实现如下:

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

请注意,我使用布尔字段activated来激活行为更改,以便它不会在GUI创建时触发。在显示GUI后,我在模型上调用setActivated(true)

关于你的编辑:

  

目标是在更改选项卡时将几个JTextField的文本保存到外部文件中,因此每次用户单击其他选项卡时,当前选项卡的值都会写入外部文件。

我应该知道,毕竟这是一个XY Problem,在最好的解决方案是使用完全不同的方法时,你会问如何解决特定的代码问题。将来,请提供原始问题的所有相关信息,以便我们避免浪费时间使用不必要的解决方案。

事实上,在选项卡更改之前,实际上不需要执行任何操作,因为在选项卡更改时获取数据是完全正常的。你的解决方案是使用ChangeListener,并且不需要通过我上面发布的体操。