【问题标题】:Java JTabbedPane - Action immediately before changing the selected TabJava JTabbedPane - 在更改选定选项卡之前立即执行的操作
【发布时间】:2016-06-20 02:37:17
【问题描述】:

使用 JTabbedPane,我想在新选项卡的选择更改生效之前捕捉瞬间并执行操作。这类似于摆动组件的焦点丢失事件。目的是在tab改变时将几个JTextField的文本保存到外部文件中,这样每次用户点击不同的tab时,当前tab的值都会写入到外部文件中。

我一直在使用 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);
    }
}

【问题讨论】:

    标签: java swing jtabbedpane changelistener


    【解决方案1】:

    一种可能方式,我不能 100% 确定这是否可以接受,而是为 JTabbedPane 创建您自己的模型,这是一个实现 SingleSelectionModel 的模型(检查SingleSelectionModel API),它覆盖了 setSelectedIndex(int index) 方法,我很确定 Swing 在它想要告诉 JTabbedPane 更改选项卡时使用的方法。如果您创建一个从DefaultSingleSelectionModel 扩展的类,一个实现上述接口并覆盖此方法的具体类,您可以在调用super 的方法之前进行方法调用,从而进行GUI 调用before 选项卡更改。例如,您的 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 时触发。我在模型上调用setActivated(true)显示 GUI。


    关于您的编辑:

    目的是在tab改变时将几个JTextField的文本保存到外部文件中,这样每次用户点击不同的tab时,当前tab的值都会写入到外部文件中。

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

    实际上,在标签更改之前 不需要做任何事情,因为在标签更改时 获取数据是非常好的。您的解决方案是使用 ChangeListener,无需通过我上面发布的体操。

    【讨论】:

    • 我不明白如何执行该操作,您能解释一下吗?可能问题不够清楚,我只是编辑了一下。
    • @David:请看我上面的编辑。请理解,我们是志愿者,提供的任何帮助都是在我们自己的时间完成的,因此非常感谢您提供完整的问题。
    • 给您带来的不便,我深表歉意。我只是想尽可能地简化问题,以便让想要帮助的人更容易。不过,我不知道如何使用 ChangeListener 来做到这一点。
    • @David:但你已经有了。您的 ChangeListener 会通知您选项卡中的更改。此时所需要做的就是从旧选项卡组件中提取数据。请注意,您没有向我们展示包含 JTextFields 的选项卡式组件,因此我们无法提供更具体的帮助,只能建议“提取字段包含的文本”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 2013-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多