2012-12-01 28 views
1

我正在处理一个问题,我似乎无法获得关于Japplet的JComponent子组件的焦点。我需要关注组件,以便我可以使用键盘监听器为多个屏幕元素(游戏)注册按键。子JComponent尽管可见,但无法获得焦点,启用为真

下面的代码:

class TestApplet extends JApplet { 
    public void init(){ 
     setSize(400, 800); 
     new test class(); 
     setFocusable(true); 
     setVisible(true); 
    } 
} 


public class testclass extends JPanel { 
public testclass() { 
     grabFocus(); 
     requestFocus(); 
     requestFocusInWindow(); 

     System.out.println("visible: " + isVisible()); 
     System.out.println("Enbled " + isEnabled()); 
     System.out.println("Focusable " + isFocusable()); 
     System.out.println(isFocusOwner()); 
    } 
} 

输出的计算结果为

visible: true 
Enbled true 
Focusable true 
false 

尽管这是我用过的重点可能是每一个抓comination为子的事实。如果我把相同的代码放到Japplet中,我创建的键盘监听器可以工作,但不会在我使用子组件时起作用...

由于我在分层地形中有许多JPanel,

N.B有人提出这可能是一个macosx特定的错误 - 我使用Intellij CE11.1。虽然我无法验证这一点。

更新:我还必须创建程序应该响应mb1,2和鼠标中键的功能 - 显然这是不可能没有焦点?

+0

这是又一个理由努力避免在Swing应用程序中使用KeyListeners。我相信你已经在其他地方读过,你应该使用键绑定来代替。 –

+0

不是之前没有。我正在研究目前的解决方案,同时完善我愚蠢的散步。 :) –

+1

考虑发布一个[sscce](http://sscce.org),一个小型可编译和可运行的小程序,不需要外部资源(即图像不能在线提供),我们可以运行,测试和修改,也许可以帮助你正确。 –

回答

2

我创建了自己的SSCCE,并且在测试中,似乎无论使用何种技术,小程序仍然必须请求并获得工作重点。我已经得到了这个成功的工作在我的Windows系统使用两个kludges中的任何一个,包括javax.swing.Timer请求焦点在xxx毫秒后,或覆盖JApplet的paint(...)方法,请求聚焦第一次调用paint并且当applet刚刚被渲染时)。例如,示出两个组装机(只有一个将被要求)和密钥绑定和SSCCE的示例:

import java.awt.BorderLayout; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.lang.reflect.InvocationTargetException; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class KeyBindingEg extends JApplet { 
    protected static final int TIMER_DELAY = 100; 
    private boolean firstPane = true; 

    @Override 
    public void init() { 
     createAndShowGui(); 
    } 

    private void createAndShowGui() { 
     try { 
     SwingUtilities.invokeAndWait(new Runnable() { 
      public void run() { 
       TestClass test = new TestClass(); 
       getContentPane().add(test); 

       // a kludge to get focus on the GUI some time after it has been created 
       new Timer(TIMER_DELAY, new ActionListener() { 

        @Override 
        public void actionPerformed(ActionEvent e) { 
        requestFocusInWindow(); 
        ((Timer)e.getSource()).stop(); 
        } 
       }).start(); 
      } 
     }); 
     } catch (InterruptedException e) { 
     e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
     } 
    } 

    @Override 
    public void paint(Graphics g) { 
     super.paint(g); 
     // another kludge to get focus on the GUI after it is 
     // first rendered 
     if (firstPane) { 
     requestFocusInWindow(); 
     firstPane = false; 
     } 
    } 
} 

@SuppressWarnings("serial") 
class TestClass extends JPanel { 
    public TestClass() { 
     setLayout(new BorderLayout()); 
     add(new JLabel("TestClass", SwingUtilities.CENTER)); 

     int condition = WHEN_IN_FOCUSED_WINDOW; 
     InputMap inputMap = getInputMap(condition); 
     ActionMap actionMap = getActionMap(); 

     for (KeyInfo keyInfo : KeyInfo.values()) { 
     KeyStroke keyStroke = KeyStroke.getKeyStroke(keyInfo.getKeyCode(), 0); 
     inputMap.put(keyStroke , keyInfo.toString()); 
     actionMap.put(keyInfo.toString(), new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent evt) { 
       System.out.println("key press: " + evt.getActionCommand()); 
      } 
     }); 
     } 
    } 
} 

enum KeyInfo { 
    UP(KeyEvent.VK_W), DOWN(KeyEvent.VK_S), LEFT(KeyEvent.VK_A), RIGHT(KeyEvent.VK_D); 
    private int keyCode; 

    private KeyInfo(int keyCode) { 
     this.keyCode = keyCode; 
    } 

    public int getKeyCode() { 
     return keyCode;    
    } 

} 

使用AncestorListener上面的代码:

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.event.*; 
import java.lang.reflect.InvocationTargetException; 

import javax.swing.*; 
import javax.swing.event.AncestorEvent; 
import javax.swing.event.AncestorListener; 

@SuppressWarnings("serial") 
public class KeyBindingEg extends JApplet { 
    protected static final int TIMER_DELAY = 100; 
    private boolean firstPane = true; 

    @Override 
    public void init() { 
     createAndShowGui(); 
    } 

    private void createAndShowGui() { 
     try { 
     SwingUtilities.invokeAndWait(new Runnable() { 
      public void run() { 
       TestClass test = new TestClass(); 

       JPanel contentPane = (JPanel) getContentPane(); 
       contentPane.add(test); 
       contentPane.addAncestorListener(new RequestFocusListener());    
      } 
     }); 
     } catch (InterruptedException e) { 
     e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
     } 
    } 

} 

class RequestFocusListener implements AncestorListener { 
    public void ancestorRemoved(AncestorEvent arg0) {} 
    public void ancestorMoved(AncestorEvent arg0) {} 

    @Override 
    public void ancestorAdded(AncestorEvent aEvt) { 
     Component comp = (Component) aEvt.getSource(); 
     comp.requestFocusInWindow(); 
    } 

} 

@SuppressWarnings("serial") 
class TestClass extends JPanel { 
    public TestClass() { 
     setLayout(new BorderLayout()); 
     add(new JLabel("TestClass", SwingUtilities.CENTER)); 

     int condition = WHEN_IN_FOCUSED_WINDOW; 
     InputMap inputMap = getInputMap(condition); 
     ActionMap actionMap = getActionMap(); 

     for (KeyInfo keyInfo : KeyInfo.values()) { 
     KeyStroke keyStroke = KeyStroke.getKeyStroke(keyInfo.getKeyCode(), 0); 
     inputMap.put(keyStroke, keyInfo.toString()); 
     actionMap.put(keyInfo.toString(), new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent evt) { 
       System.out.println("key press: " + evt.getActionCommand()); 
      } 
     }); 
     } 
    } 
} 

enum KeyInfo { 
    UP(KeyEvent.VK_W), DOWN(KeyEvent.VK_S), LEFT(KeyEvent.VK_A), RIGHT(
     KeyEvent.VK_D); 
    private int keyCode; 

    private KeyInfo(int keyCode) { 
     this.keyCode = keyCode; 
    } 

    public int getKeyCode() { 
     return keyCode; 
    } 

} 
+0

我怀疑'AncestorListener'用在[dialog focus](http:// tips4java。wordpress.com/2010/03/14/dialog-focus/)在这里可能会有效。 –

+0

@AndrewThompson:少说话 - 我认为你是对的。我会稍后再尝试,如果有效,请修改帖子。谢谢! –

+0

因此,如果我理解正确,顶级容器必须获得焦点,才能获得针对儿童容器和其祖先的焦点?在我的架构中,我有超过10个Jpanels链接在一起...因此,我冒险猜测必须强制使用受保护的void paintComponent()方法来设置专注于绘制的子面板之一。 –

相关问题