私はアクションリスナーで何が間違っているのかを理解しようとしています。複数のチュートリアルに従っていますが、アクションリスナーを使用しようとすると、netbeansとEclipseでエラーが発生します。
以下は、ボタンを機能させようとしている簡単なプログラムです。
何が間違っていますか?
_import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class calc extends JFrame implements ActionListener {
public static void main(String[] args) {
JFrame calcFrame = new JFrame();
calcFrame.setSize(100, 100);
calcFrame.setVisible(true);
JButton button1 = new JButton("1");
button1.addActionListener(this);
calcFrame.add(button1);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button1)
}
}
_
if(e.getSource() == button1)
では_button1
_を参照できないため、シンボルが見つからないというエラーが発生するため、アクションリスナーは登録されません。
静的メソッドにはthis
ポインターはありません。 (このコードがコンパイルされるとは思わない。)
main()
;のような静的メソッドでこれらのことを行うべきではありません。コンストラクターで設定します。実際に動作するかどうかを確認するためにこれをコンパイルまたは実行しませんでしたが、試してみてください。
public class Calc extends JFrame implements ActionListener {
private Button button1;
public Calc()
{
super();
this.setSize(100, 100);
this.setVisible(true);
this.button1 = new JButton("1");
this.button1.addActionListener(this);
this.add(button1);
}
public static void main(String[] args) {
Calc calc = new Calc();
calc.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button1)
}
}
アクションコマンドの使用について誰も言及していないことに驚いています。これは、ソースとリスナーを関連付ける非常に標準的な方法です。本当に便利なのは;
見る;
import Java.awt.FlowLayout;
import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class DontExtendJFrame implements ActionListener {
private enum Actions {
HELLO,
GOODBYE
}
public static void main(String[] args) {
DontExtendJFrame instance = new DontExtendJFrame();
JFrame frame = new JFrame("Test");
frame.setLayout(new FlowLayout());
frame.setSize(200, 100);
JButton hello = new JButton("Hello");
hello.setActionCommand(Actions.HELLO.name());
hello.addActionListener(instance);
frame.add(hello);
JButton goodbye = new JButton("Goodbye");
goodbye.setActionCommand(Actions.GOODBYE.name());
goodbye.addActionListener(instance);
frame.add(goodbye);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent evt) {
if (evt.getActionCommand() == Actions.HELLO.name()) {
JOptionPane.showMessageDialog(null, "Hello");
} else if (evt.getActionCommand() == Actions.GOODBYE.name()) {
JOptionPane.showMessageDialog(null, "Goodbye");
}
}
}
これが私のコメントに基づいたソースの修正形式です。 EDTでGUIを構築および更新する必要があることに注意してください。ただし、ここまでは行きませんでした。
import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
public class Calc {
public static void main(String[] args) {
JFrame calcFrame = new JFrame();
// usually a good idea.
calcFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final JButton button1 = new JButton("1");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(
button1, "..is the loneliest number");
}
});
calcFrame.add(button1);
// don't do this..
// calcFrame.setSize(100, 100);
// important!
calcFrame.pack();
calcFrame.setVisible(true);
}
}
差し迫った問題を分類する方法を教えられましたが、ここにはもっと重要な問題があると思います。
慣習に従ってください。使い捨てコードでも。つまり、クラス名の最初のケースを意味します。
必要のないクラスを拡張しないでください。 JFrame
はほとんど拡張されません。実際、派生クラスのインスタンスは作成しません!!!
たくさんのものを1つのクラスにまとめないでください。特に、通常は一度に1つのメインクラスまたはインターフェイスのみをサブタイプにする必要があります(Comparable
などは含まれません)。
AWTイベントディスパッチスレッド(EDT)上のSwing/AWT GUIを含め、常に対話します。見苦しくて冗長ですが、それはJavaです。
イベントのソースを確認するのはちょっとしたハックです。リスナーは小さいため、パフォーマンスの不十分な言い訳を主張することさえできません。
そう:
import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Calc {
public static void main(String[] args) {
Java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
runEDT();
}});
}
private static void runEDT() {
assert Java.awt.EventQueue.isDispatchThread();
JFrame frame = new JFrame();
frame.setSize(100, 100);
JButton button1 = new JButton("1");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
...
}
});
frame.add(button1);
frame.setVisible(true);
}
}
リスナー内の囲むメソッドから変数にアクセスする必要がある場合は、final
にします。
問題は、button1がローカル変数であることです。 actionListenerを追加する方法を変更するだけで実現できます。
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//button is pressed
System.out.println("You clicked the button");
}});
または、button1
グローバル変数。
最初の問題は、button1
はmain
メソッドのローカル変数であるため、actionPerformed
メソッドはそれにアクセスできません。
2番目の問題は、ActionListener
インターフェイスがクラスcalc
によって実装されますが、このクラスのインスタンスがmain
メソッドで作成されないことです。
望むことをする通常の方法は、calc
のインスタンスを作成し、button1
calc
クラスのフィールド。
ここには良い答えがありますが、multipleボタンをリッスンするアクションリスナーを追加するというよりグローバルなポイントに対処しましょう。
2つの一般的なアプローチがあります。
共通アクションリスナーの使用
actionPerformed(ActionEvent e)
実装でアクションのソースを取得できます:
JButton button1, button2; //your button
@Override
public void actionPerformed(ActionEvent e) {
JButton actionSource = (JButton) e.getSource();
if(actionSource.equals(button1)){
// YOU BUTTON 1 CODE HERE
} else if (actionSource.equals(button2)) {
// YOU BUTTON 2 CODE HERE
}
}
ActionCommandの使用
このアプローチでは、ボタンのactionCommand
フィールドを設定します。これにより、後でswitch
を使用できるようになります。
button1.setActionCommand("actionName1");
button2.setActionCommand("actionName2");
以降:
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = ((JButton) e.getSource()).getActionCommand();
switch (actionCommand) {
case "actionName1":
// YOU BUTTON 1 CODE HERE
break;
case "actionName2":
// YOU BUTTON 2 CODE HERE
break;
}
}
JFrameボタン、リスナー、およびフィールドの詳細 をご覧ください。
Mainメソッドでbutton1を宣言しているため、actionPerformでアクセスできません。クラス内でグローバルにする必要があります。
JButton button1;
public static void main(String[] args) {
JFrame calcFrame = new JFrame();
calcFrame.setSize(100, 100);
calcFrame.setVisible(true);
button1 = new JButton("1");
button1.addActionListener(this);
calcFrame.add(button1);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button1)
}
「e.getActionCommand()。contains(CharSecuence s)」を使用しています。これは、MVCコンテキストから来ており、ButtonがViewクラスで宣言されているが、actionPerformed呼び出しがコントローラーで発生するためです。
public View() {
....
buttonPlus = new Button("+");
buttonMinus = new Button("-");
....
}
public void addController(ActionListener controller) {
buttonPlus.addActionListener(controller);
buttonMinus.addActionListener(controller);
}
コントローラークラスはActionListenerを実装するため、actionPerformedをオーバーライドする場合:
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().contains("+")) {
//do some action on the model
} else if (e.getActionCommand().contains("-")) {
//do some other action on the model
}
}
この他の回答も役立つことを願っています。
最初に、super()とコンストラクタを使用してJFrameを適切に拡張してから、フレームにactionlistenerを追加し、ボタンを追加します。
import Java.awt.event.ActionEvent;
import Java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Calc extends JFrame implements ActionListener {
JButton button1 = new JButton("1");
JButton button2 = new JButton("2");
public Calc()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(100, 100);
button1.addActionListener(this);
button2.addActionListener(this);
calcFrame.add(button1);
calcFrame.add(button2);
}
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
if(source == button1)
{
\\button1 code here
} else if(source == button2)
{
\\button2 code here
}
}
public static void main(String[] args)
{
JFrame calcFrame = new JFrame();
calcFrame.setVisible(true);
}
}