在JOptionPane.showOptionDialog()中设置组件焦点

时间:2011-06-06 11:58:56

标签: java swing focus joptionpane

为了在输入对话框中有自定义按钮标题,我创建了以下代码:

String key = null;
JTextField txtKey = new JTextField();        
int answerKey = JOptionPane.showOptionDialog(this, new Object[] {pleaseEnterTheKey, txtKey}, decryptionKey, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] {okCaption, cancelCaption}, okCaption);        
if (answerKey == JOptionPane.OK_OPTION && txtKey.getText() != null) {
  key = txtKey.getText();
}

如何在显示对话框时将焦点(光标)移动到文本字段?

更新

这对我不起作用,我的意思是文本字段没有焦点: 操作系统:Fedora - Gnome

public class Test {
  public static void main(String[] args) {
    String key = null;
    JTextField txtKey = new JTextField();
    txtKey.addAncestorListener(new RequestFocusListener());
    int answerKey = JOptionPane.showOptionDialog(null, new Object[]{"Please enter the key:", txtKey}, "Title", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[]{"OKKK", "CANCELLLL"}, "OKKK");
    if (answerKey == JOptionPane.OK_OPTION && txtKey.getText() != null) {
      key = txtKey.getText();
    }
  }
}

8 个答案:

答案 0 :(得分:14)

Dialog Focus显示了如何轻松地将焦点设置在模态对话框中的任何组件上。

答案 1 :(得分:8)

    public static String getPassword(String title) {
        JPanel panel = new JPanel();
        final JPasswordField passwordField = new JPasswordField(10);
        panel.add(new JLabel("Password"));
        panel.add(passwordField);
        JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
            @Override
            public void selectInitialValue() {
                passwordField.requestFocusInWindow();
            }
        };
        pane.createDialog(null, title).setVisible(true);
        return passwordField.getPassword().length == 0 ? null : new String(passwordField.getPassword());
    }

答案 2 :(得分:5)

传递null作为最后一个参数是解决方案。至少它对我有用。

String key = null;
JTextField txtKey = new JTextField();        
int answerKey = JOptionPane.showOptionDialog(this, new Object[] {pleaseEnterTheKey, txtKey}, decryptionKey, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] {okCaption, cancelCaption}, null);        
if (answerKey == JOptionPane.OK_OPTION && txtKey.getText() != null) {
  key = txtKey.getText();
}

但即便是这个解决方案也会带来另一个问题:

专注组件和默认组件不同。默认组件或默认按钮是按下ENTER KEY时触发其onclick的按钮。最后一个参数定义了获得焦点的默认组件,并且传递null会带来没有默认组件的问题! 我通过这种方式为我的代码解决了它,但我想这不是最佳实践:

String key = null;
    final JTextField txtKey = new JTextField();
    txtKey.addKeyListener(new KeyAdapter() {

      @Override
      public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if (keyCode == 10) { //enter key
          Container parent = txtKey.getParent();              
          while (!(parent instanceof JOptionPane)) {
            parent = parent.getParent();
          }

          JOptionPane pane = (JOptionPane) parent;
          final JPanel pnlBottom = (JPanel) pane.getComponent(pane.getComponentCount() - 1);
          for (int i = 0; i < pnlBottom.getComponents().length; i++) {
            Component component = pnlBottom.getComponents()[i];
            if (component instanceof JButton) {
              final JButton okButton = ((JButton)component);
              if (okButton.getText().equalsIgnoreCase(okCaption)) {
                ActionListener[] actionListeners = okButton.getActionListeners();
                if (actionListeners.length > 0) {
                  actionListeners[0].actionPerformed(null);
                }
              }
            }
          }
        }
      }

    });

答案 3 :(得分:4)

我遇到同样的问题,RequestFocusListener()无法在Linux上运行,在对http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5018574进行讨论之后,我发现添加一个invokeLater现在修复了它...

public class RequestFocusListener implements AncestorListener
{
public void ancestorAdded(final AncestorEvent e)
{
    final AncestorListener al= this;   
    SwingUtilities.invokeLater(new Runnable(){

        @Override
        public void run() {
            JComponent component = (JComponent)e.getComponent();
            component.requestFocusInWindow();
            component.removeAncestorListener( al );
        }
    });
}

public void ancestorMoved(AncestorEvent e) {}
public void ancestorRemoved(AncestorEvent e) {}
}

答案 4 :(得分:2)

诀窍是(a)在文本组件上使用AncestorListener来请求焦点,当焦点再次丢失时(赋予默认按钮),请在文本组件上使用FocusListener再次请求焦点(但在此之后不要继续寻求关注):

final JPasswordField accessPassword = new JPasswordField();

accessPassword.addAncestorListener( new AncestorListener()
{
  @Override
  public void ancestorRemoved( final AncestorEvent event )
  {
  }
  @Override
  public void ancestorMoved( final AncestorEvent event )
  {
  }
  @Override
  public void ancestorAdded( final AncestorEvent event )
  {
    // Ask for focus (we'll lose it again)
    accessPassword.requestFocusInWindow();
  }
} );

accessPassword.addFocusListener( new FocusListener()
{
  @Override
  public void focusGained( final FocusEvent e )
  {
  }
  @Override
  public void focusLost( final FocusEvent e )
  {
    if( isFirstTime )
    {
      // When we lose focus, ask for it back but only once
      accessPassword.requestFocusInWindow();
      isFirstTime = false;
    }
  }
  private boolean isFirstTime = true;
} );

答案 5 :(得分:1)

试试这个

String key = null;
JTextField txtKey = new JTextField();
Object[] foo = {pleaseEnterTheKey, txtKey};      
int answerKey = JOptionPane.showOptionDialog(this, foo, decryptionKey, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[] {okCaption, cancelCaption}, foo[1]);        
if (answerKey == JOptionPane.OK_OPTION && txtKey.getText() != null) {
  key = txtKey.getText();
}

答案 6 :(得分:1)

更好的方法:使用构造函数创建JOptionPane,覆盖selectInitialValue以设置焦点,然后使用createDialog构建对话框。

// Replace by the constructor you want
JOptionPane pane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION) {
  @Override
  public void selectInitialValue() {
    textArea.requestFocusInWindow();
  }
};

JDialog dialog = pane.createDialog(owner, title);
dialog.setVisible(true);

答案 7 :(得分:0)

我找到了解决方案! 非常原始,但有效。

通过java.awt跳转到该字段。机器人使用键&#34; Tab&#34;。 例如:

Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_TAB);
robot.delay(100);
robot.keyRelease(KeyEvent.VK_TAB);

如果你应该多按几次&#34; Tab&#34;要获得您的组件,您可以使用以下方法:

GUIUtils.pressTab(3);

定义:

public static void pressTab(int amountOfClickes)
{
    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
            try
            {
                Robot robot = new Robot();
                int i = amountOfClickes;
                while (i-- > 0)
                {
                    robot.keyPress(KeyEvent.VK_TAB);
                    robot.delay(100);
                    robot.keyRelease(KeyEvent.VK_TAB);
                }
            }
            catch (AWTException e)
            {
                System.out.println("Failed to use Robot, got exception: " + e.getMessage());
            }
        }
    });
}

如果你的Component位置是动态的,你可以无限制地运行while循环,但是在组件上添加一些焦点监听器,一旦到达它就停止循环。