无法将焦点转移到未示出的CardLayout JPanel

时间:2014-05-16 16:19:48

标签: java swing focus

为什么我无法将焦点转移到JPanel中未显示的CardLayout卡?

我正在实现一个基于CardLayout的界面,需要键盘导航友好。当用户完成对一张卡上所有字段的选项卡切换时,用户需要能够切换到下一张卡片。

我已经实施了一个FocusTraversalPolicy,在此过程中的每个点生成了正确的Component,并FocusAdapter用于弹出新标记的卡片,但有些东西正在吃消息和防止焦点改变。

可以不清楚地将CardLayout传递给FocusTraversalPolicy以更改卡片 - 虽然它在Swing的多个线程中多次调用它的任何函数并导致奇怪的行为。此外,那种方式只是肮脏的。

想要使用键盘绑定b / c,这需要重新实现Java已经为我做的所有焦点工作,并且也非常不洁净。

基本上:Java不喜欢将焦点转移到CardLayout s中的未显示的卡片 - 如何覆盖它?

2 个答案:

答案 0 :(得分:2)

听起来你有一个类似巫师的UI。如果是这样,请添加"下一步"按钮作为每张卡片上的最后一个字段。

“下一步”按钮的操作是将设置焦点翻转到下一张卡片到第一个输入字段。

每张卡片上的最后一个输入字段会将焦点转移到“下一步”按钮,然后可以按下"按下"获得焦点时空格键的敲击(这是JButton的默认行为),保持键盘友好。

这将减少对特殊KeyBindings或FocusTraversalPolicies的需求。

修改

尝试使用FocusListeners作为JTextFields。选项卡切换到字段,一旦您退出最后一个字段,卡片将自动翻转到下一个。如果您愿意,可以使用ActionListeners:

编辑2:为只有1个字段的面板添加了黑客攻击。

import java.awt.*;
import java.awt.event.*;
import java.beans.*;

import javax.swing.*;

public class CardLayoutDemo2 implements Runnable
{
  final static String CARD1 = "One";
  final static String CARD2 = "Two";
  final static String CARD3 = "Three";

  JPanel cards;
  CardLayout cardLayout;
  JTextField tf1, tf2, tf3, tf4, tf5;
  JButton dummy;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new CardLayoutDemo2());
  }

  public void run()
  {
    tf1 = new JTextField(10);
    tf2 = new JTextField(10);
    tf2.addFocusListener(new CardFlipper(CARD2));

    tf3 = new JTextField(10);
    tf4 = new JTextField(10);
    tf4.addFocusListener(new CardFlipper(CARD3));

    tf5 = new JTextField(10);
    tf5.addFocusListener(new CardFlipper(CARD1));

    dummy = new JButton()
    {
      @Override
      public Dimension getPreferredSize()
      {
        return new Dimension(0,0);
      }
    };

    dummy.addFocusListener(new FocusAdapter()
    {
      @Override
      public void focusGained(FocusEvent e)
      {
        dummy.transferFocus();
      }
    });

    JPanel card1 = new JPanel();
    card1.add(new JLabel("One"));
    card1.add(tf1);
    card1.add(new JLabel("Two"));
    card1.add(tf2);

    JPanel card2 = new JPanel();
    card2.add(new JLabel("Three"));
    card2.add(tf3);
    card2.add(new JLabel("Four"));
    card2.add(tf4);

    JPanel card3 = new JPanel();
    card3.add(dummy);
    card3.add(new JLabel("Five"));
    card3.add(tf5);    

    cardLayout = new CardLayout();
    cards = new JPanel(cardLayout);
    cards.add(card1, CARD1);
    cards.add(card2, CARD2);
    cards.add(card3, CARD3);

    JFrame f = new JFrame("CardLayout Demo");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.add(cards, BorderLayout.CENTER);
    f.setSize(180, 200);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }

  private class CardFlipper extends FocusAdapter
  {
    private String nextCard;

    CardFlipper(String cardName)
    {
      this.nextCard = cardName;
    }

    @Override
    public void focusLost(FocusEvent e)
    {
      cardLayout.show(cards, nextCard);
    }
  } 
}

答案 1 :(得分:2)

  

我想让程序分开,因为它以不同的步骤运行。

这不会阻止您创建长滚动表单?

您仍然可以按照现在的方式创建单独的面板。然后,您可以使用BoxLayout(或GridBagLayout)将面板添加到面板,而不是将这些面板添加到需要交换面板的CardLayout。

这甚至可以提供更大的灵活性,因为每个面板可以具有不同的尺寸,而不会影响每个面板的尺寸。

但是,表单当前不会在JScrollPane中自动滚动,因此您可能需要查看Scrolling a Form这样的类,这将为您执行此操作。