从 button/mouse 版本调用 Java AbstractAction
Calling a Java AbstractAction from a button/mouse release
在一个简单的计算器应用程序中,我使用抽象操作来处理用鼠标单击的按钮和按下相应的数字键盘键(具有键绑定)。我希望在使用键盘时发生某些外观上的变化,例如当我按下数字 1 键时更改 JButton 数字 1 的边框。并在发布时将其改回。这一切都有效。然后我开始再次用我的鼠标按下 JButtons 并意识到按键释放动作永远不会被调用,显然是因为我没有使用键绑定。所以我的问题是,有没有办法在鼠标 release/button 抬起时调用适当的释放抽象操作?
当我发现这一点时,我最初尝试了这个:
Abstract action(){
set border to this..
code..
code..
code..
set border to this..
}
所以无论是按键还是鼠标,都会发生变化。然而它并没有改变,或者可能变得如此之快以至于无法检测到。
在这种情况下注册鼠标侦听器没有意义。无论如何我都试过了,但我似乎无法将抽象动作注册为鼠标侦听器。
感谢您的意见和想法。
我注册了actionlistener:
btnMultiplication.addActionListener( operatorAction );
btnDivision.addActionListener( operatorAction );
btnAddition.addActionListener( operatorAction );
btnSubtraction.addActionListener( operatorAction );
btnSix.addActionListener( numberAction );
btnSeven.addActionListener( numberAction );
btnEight.addActionListener( numberAction );
*Action 是抽象动作
我用这个做键盘输入
im.put( KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD0, 0, false ), "Number" );
im.put( KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD0, 0, true ), "Number Released" );
am.put( "Number", numberAction );
am.put( "Number Released", numberActionR );
我使用 Number 操作来更改相应 jbutton 的边框。然后我用Number Released再次更改边框。
很明显,当我用鼠标点击时,边框高亮显示。但是 Number Released 不会调用。就像我说的那样,一起消除已发布的方面,并将第一个边界更改放在 抽象操作 的开头,然后将最终的边界更改放在 摘要的末尾action 显然进行得如此之快以至于你看不到边框的变化。
许多人在处理键绑定时会忽略的一件事是,您可以注册 "press" 或 "release" 事件(默认为按下)。所以在你的情况下,你需要做这两件事。 "press" 事件应该 "arm" 和 "press" 按钮,"release" 应该 "unpress" 和 "unarm" 按钮(顺序很重要),因为例如...
我也会改变你的关注点。让 JButton
Action
执行此操作,而不是让键绑定触发所需的操作,这将使您可以专注于让键绑定更改按钮的状态,最好是通过使用按钮模型,它将允许触发按钮并调用关联的 Action
。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.NAME;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridLayout(4, 3));
add(createButton(7, KeyEvent.VK_7, KeyEvent.VK_NUMPAD7));
add(createButton(8, KeyEvent.VK_8, KeyEvent.VK_NUMPAD8));
add(createButton(9, KeyEvent.VK_9, KeyEvent.VK_NUMPAD9));
add(createButton(4, KeyEvent.VK_4, KeyEvent.VK_NUMPAD4));
add(createButton(5, KeyEvent.VK_5, KeyEvent.VK_NUMPAD5));
add(createButton(6, KeyEvent.VK_6, KeyEvent.VK_NUMPAD6));
add(createButton(1, KeyEvent.VK_1, KeyEvent.VK_NUMPAD1));
add(createButton(2, KeyEvent.VK_2, KeyEvent.VK_NUMPAD2));
add(createButton(3, KeyEvent.VK_3, KeyEvent.VK_NUMPAD3));
add(createButton(0, KeyEvent.VK_0, KeyEvent.VK_NUMPAD0));
}
protected JButton createButton(int number, int... virtualKeys) {
NumberAction na = new NumberAction(Integer.toString(number));
JButton btn = new JButton(na);
InputMap im = btn.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = btn.getActionMap();
for (int virtualKey : virtualKeys) {
im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), "number-pressed");
im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), "number-released");
}
am.put("number-pressed", new NumberKeyPressedAction(btn, true));
am.put("number-released", new NumberKeyPressedAction(btn, false));
return btn;
}
public class NumberAction extends AbstractAction {
public NumberAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(getValue(NAME) + " was clicked");
}
}
public class NumberKeyPressedAction extends AbstractAction {
private final JButton btn;
private final boolean pressed;
public NumberKeyPressedAction(JButton btn, boolean pressed) {
// You could just pass the button model, but this was easier...
this.btn = btn;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
btn.getModel().setArmed(pressed);
btn.getModel().setPressed(pressed);
} else {
btn.getModel().setPressed(pressed);
btn.getModel().setArmed(pressed);
}
}
}
}
}
所以,我想 post 根据 MadProgrammer.
给出的所选解决方案,我的实现是有效的
我删除了 jbutton 的显式创建。我现在这样创建它们:
createButton( 3, 5, 1, 1, ".", "btnDecimal", KeyEvent.VK_DECIMAL );
createButton( 1, 5, 1, 2, "0", "btnZero", KeyEvent.VK_0, KeyEvent.VK_NUMPAD0 );
createButton( 1, 4, 1, 1, "1", "btnOne", KeyEvent.VK_1, KeyEvent.VK_NUMPAD1 );
createButton( 2, 4, 1, 1, "2", "btnTwo", KeyEvent.VK_2, KeyEvent.VK_NUMPAD2 );
createButton( 3, 4, 1, 1, "3", "btnThree", KeyEvent.VK_3, KeyEvent.VK_NUMPAD3 );
createButton( 1, 3, 1, 1, "4", "btnFour", KeyEvent.VK_4, KeyEvent.VK_NUMPAD4 );
createButton( 2, 3, 1, 1, "5", "btnFive", KeyEvent.VK_5, KeyEvent.VK_NUMPAD5 );
createButton( 3, 3, 1, 1, "6", "btnSix", KeyEvent.VK_6, KeyEvent.VK_NUMPAD6 );
createButton( 1, 2, 1, 1, "7", "btnSeven", KeyEvent.VK_7, KeyEvent.VK_NUMPAD7 );
createButton( 2, 2, 1, 1, "8", "btnEight", KeyEvent.VK_8, KeyEvent.VK_NUMPAD8 );
createButton( 3, 2, 1, 1, "9", "btnNine", KeyEvent.VK_9, KeyEvent.VK_NUMPAD9 );
createButton 方法执行此操作:
private void createButton( int x, int y, int h, int w, String actionCommand, String name, int... keys ) {
nAction na = new nAction( actionCommand );
JButton btn = new JButton( na );
btn.setName( name );
InputMap im = btn.getInputMap( WHEN_IN_FOCUSED_WINDOW );
ActionMap am = btn.getActionMap();
for ( int virtualKey : keys ) {
im.put( KeyStroke.getKeyStroke( virtualKey, 0, false ), "number-pressed" );
im.put( KeyStroke.getKeyStroke( virtualKey, 0, true ), "number-released" );
}
am.put( "number-pressed", new NumberKeyPressedAction( btn, true ) );
am.put( "number-released", new NumberKeyPressedAction( btn, false ) );
GridBagConstraints gbc_btn = new GridBagConstraints();
// gbc_btnEquals.anchor = GridBagConstraints.WEST;
gbc_btn.fill = GridBagConstraints.BOTH;
gbc_btn.insets = new Insets( 0, 0, 5, 5 );
gbc_btn.gridheight = h;
gbc_btn.gridwidth = w;
gbc_btn.gridx = x;
gbc_btn.gridy = y;
frame.getContentPane().add( btn, gbc_btn );
btn.setBackground( new Color( 225, 225, 225 ) );
btn.setBorder( BorderFactory.createLineBorder( Color.BLACK ) );
如您所见,我创建了我的实例,正如 MadProgrammer 在他的示例中所展示的那样,并创建了对 AbstractActions 的引用。然后我设置各种 swing 属性的属性,然后是边框和背景。这大大减少了代码和变量的使用。旁注。 createButton 中的参数 name 及其命名按钮的用途不再使用,将被删除。
在一个简单的计算器应用程序中,我使用抽象操作来处理用鼠标单击的按钮和按下相应的数字键盘键(具有键绑定)。我希望在使用键盘时发生某些外观上的变化,例如当我按下数字 1 键时更改 JButton 数字 1 的边框。并在发布时将其改回。这一切都有效。然后我开始再次用我的鼠标按下 JButtons 并意识到按键释放动作永远不会被调用,显然是因为我没有使用键绑定。所以我的问题是,有没有办法在鼠标 release/button 抬起时调用适当的释放抽象操作?
当我发现这一点时,我最初尝试了这个:
Abstract action(){
set border to this..
code..
code..
code..
set border to this..
}
所以无论是按键还是鼠标,都会发生变化。然而它并没有改变,或者可能变得如此之快以至于无法检测到。
在这种情况下注册鼠标侦听器没有意义。无论如何我都试过了,但我似乎无法将抽象动作注册为鼠标侦听器。
感谢您的意见和想法。
我注册了actionlistener:
btnMultiplication.addActionListener( operatorAction );
btnDivision.addActionListener( operatorAction );
btnAddition.addActionListener( operatorAction );
btnSubtraction.addActionListener( operatorAction );
btnSix.addActionListener( numberAction );
btnSeven.addActionListener( numberAction );
btnEight.addActionListener( numberAction );
*Action 是抽象动作
我用这个做键盘输入
im.put( KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD0, 0, false ), "Number" );
im.put( KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD0, 0, true ), "Number Released" );
am.put( "Number", numberAction );
am.put( "Number Released", numberActionR );
我使用 Number 操作来更改相应 jbutton 的边框。然后我用Number Released再次更改边框。
很明显,当我用鼠标点击时,边框高亮显示。但是 Number Released 不会调用。就像我说的那样,一起消除已发布的方面,并将第一个边界更改放在 抽象操作 的开头,然后将最终的边界更改放在 摘要的末尾action 显然进行得如此之快以至于你看不到边框的变化。
许多人在处理键绑定时会忽略的一件事是,您可以注册 "press" 或 "release" 事件(默认为按下)。所以在你的情况下,你需要做这两件事。 "press" 事件应该 "arm" 和 "press" 按钮,"release" 应该 "unpress" 和 "unarm" 按钮(顺序很重要),因为例如...
我也会改变你的关注点。让 JButton
Action
执行此操作,而不是让键绑定触发所需的操作,这将使您可以专注于让键绑定更改按钮的状态,最好是通过使用按钮模型,它将允许触发按钮并调用关联的 Action
。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import static javax.swing.Action.NAME;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridLayout(4, 3));
add(createButton(7, KeyEvent.VK_7, KeyEvent.VK_NUMPAD7));
add(createButton(8, KeyEvent.VK_8, KeyEvent.VK_NUMPAD8));
add(createButton(9, KeyEvent.VK_9, KeyEvent.VK_NUMPAD9));
add(createButton(4, KeyEvent.VK_4, KeyEvent.VK_NUMPAD4));
add(createButton(5, KeyEvent.VK_5, KeyEvent.VK_NUMPAD5));
add(createButton(6, KeyEvent.VK_6, KeyEvent.VK_NUMPAD6));
add(createButton(1, KeyEvent.VK_1, KeyEvent.VK_NUMPAD1));
add(createButton(2, KeyEvent.VK_2, KeyEvent.VK_NUMPAD2));
add(createButton(3, KeyEvent.VK_3, KeyEvent.VK_NUMPAD3));
add(createButton(0, KeyEvent.VK_0, KeyEvent.VK_NUMPAD0));
}
protected JButton createButton(int number, int... virtualKeys) {
NumberAction na = new NumberAction(Integer.toString(number));
JButton btn = new JButton(na);
InputMap im = btn.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = btn.getActionMap();
for (int virtualKey : virtualKeys) {
im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), "number-pressed");
im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), "number-released");
}
am.put("number-pressed", new NumberKeyPressedAction(btn, true));
am.put("number-released", new NumberKeyPressedAction(btn, false));
return btn;
}
public class NumberAction extends AbstractAction {
public NumberAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(getValue(NAME) + " was clicked");
}
}
public class NumberKeyPressedAction extends AbstractAction {
private final JButton btn;
private final boolean pressed;
public NumberKeyPressedAction(JButton btn, boolean pressed) {
// You could just pass the button model, but this was easier...
this.btn = btn;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
btn.getModel().setArmed(pressed);
btn.getModel().setPressed(pressed);
} else {
btn.getModel().setPressed(pressed);
btn.getModel().setArmed(pressed);
}
}
}
}
}
所以,我想 post 根据 MadProgrammer.
给出的所选解决方案,我的实现是有效的我删除了 jbutton 的显式创建。我现在这样创建它们:
createButton( 3, 5, 1, 1, ".", "btnDecimal", KeyEvent.VK_DECIMAL );
createButton( 1, 5, 1, 2, "0", "btnZero", KeyEvent.VK_0, KeyEvent.VK_NUMPAD0 );
createButton( 1, 4, 1, 1, "1", "btnOne", KeyEvent.VK_1, KeyEvent.VK_NUMPAD1 );
createButton( 2, 4, 1, 1, "2", "btnTwo", KeyEvent.VK_2, KeyEvent.VK_NUMPAD2 );
createButton( 3, 4, 1, 1, "3", "btnThree", KeyEvent.VK_3, KeyEvent.VK_NUMPAD3 );
createButton( 1, 3, 1, 1, "4", "btnFour", KeyEvent.VK_4, KeyEvent.VK_NUMPAD4 );
createButton( 2, 3, 1, 1, "5", "btnFive", KeyEvent.VK_5, KeyEvent.VK_NUMPAD5 );
createButton( 3, 3, 1, 1, "6", "btnSix", KeyEvent.VK_6, KeyEvent.VK_NUMPAD6 );
createButton( 1, 2, 1, 1, "7", "btnSeven", KeyEvent.VK_7, KeyEvent.VK_NUMPAD7 );
createButton( 2, 2, 1, 1, "8", "btnEight", KeyEvent.VK_8, KeyEvent.VK_NUMPAD8 );
createButton( 3, 2, 1, 1, "9", "btnNine", KeyEvent.VK_9, KeyEvent.VK_NUMPAD9 );
createButton 方法执行此操作:
private void createButton( int x, int y, int h, int w, String actionCommand, String name, int... keys ) {
nAction na = new nAction( actionCommand );
JButton btn = new JButton( na );
btn.setName( name );
InputMap im = btn.getInputMap( WHEN_IN_FOCUSED_WINDOW );
ActionMap am = btn.getActionMap();
for ( int virtualKey : keys ) {
im.put( KeyStroke.getKeyStroke( virtualKey, 0, false ), "number-pressed" );
im.put( KeyStroke.getKeyStroke( virtualKey, 0, true ), "number-released" );
}
am.put( "number-pressed", new NumberKeyPressedAction( btn, true ) );
am.put( "number-released", new NumberKeyPressedAction( btn, false ) );
GridBagConstraints gbc_btn = new GridBagConstraints();
// gbc_btnEquals.anchor = GridBagConstraints.WEST;
gbc_btn.fill = GridBagConstraints.BOTH;
gbc_btn.insets = new Insets( 0, 0, 5, 5 );
gbc_btn.gridheight = h;
gbc_btn.gridwidth = w;
gbc_btn.gridx = x;
gbc_btn.gridy = y;
frame.getContentPane().add( btn, gbc_btn );
btn.setBackground( new Color( 225, 225, 225 ) );
btn.setBorder( BorderFactory.createLineBorder( Color.BLACK ) );
如您所见,我创建了我的实例,正如 MadProgrammer 在他的示例中所展示的那样,并创建了对 AbstractActions 的引用。然后我设置各种 swing 属性的属性,然后是边框和背景。这大大减少了代码和变量的使用。旁注。 createButton 中的参数 name 及其命名按钮的用途不再使用,将被删除。