1

I'm working on a problem and I can't seem to gain focus for JComponent sub components of a Japplet. I'm required to focus the component so that I can use a keyboard listener to register keypresses for a number of onscreen elements (game).

Here's the code:

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()); 
    } 
}

the output evaluates as

visible: true
Enbled true
Focusable true
false

This is despite the fact that I've used every possibly comination of focus grabbing for the subcomponent. If I place the same code into the Japplet, the keyboard listener that I create does work but not when I use a subcomponent...

This is fairy critical to my application since I have many JPanels in a hierarchal topography.

N.B it's been suggested that this might be a macosx specific bug - I'm using Intellij CE11.1. Although I'm unable to verify this.

UPDATE: I have to also create the functionality that the program should respond to mb1,2 and the middle mouse button - clearly this is impossible without focus?

4

1 回答 1

2

我创建了自己的 SSCCE,在测试中,似乎无论使用什么技术,小程序仍然必须请求并获得焦点才能使它们工作。我已经使用两个组件中的任何一个成功地在我的 Windows 系统上工作,包括在 xxx ms 之后请求焦点的 javax.swing.Timer,或者paint(...)在第一次调用绘制时请求焦点的 JApplet 方法的覆盖(和当小程序刚刚被渲染时)。例如,显示两个 kludges(只需要一个)以及键绑定和 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;
   }

}
于 2012-12-01T21:49:01.900 回答