在手动单击组件之前,焦点不起作用
Focus does not work until component is manually clicked
我正在尝试创建一个计算器,我正在使用 KeyBinders 来允许用户输入数字,而不必手动按下按钮。但是,我注意到在我用鼠标按下其中一个按钮之后,KeyBinders 才会工作。这是我的代码:
import java.awt.*;
...
public class Calculator extends JFrame {
static JFrame f = new JFrame();
static JPanel p = new JPanel();
static JButton[] b = new JButton[19];
static String[] bs = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
".", "+", "-", "*", "/", "=", "C", "\u2190", "\u00B1" };
static JTextArea t = new JTextArea();
public static void main(String[] args) {
f.setSize(300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
for (int i = 0; i < b.length; i++) {
b[i] = new JButton();
b[i].setText(bs[i]);
b[i].addActionListener(new BAction());
b[i].setFont(new Font("Arial", Font.BOLD, 17));
b[i].setFocusable(true);
}
setLayout(p, b);
f.add(p);
f.setVisible(true);
}
public static JPanel setLayout(JPanel p, JButton[] b) {
Image icon = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
f.setIconImage(icon);
GridBagLayout g = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
p.setLayout(g);
p.setSize(f.getSize());
t.setEditable(false);
t.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
t.setFont(new Font("Arial", Font.PLAIN, 15));
t.setFocusable(false);
t.setText("0");
f.setFocusable(true);
p.setFocusable(true);
key();
...
// GridBagLayouting here
...
return p;
}
static class BAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
...
// Assigning ActionEventListeners
...
}
@SuppressWarnings({ "serial" })
private static void key() {
// 0
Action b0 = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[0].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "b0");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), "b0");
p.getActionMap().put("b0", b0);
// 1
Action b1 = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[1].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD1, 0), "b1");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), "b1");
p.getActionMap().put("b1", b1);
// 2
Action b2 = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[2].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, 0), "b2");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_2, 0), "b2");
p.getActionMap().put("b2", b2);
// +
Action bplus = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[11].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "b+");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS,
InputEvent.SHIFT_MASK), "b+");
p.getActionMap().put("b+", bplus);
}
}
您可以在创建绑定时使用 WHEN_IN_FOCUSED_WINDOW
而不是 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
。
更新
/**
* Constant used for <code>registerKeyboardAction</code> that
* means that the command should be invoked when the receiving
* component is an ancestor of the focused component or is
* itself the focused component.
*/
public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1;
/**
* Constant used for <code>registerKeyboardAction</code> that
* means that the command should be invoked when
* the receiving component is in the window that has the focus
* or is itself the focused component.
*/
public static final int WHEN_IN_FOCUSED_WINDOW = 2;
I am using KeyBinders to allow the user to type out numbers as well instead of having to manually press the buttons
不要为每个键绑定创建唯一的操作。您可以轻松创建一个由所有号码共享的操作:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(50, 50) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
// UIManager.put("Button.margin", new Insets(10, 10, 10, 10) );
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
我正在尝试创建一个计算器,我正在使用 KeyBinders 来允许用户输入数字,而不必手动按下按钮。但是,我注意到在我用鼠标按下其中一个按钮之后,KeyBinders 才会工作。这是我的代码:
import java.awt.*;
...
public class Calculator extends JFrame {
static JFrame f = new JFrame();
static JPanel p = new JPanel();
static JButton[] b = new JButton[19];
static String[] bs = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
".", "+", "-", "*", "/", "=", "C", "\u2190", "\u00B1" };
static JTextArea t = new JTextArea();
public static void main(String[] args) {
f.setSize(300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
for (int i = 0; i < b.length; i++) {
b[i] = new JButton();
b[i].setText(bs[i]);
b[i].addActionListener(new BAction());
b[i].setFont(new Font("Arial", Font.BOLD, 17));
b[i].setFocusable(true);
}
setLayout(p, b);
f.add(p);
f.setVisible(true);
}
public static JPanel setLayout(JPanel p, JButton[] b) {
Image icon = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
f.setIconImage(icon);
GridBagLayout g = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
p.setLayout(g);
p.setSize(f.getSize());
t.setEditable(false);
t.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
t.setFont(new Font("Arial", Font.PLAIN, 15));
t.setFocusable(false);
t.setText("0");
f.setFocusable(true);
p.setFocusable(true);
key();
...
// GridBagLayouting here
...
return p;
}
static class BAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
...
// Assigning ActionEventListeners
...
}
@SuppressWarnings({ "serial" })
private static void key() {
// 0
Action b0 = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[0].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "b0");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), "b0");
p.getActionMap().put("b0", b0);
// 1
Action b1 = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[1].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD1, 0), "b1");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), "b1");
p.getActionMap().put("b1", b1);
// 2
Action b2 = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[2].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, 0), "b2");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_2, 0), "b2");
p.getActionMap().put("b2", b2);
// +
Action bplus = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
b[11].doClick();
}
};
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), "b+");
p.getInputMap(JPanel.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS,
InputEvent.SHIFT_MASK), "b+");
p.getActionMap().put("b+", bplus);
}
}
您可以在创建绑定时使用 WHEN_IN_FOCUSED_WINDOW
而不是 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
。
更新
/**
* Constant used for <code>registerKeyboardAction</code> that
* means that the command should be invoked when the receiving
* component is an ancestor of the focused component or is
* itself the focused component.
*/
public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1;
/**
* Constant used for <code>registerKeyboardAction</code> that
* means that the command should be invoked when
* the receiving component is in the window that has the focus
* or is itself the focused component.
*/
public static final int WHEN_IN_FOCUSED_WINDOW = 2;
I am using KeyBinders to allow the user to type out numbers as well instead of having to manually press the buttons
不要为每个键绑定创建唯一的操作。您可以轻松创建一个由所有号码共享的操作:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
@Override
public void actionPerformed(ActionEvent e)
{
display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(50, 50) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
// UIManager.put("Button.margin", new Insets(10, 10, 10, 10) );
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}