tags:

views:

155

answers:

4

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.
+1  A: 

The code works just fine I guess.

e-kayrakli
+3  A: 

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.

Noel Ang
I've tested the code on 2 machines (XP, Windows 7) using NetBeans 6.8 and in the command line on Java 1.6.0_18 b07.Here is a screenshot after I have hovered over serveral buttons:http://imgur.com/Mqq1D.png
Anarchist
If you could make the compiled program downloadable from somewhere, we could run/decompile it to look for other causes.
Noel Ang
Thanks I have added a comment to the parent with a link to the class files.
Anarchist
Problem reproduced. See my revised answer for an explanation.
Noel Ang
Code and problem fixed. Thank you!!!
Anarchist
+1 Nice catch Noel
Jason Nichols
+1  A: 

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);
            }
        });
    }
}
trashgod
I'm still in the process of Java and haven't started using lists as of yet. However the main purpose of the array was just to place the keys elegantly in the style of a standard ATM.What imports are required in order to compile the code you have posted?
Anarchist
Imports added. I've become dependent on the typical IDE's `fix imports` command.
trashgod
+1  A: 

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

Carlos Heuberger