简体   繁体   English

从按钮/鼠标释放中调用Java AbstractAction

[英]Calling a Java AbstractAction from a button/mouse release

In a simple calculator app, I use abstract actions to handle the buttons being clicked with the mouse and the respective number pad keys (with key bindings) being pressed. 在一个简单的计算器应用程序中,我使用抽象操作来处理用鼠标单击的按钮以及相应的数字键盘按键(带有键绑定)。 I wanted certain cosmetic changes to occur upon using the keyboard, such as changing the border of JButton number 1 when I press the number 1 key. 我希望在使用键盘时进行某些外观上的更改,例如在按数字1键时更改数字1的JButton的边框。 And changing it back upon release. 并在发布时将其更改回。 This all works. 所有这一切。 Then I went and started pressing the JButtons with my mouse again and realized that the key released action never gets invoked, obviously because I'm not using the keybinding. 然后,我又开始用鼠标再次按下JButton,并意识到从不调用键释放操作,这显然是因为我没有使用键绑定。 So my question is, is there a way to invoke the appropriate released abstract action when the mouse release/button raises? 所以我的问题是,有一种方法可以在鼠标释放/按钮抬起时调用适当的释放抽象动作?

When I discovered this, I initially tried this: 当我发现这个时,我最初尝试了这个:

Abstract action(){
set border to this..
code..
code..
code..
set border to this..
}

So no matter if the key or the mouse, it would change. 因此,无论键还是鼠标,它都会改变。 However it doesn't change, or probably goes so fast it's undetectable. 但是,它没有改变,或者运行得如此之快以至于无法检测。

It doesn't make sense to register a mouse listener in this instance. 在这种情况下,注册鼠标侦听器没有任何意义。 I tried this anyway and I cannot seem to register the abstract action as a mouse listener. 无论如何,我还是尝试过,但似乎无法将抽象操作注册为鼠标侦听器。

Thanks for your input and ideas. 感谢您的意见和建议。

I register actionlistener: 我注册动作侦听器:

    btnMultiplication.addActionListener( operatorAction );
    btnDivision.addActionListener( operatorAction );
    btnAddition.addActionListener( operatorAction );
    btnSubtraction.addActionListener( operatorAction );
    btnSix.addActionListener( numberAction );
    btnSeven.addActionListener( numberAction );
    btnEight.addActionListener( numberAction );

the *Action's are abstract actions *动作是抽象动作

I use this for keyboard input 我用它来输入键盘

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

I used the Number action to change the border of the respective jbutton. 我使用Number动作来更改相应jbutton的边框。 Then I use Number Released to change the border again. 然后,我使用数字下达来再次更改边框。

Obviously, when I click with the mouse, the border highlights. 显然,当我用鼠标单击时,边框会突出显示。 But the Number Released doesn't invoke. 但是释放号码不会调用。 Like I stated, eliminating the released aspect all together and putting the first border change at the start of the abstract action and then the final border change at the end of the abstract action evidently goes so fast you cannot see the border change. 就像我说过的,消除所有释放的方面,将第一个边界更改放在抽象动作的开始,然后将最后一个边界更改放在抽象动作的结尾,显然进行得如此之快,以至于看不到边界的变化。

One thing that many people miss when dealing with key bindings, is the fact that you can register for either a "press" or "release" event (press been the default). 很多人在处理键绑定时会错过的一件事是,您可以注册“ press”或“ release”事件(press是默认设置)。 So in your case, you need to do both. 因此,在您的情况下,您需要同时执行这两项操作。 The "press" event should "arm" AND "press" the button, the "release" should "unpress" and "unarm" the button (the order is important), for example... “按下”事件应“布防”并“按下”按钮,“释放”应“松开”并“解除”按钮(顺序很重要),例如...

I would also change your focus. 我也会改变你的重点。 Instead of having the key bindings trigger the desired action, have the JButton Action do this, this will allow you to focus on having the key bindings change the state of the button, preferably through the use of the button model, which will allow the button to be triggered and the associated Action called. 不必让按键绑定触发所需的动作,而是让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);
                }
            }

        }

    }

}

So, I wanted to post my implementation that worked, based on the chosen solution given by MadProgrammer . 因此,我想根据MadProgrammer提供的选定解决方案发布有效的实现

I removed explicit creation of the jbuttons. 我删除了jbutton的显式创建。 I now create them like this: 我现在这样创建它们:

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

The createButton method does this: 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 ) );

As you can see, I create my instances as MadProgrammer has shown in his example and created references to the AbstractActions. 如您所见,我按照MadProgrammer在其示例中显示的方式创建了实例,并创建了对AbstractActions的引用。 I then set the properties for the various swing attributes and then the border and background. 然后,我设置各种挥杆属性的属性,然后设置边框和背景。 This reduces the code and variable usage greatly. 这大大减少了代码和变量的使用。 A side note. 旁注。 The parameter name in createButton and its use to name the button are no longer used and will be removed. createButton中的参数名称及其用于命名按钮的用法不再使用,将被删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM