Ashley
Ashley

Reputation: 2318

JButtons re-enable themselves after being disabled

I have an array of JButtons which form a keypad interface. After six numbers are entered I want to disable the keypad so that no further numbers can be entered by the user.

I have written the code and the buttons do disable until the mouse hovers above any of them, then the buttons seem to re-enable themselves and run actionEvents added to them.

The full code is available here.

Possible things that I think are wrong.

  1. There is some sort of MouseListener which is ignoring when I set button.setEnabled(false);
  2. I haven't separated attributes from the buildGUI(); correctly, I only did this anyway so that the inner class could access them.
  3. Possibly something to do with the gridLayout as disabling the buttons seems to work for my services JPanel buttons.

Upvotes: 0

Views: 794

Answers (4)

user85421
user85421

Reputation: 29680

Examining the class files was helpful! The problem is in the Driver class: the buildGUI() method is being called 2 times: once in the constructor of CashMachine and second in the main method after calling the constructor.

public static void main(String args[])
{
    CashMachine cashmachine = new CashMachine();
    cashmachine.buildGUI();
}

This way you end up with the double number of buttons, that is, a pair of buttons at each position. But only one of each is being disabled.
Just remove the call to buildGUI from main (or from the constructor).
(I would change buildGUI to private as it should not be called from outside the class...)

Upvotes: 1

trashgod
trashgod

Reputation: 205775

One possible source of confusion in your program is mixing number keys with control keys, Clear and Enter. Consider handling number keys separately with a single listener, as suggested in the NumberButton class shown below. Then you can handle the Clear and Enter buttons as desired. Also, using a List<NumberButton> makes the enable and disable loops easier.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class KeyPadPanel extends JPanel implements ActionListener {

    private static final int MAX = 6;
    private final List<NumberButton> numbers = new ArrayList<NumberButton>();
    private final JTextArea text = new JTextArea(1, MAX);
    private final JButton clear = new JButton("Clear");
    private final JButton enter = new JButton("Enter");

    public KeyPadPanel() {
        super(new BorderLayout());

        JPanel display = new JPanel();
        text.setEditable(false);
        display.add(text);
        this.add(display, BorderLayout.NORTH);

        JPanel pad = new JPanel(new GridLayout(4, 4));
        for (int i = 0; i < 10; i++) {
            NumberButton n = new NumberButton(i);
            numbers.add(n);
            if (i > 0) {
                pad.add(n);
            }
        }
        pad.add(clear);
        pad.add(numbers.get(0));
        pad.add(enter);
        clear.addActionListener(this);
        enter.addActionListener(this);
        this.add(pad, BorderLayout.CENTER);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        text.setText("");
        enableButtons();
    }

    private void enableButtons() {
        for (NumberButton n : numbers) {
            n.setEnabled(true);
        }
    }

    private void disableButtons() {
        for (NumberButton n : numbers) {
            n.setEnabled(false);
        }
    }

    private class NumberButton extends JButton implements ActionListener {

        public NumberButton(int number) {
            super(String.valueOf(number));
            this.addActionListener(this);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            NumberButton b = (NumberButton) e.getSource();
            if (text.getText().length() < MAX) {
                text.append(b.getText());
            }
            if (text.getText().length() == MAX) {
                disableButtons();
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new KeyPadPanel());
                f.pack();
                f.setVisible(true);
            }
        });
    }
}

Upvotes: 1

Noel Ang
Noel Ang

Reputation: 5099

The problem lies in how you instantiated your Frame (CashMachine), not (directly) with its implementation.

You are calling buildGUI twice, one in the object's constructor, and then in the Driver class that instantiates the object. As a result, you are creating (and laying out) two sets of buttons.

When the buttons of the first set were eventually disabled, your mousing activity was revealing the second set of buttons. And a flaw in your ActionListener implementation can cause inputCount to take on values greater than 6, so buttons in the second set were not eventually disabled like those from the first set.

buildGUI should be private; it should be called in the CashMachine constructor, and not by your Driver class.

Conversely, in my opinion, CashMachine.setVisible should be called by the Driver class, and not by the CashMachine constructor.

Upvotes: 3

Engin Kayraklioglu
Engin Kayraklioglu

Reputation: 595

The code works just fine I guess.

Upvotes: 1

Related Questions