KeyStroke に関する最初の質問については、 KeyListener を使用する代わりにKeyBindingを使用できると思います。これにより、問題のコンポーネントのフォーカス関連の問題がなくても、Java ディメンション内で目的の結果が得られます。
以下の例では、フォーカスがJTextField
最初にあるため、 を押すと、フォーカスが にある場合でもCTRL + D、 にアタッチされた paintActionCustomPanel
が機能しますJTextField
。
ただし、 にsetMnemonic()メソッドを使用する場合、 はフォーカスを取得しJButton
、JButton
それに関連付けられた独自のアクション (楕円を描画する) を実行します。これは、 を押しALT + Cて目的の効果を確認することで確認できます。再び描画関連の処理を実行するために、問題のコンポーネントは両方ともフォーカスを必要としませんが、それでも KeyStrokes に応答します。
コード例は次のとおりです。
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class SSCCE
{
private final int WIDTH = 500;
private final int HEIGHT = 500;
private CustomPanel customPanel;
private JButton circleButton;
private JTextField tfield;
private Random random;
private int mode;
private Action paintAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent ae)
{
mode = random.nextInt(3);
Color color = new Color(random.nextFloat(), random.nextFloat()
, random.nextFloat(), random.nextFloat());
customPanel.setValues(random.nextInt(WIDTH),
random.nextInt(HEIGHT), random.nextInt(WIDTH),
random.nextInt(HEIGHT), color, mode);
}
};
private ActionListener buttonAction = new ActionListener()
{
@Override
public void actionPerformed(ActionEvent ae)
{
Color color = new Color(random.nextFloat(), random.nextFloat()
, random.nextFloat(), random.nextFloat());
customPanel.setValues(random.nextInt(WIDTH),
random.nextInt(HEIGHT), random.nextInt(WIDTH),
random.nextInt(HEIGHT), color, 2);
}
};
public SSCCE()
{
random = new Random();
}
private void displayGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
customPanel = new CustomPanel();
customPanel.getInputMap(
JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_D
, InputEvent.CTRL_DOWN_MASK), "paintAction");
customPanel.getActionMap().put("paintAction", paintAction);
JPanel footerPanel = new JPanel();
circleButton = new JButton("Draw Circle");
circleButton.setMnemonic(KeyEvent.VK_C);
circleButton.addActionListener(buttonAction);
tfield = new JTextField(20);
tfield.setText("USELESS, just to get the focus for itself.");
tfield.requestFocusInWindow();
footerPanel.add(tfield);
footerPanel.add(circleButton);
contentPane.add(customPanel, BorderLayout.CENTER);
contentPane.add(footerPanel, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
new SSCCE().displayGUI();
}
});
}
}
class CustomPanel extends JPanel
{
private final int WIDTH = 500;
private final int HEIGHT = 500;
private int mode = 0;
private Color colorShape;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
public void setValues(int x, int y, int w, int h, Color color, int mode)
{
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.colorShape = color;
this.mode = mode;
repaint();
}
@Override
public Dimension getPreferredSize()
{
return (new Dimension(WIDTH, HEIGHT));
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(colorShape);
if (mode == 1)
g.fillRect(x, y, width, height);
else if (mode == 2)
g.fillOval(x, y, width, height);
}
}
モノに関連してmousePressed()
、@mKorbel はいつものようにモノ全体を楽しい方法で提示しました。
そして、あなたの2番目の質問に関しては、あなた自身が宿題をしたようです. 質問で示したものを使用することは、オペレーティング システム関連のイベントをキャッチし、それを Java Application またはJava Native Interfaceに転送するための回避策であるように思われますが、これでもうまくいくと思います。