为什么JPanel.focusGaind和Lost不起作用?

时间:2014-03-01 14:20:57

标签: java swing events jpanel

请查看以下代码(我故意错过了进口)

public class MainFrame extends JFrame {
    private JPanel contentPane;
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MainFrame frame = new MainFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    public MainFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);
        JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        tabbedPane.setBounds(10, 11, 414, 240);
        contentPane.add(tabbedPane);
        JPanel panel = new JPanel();
        panel.addFocusListener(new FocusListener() {

            @Override
            public void focusLost(FocusEvent arg0) {
                System.out.println("lost");
                // I want to do something here, if I reach here!
            }

            @Override
            public void focusGained(FocusEvent arg0) {
                System.out.println("gained");
                // I want to do something here, if I reach here!
            }
        });
        tabbedPane.addTab("New tab", null, panel, null);
        JButton button = new JButton("New button");
        panel.add(button);
        JPanel panel_1 = new JPanel();
        tabbedPane.addTab("New tab", null, panel_1, null);
        JPanel panel_2 = new JPanel();
        tabbedPane.addTab("New tab", null, panel_2, null);
    }
}

我已经创建了这个类来测试它,然后在我的主代码中添加onFocusListener,但它没有按照我期望的方式工作。请告诉我哪里错了,或者这是正确的EvenetListener?

2 个答案:

答案 0 :(得分:4)

  1. 默认情况下,JPanel不可聚焦。如果您想在它们上使用FocusListener,则首先必须通过setFocusable(true)更改此属性。
  2. 但即使你这样做,FocusListener也不是你想要的。
  3. 相反,我希望听听JTabbedPane的模型进行更改。它使用SingleSelectionModel,您可以将ChangeListener添加到此模型,侦听更改,检查当前正在显示的组件以及您的组件是否做出反应。
  4. 您正在使用setBounds和null布局,如果您计划创建和维护除玩具Swing程序以外的任何内容,则需要避免这样做。

  5. 修改
    例如:

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.Dimension;
    import javax.swing.*;
    import javax.swing.event.*;
    
    @SuppressWarnings("serial")
    public class MainPanel extends JPanel {
       private static final int PREF_W = 450;
       private static final int PREF_H = 300;
       private static final int GAP = 5;
       private static final int TAB_COUNT = 5;
    
       private JTabbedPane tabbedPane = new JTabbedPane();
    
       public MainPanel() {
          for (int i = 0; i < TAB_COUNT; i++) {
             JPanel panel = new JPanel();
             panel.add(new JButton("Button " + (i + 1)));
             panel.setName("Panel " + (i + 1));
             tabbedPane.add(panel.getName(), panel);         
          }
    
          setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
          setLayout(new BorderLayout());
          add(tabbedPane, BorderLayout.CENTER);
    
          tabbedPane.getModel().addChangeListener(new ChangeListener() {
    
             @Override
             public void stateChanged(ChangeEvent evt) {
                Component component = tabbedPane.getSelectedComponent();
                System.out.println("Component Selected: " + component.getName());
             }
          });
       }
    
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PREF_W, PREF_H);
       }
    
       private static void createAndShowGui() {
          MainPanel mainPanel = new MainPanel();
    
          JFrame frame = new JFrame("MainPanel");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(mainPanel);
          frame.pack();
          frame.setLocationByPlatform(true);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    

答案 1 :(得分:2)

JPanel是一个轻量级容器,它不是一个Actionable组件,因此它不会获得焦点事件。它允许您添加焦点侦听器,因为swing组件层次结构。为了获得标签选择的事件,您需要使用JTabbedPane#addChangeListener

希望这有帮助。