简体   繁体   English

另一个类中的Java ActionListener-从主类访问对象

[英]Java ActionListener in another class - accessing objects from main class

i am writing a simple BMI calculator program. 我正在编写一个简单的BMI计算器程序。 The application includes ActionListener, which handles button click, check if textfields are filled in and executes calculations. 该应用程序包括ActionListener,它可以处理按钮单击,检查文本字段是否已填充并执行计算。

For now, the ActionListener method is as a subclass of a main class. 目前,ActionListener方法是作为主类的子类。 And it looks like this: 它看起来像这样:

BMICalc.java BMICalc.java

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
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.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class BMICalc extends JFrame {

    private JMenuBar menuBar1;
    private JMenu jMenu1;
    private JMenuItem jMenuItem1, jMenuItem2;
    private JButton jButton1;
    private JPanel mainPanel, jPanel1;
    private JLabel jLabel1, jLabel2;
    private JTextField jTextField1, jTextField2;


    private BMICalc() {

        super("BMI Calculator");

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(new Dimension(250, 300));
        setLocationRelativeTo(null);
        setLayout(new BorderLayout(10, 10));


        mainPanel = new JPanel(new BorderLayout(10, 10));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        add(mainPanel);

        jPanel1 = new JPanel(new GridLayout(6,2));
        mainPanel.add(jPanel1, BorderLayout.CENTER);

        menuBar1 = new JMenuBar();

            jMenu1 = new JMenu("Help");
            menuBar1.add(jMenu1);

                jMenuItem1 = new JMenuItem("The purpose");
                jMenu1.add(jMenuItem1);

                jMenuItem2 = new JMenuItem("About");
                jMenu1.add(jMenuItem2);

        setJMenuBar(menuBar1);

        jLabel1 = new JLabel("Enter weight in [kg]:");
        jPanel1.add(jLabel1);

        jTextField1 = new JTextField("");
        jPanel1.add(jTextField1);

        jLabel2 = new JLabel("Enter height in [cm]:");
        jPanel1.add(jLabel2);

        jTextField2 = new JTextField("");
        jPanel1.add(jTextField2);

        jButton1 = new JButton("Calculate");
        mainPanel.add(jButton1, BorderLayout.SOUTH);

        Handler handler = new Handler();
        jButton1.addActionListener(handler);
        jMenuItem1.addActionListener(handler);
        jMenuItem2.addActionListener(handler);
    }


    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                BMICalc bmicalc = new BMICalc();
                bmicalc.setVisible(true);
            }
        });
    }

    private class Handler implements ActionListener {

        public void actionPerformed(ActionEvent event) {

            if (event.getSource() == jButton1) {

                if (jTextField1.getText().equals("") || jTextField2.getText().equals("")) {

                    JOptionPane.showMessageDialog(null, "All fields must be filled in!", "Error", JOptionPane.INFORMATION_MESSAGE);
                }
                else {
                    Calculations calcs = new Calculations();
                    calcs.calculateBMI(jTextField1.getText(), jTextField2.getText());
                    JOptionPane.showMessageDialog(null, "Your BMI: " +calcs.returnBMI());
                }
            }
            else if (event.getSource() == jMenuItem1) {

                JOptionPane.showMessageDialog(null, "The program calculates BMI based on information entered by user." , "The purpose of this program", JOptionPane.INFORMATION_MESSAGE);
            }
            else if (event.getSource() == jMenuItem2) {

                JOptionPane.showMessageDialog(null, "BMI Calc v. 1.0 " , "About", JOptionPane.INFORMATION_MESSAGE);
            }


        }

    }

}

Calculations.java Calculations.java

public class Calculations {

        private double BMI;
        private int weight, height;

        public void calculateBMI(String sWeight, String sHeight) {

            weight = Integer.parseInt(sWeight);
            height = Integer.parseInt(sHeight);
            BMI = weight/(height*height*0.0001);
        }

        public String returnBMI() {

            return String.format("%.2f", BMI);

        }
}

