1

I am trying to make buttons change color when pressed. I have created the following code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class KeyboardTest extends JFrame {

    public static void main(String[] args) {
        new KeyboardTest();
    }

public KeyboardTest() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            } catch (Exception ex) {
                try {
                    UIManager.setLookAndFeel(UIManager
                            .getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
                    e.printStackTrace();
                }
            }
            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new TestPane());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.setBounds(100, 100, 650, 390);
        }
    });

}

public class TestPane extends JPanel {

    public TestPane() {
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        add(contentPane);
        contentPane.setLayout(null);

        JPanel keyboardPanel = new JPanel();
        keyboardPanel.setBounds(10, 122, 614, 181);
        contentPane.add(keyboardPanel);
        keyboardPanel.setLayout(new GridLayout(5, 0, 0, 0));

        ... adding panels and buttons...

        addKeyBinding(A, "A", KeyEvent.VK_A);
        addKeyBinding(B, "B", KeyEvent.VK_B);
        addKeyBinding(C, "C", KeyEvent.VK_C);
        addKeyBinding(D, "D", KeyEvent.VK_D);
        addKeyBinding(E, "E", KeyEvent.VK_E);

    }

    protected void addKeyBinding(JButton btn, String name, int virtualKey) {
        ActionMap am = getActionMap();
        InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);

        im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name
                + ".pressed");
        im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name
                + ".released");

        am.put(name + ".pressed", new KeyAction(btn, true));
        am.put(name + ".released", new KeyAction(btn, false));
    }

}

public class KeyAction extends AbstractAction {

    private JButton btn;
    private boolean highlight;

    public KeyAction(JButton btn, boolean highlight) {
        this.btn = btn;
        this.highlight = highlight;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (highlight) {
            btn.getModel().setPressed(true);
            btn.setBackground(Color.RED);
            btn.setOpaque(true);
        } else {
            btn.getModel().setPressed(false);
            btn.setBackground(null);
            btn.setOpaque(false);
        }
    }

}

}

Here is what it's supposed to look like:

enter image description here

Here is what actually appears:

enter image description here

Should I attach the full code? (it's pretty long...)

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720

1 Answers1

1

Can't test your code (because of your missing components). And I won't get on you about the null layout. But here's a problem and a solution, based on what I was able to test (using my own components).

  • I see a useless JPanel contentPane. The class you're using is already a panel, I don't see the point to create another one, and then wrap it in another one. (Not the whole problem though)

  • The class TestPane has a default FlowLayout, which means that it will respect the preferred size of the components inside, which is the contentPane panel. The problem with that is that it will have no preferred size. You are set the button sizes by using setBounds. This is not the same as preferredSize. So the there is no preferred size for the TestPane panel to calculate.

  • Simple fix is to set the layout of the TestPane to BorderLayout. This will not take preferred size into account, and will stretch the contentPane so you can see it. Problem with this though is that you need to set the size of the frame. pack() won't work, because the whole preferred size deal. That's why you frame blinks when you first open it, because it's first shrunk, and then you expand it with setBounds.

Again like I said though in my comment, I'd stay away from the null layouts (for many reasons). You can see a good example of a keyboard using GridBagLayout here as posted in my comment, from the mad man himself @MadProgrammer

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720