Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
173 views
in Technique[技术] by (71.8m points)

java - Can't figure out error with ActionListener

The following is my program. the goal is to convert from a roman numeral to an Arabic number after a user types in the numeral and presses the enter key.

This is a homework assignment and we are forced to user JTextAreas in lieu of JTextFields.

My error exists on the line: enterRomanNumber.addActionListener(handler); The error reads:

"The method addActionListener(ArabicToRomanGUI.HandlerForTextArea) is undefined for the type JTextArea"

I can't seem to figure out why I am getting this error or how to correct it, can someone please advise.

import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class ArabicToRomanGUI extends JFrame
{
private static final long serialVersionUID = 1L;
private JTextArea enterRomanNumber = new JTextArea();
JLabel label = new JLabel();
JPanel panel = new JPanel();
JFrame frame = new JFrame();


//TestArea contructor adds jtextArea to jframe
public ArabicToRomanGUI()
{
    super("Convert a Roman Numeral");
    setLayout(new FlowLayout());

    //Text field to enter a roman numeral
    enterRomanNumber = new JTextArea(1,25);
    enterRomanNumber.setText("Delete this text and Enter a Roman Numerial Here!");
    //enterRomanNumber.setAlignmentX(0);
    //enterRomanNumber.setAlignmentY(0);

    add(enterRomanNumber);

    HandlerForTextArea handler = new HandlerForTextArea();
    enterRomanNumber.addActionListener(handler);
}

private class HandlerForTextArea implements ActionListener
{
    //used to process textArea events
    @Override
    public void actionPerformed(ActionEvent e) 
    {
        String userInput = "";
        userInput = enterRomanNumber.getText();
        userInput = userInput.toUpperCase();

        ConversionLogic.ConvertFromRomanToArabic(userInput); //converts user string of Roman numerals to an int in arabic
        String arabicNumberAsString = ConversionLogic.getConvertedRomanNumeral();
        enterRomanNumber.setText(arabicNumberAsString);

        //user pressed enter in JTextField enterNumberField
        if(e.getSource() == enterRomanNumber)
        {
            //enterRomanNumber.setText(arabicNumberAsString);
            if (ConversionLogic.getCheckFail() == true)
            {
                JOptionPane.showMessageDialog(frame, "The Roman Numeral entered is Invalid", "Error", JOptionPane.ERROR_MESSAGE);
            }
            else
            {
                JOptionPane.showMessageDialog(frame, "The arabic equivalent is " + arabicNumberAsString + "." , "Conversion Successful", JOptionPane.PLAIN_MESSAGE);
            }
        }

    }
}
}//end inner class TextAreaHandler
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

KeyListeners are NEVER appropriate solutions to use with text components, if you want to be notified when a text component changes, you use a DocumentListener, if you want to change/filter what can be entered into a text component, you use a DocumentFilter, if you need to change a special key, like Enter, you should use a key binding

See How to Use Key Bindings for more details.

One of the problems you could have with KeyListener is not knowing when the key stroke is processed by the text component, in your case, it may not be a major issue, but it could change the way the program works on different platforms.

Instead, you can override the JTextArea's key binding for the Enter key (named insert-break). This provides you with the ability to actually change the behavior of the key stroke, or, in your case, manage how you process the event. For example, this replaces the Action for the text area's Enter key, but retains the previous/default behavior...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class KeyBindingsTest {

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

    public KeyBindingsTest() {
        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 {

        private JTextArea ta;

        public TestPane() {
            ta = new JTextArea(10, 20);
            ActionMap am = ta.getActionMap();

            Action proxy = am.get("insert-break");
            am.put("insert-break", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // You can process the event through the original action BEFORE
                    // you do your own processing
                    //proxy.actionPerformed(e);
                    System.out.println("You pressed the enter key, you can have candy");
                    // Or you can process the event through the original action AFTER
                    // you do your own processing, you have now gained control
                    proxy.actionPerformed(e);
                }
            });

            setLayout(new BorderLayout());
            add(ta);
        }

    }

}

Now, you could even go to the extent for creating your own JTextArea which supported ActionPerformed...

public class ActionableTextArea extends JTextArea {

    private String actionCommand;

    public ActionableTextArea() {
        installKeyBindings();
    }

    public ActionableTextArea(String text) {
        super(text);
        installKeyBindings();
    }

    public ActionableTextArea(int rows, int columns) {
        super(rows, columns);
        installKeyBindings();
    }

    public ActionableTextArea(String text, int rows, int columns) {
        super(text, rows, columns);
        installKeyBindings();
    }

    public ActionableTextArea(Document doc) {
        super(doc);
        installKeyBindings();
    }

    public ActionableTextArea(Document doc, String text, int rows, int columns) {
        super(doc, text, rows, columns);
        installKeyBindings();
    }

    protected void installKeyBindings() {
        ActionMap am = getActionMap();
        Action proxy = am.get("insert-break");
        am.put("insert-break", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                    // You can process the event through the original action BEFORE
                // you do your own processing
                //proxy.actionPerformed(e);
                fireActionPerformed();
                    // Or you can process the event through the original action AFTER
                // you do your own processing, you have now gained control
                proxy.actionPerformed(e);
            }
        });
    }

    public void addActionListener(ActionListener listener) {
        listenerList.add(ActionListener.class, listener);
    }

    public void removeActionListener(ActionListener listener) {
        listenerList.remove(ActionListener.class, listener);
    }

    public void setActionCommand(String actionCommand) {
        this.actionCommand = actionCommand;
    }

    public String getActionCommand() {
        return actionCommand;
    }

    protected void fireActionPerformed() {
        ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
        if (listeners.length > 0) {
            ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand());
            for (ActionListener listener : listeners) {
                listener.actionPerformed(evt);
            }
        }
    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...