It works just fine, but I would like to make the code 'clenaer' and make the Handler a class, not a subclass, in another file. 它工作正常,但是我想使代码“ clenaer”并使Handler在另一个文件中成为一个类,而不是子类。 I've created a Handler.java and moved the whole Handler subclass, but the class doesn't see the jTextFields and jButton, as they are private (and as far as I'm concerned, they should be). 我创建了一个Handler.java并移动了整个Handler子类,但是该类没有看到jTextFields和jButton,因为它们是私有的(就我而言,它们应该是私有的)。

How can I separate ActionListener class, access these jObjects in it and still be fair with privacy stuff? 如何分隔ActionListener类,访问其中的这些jObject并仍然对隐私保密?

Thank you very much for answers. 非常感谢您的回答。

You can pass the objects you need to the Handler class using the constructor : 您可以使用构造函数将所需的对象传递给Handler类:

public class Handler {

     private JButton button;
     private JTextField textField;

     public Handler(JButton button, JTextField textField) {
          this.button = button;
          this.textField = textField;
     }

}

And when you instantiate the class you just pass in the two variables you want: 当实例化该类时,您只需要传入两个变量即可:

Handler handler = new Handler(jButton1, jTextField1);

Explanation: 说明:

your Handler class is inner class of of BMICalc . 您的Handler类是BMICalc 内部类。 When a nested class is not static (see also difference between static and non-static nested classes) it means that objects of those class exist within an object of the parent class. 当嵌套类不是静态的时(请参见静态和非静态嵌套类之间的区别),这意味着这些类的对象存在于父类的对象中。 That's why your Handler class see private fields. 这就是您的Handler类看到私有字段的原因。

This is no problem for us when the class is static. 当类是静态的时,这对我们来说没有问题。 You just have to pass in those variables to the Handler somehow (constructor or setter fields) and then you can reuse your class for other button-text field combinations. 您只需要以某种方式将这些变量传递给Handler (构造函数或setter字段),然后可以将您的类重用于其他按钮文本字段组合。


Edit: Yet another way: 编辑:还有另一种方式:

If your handler is to be used here, and only here, and nowhere else in the code, you could instantiate anonymous Handler and assign it to the field (no need to reuse somewhere else). 如果您的处理程序仅在此处,仅在此处和代码中的任何其他地方使用,则可以实例化匿名 Handler并将其分配给该字段(无需在其他地方重复使用)。 So, in example: 因此,例如:

jMenuItem1.addActionListener(new Handler() {
    @Override
    public void actionPerformed(ActionEvent event) {
        JOptionPane.showMessageDialog(null, "The program calculates BMI based on information entered by user." , "The purpose of this program", JOptionPane.INFORMATION_MESSAGE);
    }
});

jMenuItem2.addActionListener(new Handler() {
    @Override
    public void actionPerformed(ActionEvent event) {
        JOptionPane.showMessageDialog(null, "BMI Calc v. 1.0 " , "About", JOptionPane.INFORMATION_MESSAGE);
    }
});

Now you don't have to create one huge Handler with a lot of fields and ifs... 现在,您不必创建一个包含许多字段和ifs的大型Handler。

Note that the class Handler that you show is not a subclass of Main . 请注意,您显示的Handler 不是Main子类 To be a subclass means it inherits. 成为子类意味着它继承。 What you have is an inner class . 你所拥有的是一个内部阶级

You need to pass the references to the handler so it can refer to them. 您需要将引用传递给处理程序,以便它可以引用它们。 For example: 例如:

public class Handler implements ActionListener {
    private final JTextField jTextField1;
    private final JButton jButton1;
    public Handler(final JTextField textField, final JButton button)
        {
        this.jTextField1 = textField;
        this.jButton1 = button;
        }
}

And create it like this: 并像这样创建它:

Handler handler = new Handler(jTextField1, jButton1);

If you want to protect those JTextField and JMenuItem from the others classes while having the handler in another classe, then you need to add some methods to the BMICalc class: 如果要在将处理程序放在另一个类中的同时保护其他类的JTextFieldJMenuItem ,则需要向BMICalc类添加一些方法:

public boolean isButton1(ActionEvent event) {
    return event.getSource() == jButton1;
}

public boolean isJMenuItem1(ActionEvent event) {
    return event.getSource() == jMenuItem1;
}

public boolean isJMenuItem2(ActionEvent event) {
    return event.getSource() == jMenuItem2;
}


public String getJButton1Text() {
    return this.jButton1.getText();
}

public String getJTextField1Text() {
    return jTextField1.getText();
}

public String getJTextField2Text() {
    return jTextField2.getText();
}

Then you need to have the following Handler class: 然后,您需要具有以下Handler类:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;

public class Handler implements ActionListener {

private final BMICalc calc;

public Handler(BMICalc calc) {
    this.calc = calc;
}

public void actionPerformed(ActionEvent event) {

    if (calc.isButton1(event)) {

        if (calc.getJTextField1Text().equals("") || calc.getJTextField2Text().equals("")) {

            JOptionPane.showMessageDialog(null, "All fields must be filled in!", "Error", JOptionPane.INFORMATION_MESSAGE);
        }
        else {
            Calculations calcs = new Calculations();
            calcs.calculateBMI(calc.getJTextField1Text(), calc.getJTextField2Text());
            JOptionPane.showMessageDialog(null, "Your BMI: " +calcs.returnBMI());
        }
    }
    else if (calc.isJMenuItem1(event)) {

        JOptionPane.showMessageDialog(null, "The program calculates BMI based on information entered by user." , "The purpose of this program", JOptionPane.INFORMATION_MESSAGE);
    }
    else if (calc.isJMenuItem2(event)) {

        JOptionPane.showMessageDialog(null, "BMI Calc v. 1.0 " , "About", JOptionPane.INFORMATION_MESSAGE);
    }


}

}

And change on line in the BMICalc : 并在BMICalc在线更改:

Handler handler = new Handler(this);

But as the handler is supposed to handle only button and input of this view (and BMICalc class), it would make more sense (for me) to keep this Handler class private and inside the BMICalc class). 但是由于处理程序只应处理该视图(和BMICalc类)的按钮和输入,(对我而言)将这个Handler类保持私有状态并保留在BMICalc类内部会更有意义。 Hope this helps ! 希望这可以帮助 !

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM