我在Java程序中实现多个动作侦听器时遇到了问题。该程序是一个使用基本GUI执行基本功能的计算器。根据我的研究,我注意到动作听众应该进入不同的班级。我已经组成了我的四个动作监听器的程序,但是每次运行程序时都会遇到大量的错误以及每个动作监听器的警告说"可序列化类ClearListener没有声明类型的静态最终serialVersionUID字段长"对此的任何帮助将不胜感激。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GUICalc extends JPanel {
private static final long serialVersionUID = 1L;
JButton[] numberButtons;
JButton[] upButtons;
JTextField field;
double num1;
double num2;
double ans;
int op;
DigitalListener listener1 = new DigitalListener();
OperatorListener listener2 = new OperatorListener();
ClearListener listerner3 = new ClearListener();
EqualsListener listerner4 = new EqualsListener();
// 0 = gridx 1 gridy 2 gridwidth 3 gridheight
private int[][] numConstraints = new int[][] {
{0, 4, 1, 1},
{0, 1, 1, 1},
{1, 1, 1, 1},
{2, 1, 1, 1},
{0, 2, 1, 1},
{1, 2, 1, 1},
{2, 2, 1, 1},
{0, 3, 1, 1},
{1, 3, 1, 1},
{2, 3, 1, 1},
};
private int[][] upConstraints = new int[][] {
{1, 4, 1, 1},
{3, 4, 1, 1},
{3, 3, 1, 1},
{3, 2, 1, 1},
{3, 1, 1, 1},
{0, 5, 4, 1},
{2, 4, 1, 1},
};
public GUICalc() {
setPreferredSize(new Dimension(666, 666)); //width & heigth
GridBagLayout layout; // used to be private
GridBagConstraints gbc; // used to be private
layout = new GridBagLayout();
layout.columnWidths = new int[] {60, 60, 60, 60};
layout.rowHeights = new int[] {60, 60, 60, 60, 60, 60};
setLayout(layout);
gbc = new GridBagConstraints();
numberButtons = new JButton[10];
numberButtons[0] = new JButton("0");
numberButtons[1] = new JButton("1");
numberButtons[2] = new JButton("2");
numberButtons[3] = new JButton("3");
numberButtons[4] = new JButton("4");
numberButtons[5] = new JButton("5");
numberButtons[6] = new JButton("6");
numberButtons[7] = new JButton("7");
numberButtons[8] = new JButton("8");
numberButtons[9] = new JButton("9");
for(int i = 0; i < numberButtons.length; i++){
gbc.gridx = numConstraints[i][0];
gbc.gridy = numConstraints[i][1];
gbc.gridwidth = numConstraints[i][2];
gbc.gridheight = numConstraints[1][3];
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(2, 2, 2, 2);
numberButtons[i].addActionListener(listener1);
add(numberButtons[i], gbc);
}
upButtons = new JButton[7];
upButtons[0] = new JButton(".");
upButtons[1] = new JButton("/");
upButtons[2] = new JButton("*");
upButtons[3] = new JButton("-");
upButtons[4] = new JButton("+");
upButtons[5] = new JButton("=");
upButtons[6] = new JButton("C");
gbc.gridx = upConstraints[0][0];
gbc.gridy = upConstraints[0][1];
gbc.gridwidth = upConstraints[0][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[0].addActionListener(listener2);
add(upButtons[0], gbc);
gbc.gridx = upConstraints[1][0];
gbc.gridy = upConstraints[1][1];
gbc.gridwidth = upConstraints[1][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[1].addActionListener(listener2);
add(upButtons[1], gbc);
gbc.gridx = upConstraints[2][0];
gbc.gridy = upConstraints[2][1];
gbc.gridwidth = upConstraints[2][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[2].addActionListener(listener2);
add(upButtons[2], gbc);
gbc.gridx = upConstraints[3][0];
gbc.gridy = upConstraints[3][1];
gbc.gridwidth = upConstraints[3][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[3].addActionListener(listener2);
add(upButtons[3], gbc);
gbc.gridx = upConstraints[4][0];
gbc.gridy = upConstraints[4][1];
gbc.gridwidth = upConstraints[4][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[4].addActionListener(listener2);
add(upButtons[4], gbc);
gbc.gridx = upConstraints[5][0];
gbc.gridy = upConstraints[5][1];
gbc.gridwidth = upConstraints[5][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[5].addActionListener(listerner4);
add(upButtons[5], gbc);
gbc.gridx = upConstraints[6][0];
gbc.gridy = upConstraints[6][1];
gbc.gridwidth = upConstraints[6][2];
gbc.gridheight = upConstraints[1][3];
gbc.insets = new Insets(2, 2, 2, 2);
upButtons[6].addActionListener(listerner3);
add(upButtons[6], gbc);
field = new JTextField();
field.setBorder(BorderFactory.createLineBorder(Color.BLACK));
field.setEditable(false);
field.setFont(new Font("Arial",Font.PLAIN, 24));
field.setText(null);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 4;
gbc.gridheight = 1;
add(field, gbc);
}
public static void main(String [] args){
JFrame frame = new JFrame("Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLayout(new BorderLayout());
frame.add(new GUICalc(), BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class DigitalListener extends GUICalc implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == numberButtons[0]){
field.setText(field.getText() + 0);
}
if(e.getSource() == numberButtons[1]){
field.setText(field.getText() + 1);
}
if(e.getSource() == numberButtons[2]){
field.setText(field.getText() + 2);
}
if(e.getSource() == numberButtons[3]){
field.setText(field.getText() + 3);
}
if(e.getSource() == numberButtons[4]){
field.setText(field.getText() + 4);
}
if(e.getSource() == numberButtons[5]){
field.setText(field.getText() + 5);
}
if(e.getSource() == numberButtons[6]){
field.setText(field.getText() + 6);
}
if(e.getSource() == numberButtons[7]){
field.setText(field.getText() + 7);
}
if(e.getSource() == numberButtons[8]){
field.setText(field.getText() + 8);
}
if(e.getSource() == numberButtons[9]){
field.setText(field.getText() + 9);
}
if(e.getSource() == upButtons[0] && !field.getText().contains(".")) {
field.setText(field.getText() + ".");
}
}
}
class OperatorListener extends GUICalc implements ActionListener {
@Override
public void actionPerformed(ActionEvent e){
if(e.getSource() == upButtons[1]) {
num1 = Integer.parseInt(field.getText());
op = 4;
field.setText("");
}
if(e.getSource() == upButtons[2]) {
num1 = Integer.parseInt(field.getText());
op = 3;
field.setText("");
}
if(e.getSource() == upButtons[3]) {
num1 = Integer.parseInt(field.getText());
op = 2;
field.setText("");
}
if(e.getSource() == upButtons[4]) {
num1 = Integer.parseInt(field.getText());
op = 1;
field.setText("");
}
}
}
class ClearListener extends GUICalc implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == upButtons[6]) {
field.setText("0.0");
}
}
}
class EqualsListener extends GUICalc implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == upButtons[5]) {
num2 = Integer.parseInt(field.getText());
if(op == 1){
ans = num1 + num2;
} else if(op == 2){
ans = num1 - num2;
} else if(op == 3){
ans = num1 * num2;
} else if(op == 4){
ans = num1 / num2;
}
op = 0;
field.setText("" + ans);
}
}
}
答案 0 :(得分:1)
很可能你得到Exception in thread "main" java.lang.StackOverflowError
这样做:
class OperatorListener implements ActionListener {
private GUICalc guiCalc;
public OperatorListener(GUICalc guiCalc){
this.guiCalc=guiCalc;
}
// use guiCalc to refer the values
...
}
并在GUICalc.java
OperatorListener listener2 = new OperatorListener(this);
对所有类型的自定义侦听器执行相同的操作。
您已在对象之间创建了循环依赖关系。
GUICalc
包含OperatorListener
public class GUICalc extends JPanel {
...
OperatorListener listener2 = new OperatorListener();
...
}
OperatorListener
正在扩展GUICalc
类
class OperatorListener extends GUICalc implements ActionListener {...}
现在每当GUICalc
超类对象构建时,它都会尝试创建依赖项子类对象,例如OperatorListener
,但是现在无法构造子类对象,除非超级对象创建了类对象。
答案 1 :(得分:1)
虽然第一个答案已被接受,但有一些提示:
“动作侦听器应该在不同的类中”的建议是正确的。但是,这并不意味着您应该将多个ActionListener任意组合到一个类中。虽然这是可能的,并且在某些情况下可能是可行的,但有些解决方案更适合像您这样的用例。
这可以帮助您稍微简化代码。 (如果我不得不清理它,我会从GridBagLayout和这些numConstraints
数组开始 - 我认为这些是可怕的 - 但这是一个不同的故事......)。特别是,您可以创建一个创建匿名ActionListener
的方法,如下所示:
private ActionListener createActionListener(final String string)
{
return new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
field.setText(field.getText() + string);
}
};
}
然后你可以创建这些监听器的实例并将它们添加到按钮:
for(int i = 0; i < numberButtons.length; i++)
{
...
numberButtons[i].addActionListener(
createActionListener(String.valueOf(i)));
}
(请注意,在最好的情况下,您甚至可能不必将numberButtons
数组存储为实例变量...)
类似的概念可以应用于操作按钮。一般来说,我认为使用匿名侦听器将特定方法调用“连接”到一个按钮是一个很好的做法,大概是这样的:
someButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
doSomething();
}
});
对于很多情况,使用Action
更为有用(参见http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html),但这至少在概念上是相似的,而不是让ActionListener
检查事件源或动作命令。