如何使用其中包含 actionPerformed 的 IF 语句从另一个 class 检查 class 中的 JToggleButton 状态?

How to check JToggleButton state in a class from another class using IF-statement that have actionPerformed within it?

EDIT : I found my problem but still don't have a clue for why this happen, I'm still not finished Online Lectures from Professor Mehran Sahami (Stanford), maybe I'll find an answer if I push on on the lecture videos.

The problem is I remove my other components methods before my button method for efficient posting space, so I should put my JToggleButton method after my main JFrame method for it to work, but what if my other components inherit other class too? Which method should I put first to make all of components works? That I'll found out with practicing java more.

Thank you @Dan and @SebVb for answers and suggestions, sorry if this just a beginners mistake :)

我正在学习 java 一个月,并且已经有了简单的学习项目,但现在我在 JToggleButtonItemEventactionPerformed 中遇到问题If 语句。

我已经搜索了一周的时间来寻找在 if 语句中使用 actionPerformed 的示例,该语句具有来自另一个 class 的 ItemEvent,但我找不到相同的问题来产生工作结果。

我正在尝试制作一个 window 扫描仪,它只会在选择切换按钮时进行扫描,然后使用缓冲图像绘制 JPanel(每 100 毫秒重新绘制一次)并在切换按钮被选中时将其丢弃取消选择,但我认为我的做法是错误的。我有一个主 class 和两个子 class,如下所示:

主要class:

public class WindowScanner {
    public static void main(String[] args) {
        new Window().setVisible(true);
    }
}

Window class:

class Window extends JFrame {
    static JToggleButton captureButton = new JToggleButton("CAPTURE");

    @SuppressWarnings("Convert2Lambda")
    public Window() {
        // JFrame looks codes

        /** EDIT: these components method should be written after button method
        * JPanel looks codes
        * JLabel looks codes
        * END EDIT
        */

        add(captureButton);
        // capture button default looks code
        ItemListener captureListener = new ItemListener(){
            @Override
            public void itemStateChanged(ItemEvent captureButtonEvent) {
                int captureState = captureButtonEvent.getStateChange();
                if(captureState == ItemEvent.SELECTED){
                    // capture button SELECTED looks code
                    System.out.println("capture button is selected");
                } else if(captureState == ItemEvent.DESELECTED){
                    // capture button DESELECTED looks code
                    System.out.println("capture button is deselected");
                }
            }
        }; captureButton.addItemListener(captureListener);
    }
}

扫描仪class:

public class Scanner extends Window {

    private static BufferedImage boardCaptured;
    static int delay = 100;

    protected BufferedImage boardScanned(){
        return boardCaptured;
    }

    @SuppressWarnings("Convert2Lambda")
    public static void Scan() {
        if (captureButton.isSelected()) {
            ActionListener taskPerformer = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent captureEvent) {
                    try {
                        // capturing method
                    } catch (AWTException error) {
                        // AWTException error method
                    }
                    // is this the right place to put JPanel code?
                    JPanel panel = new JPanel();
                    boardCaptured = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
                    Graphics2D graphic = boardCaptured.createGraphics();
                    panel.setSize(500,500);
                    panel.paint(graphic);
                    panel.revalidate();
                    panel.repaint();
                }
            }; new Timer(delay, taskPerformer).start();
        } else {
            // this suppose to end capturing if capture button isSelected() == false
        }
    }
}

所以这是我的问题:

  1. 我真的必须将 Main class 与 Window class 分开吗? 什么原因?
  2. 如何使 Scan 方法中的 if 语句识别我的状态 JToggleButton 来自 Window class?这不可能吗,我错了 方法来做到这一点?
  3. 在扫描仪 class 中,我无法为我的 actionPerformed 创建 get/set (Netbeans 总是将其检查为错误),但为什么我可以为 BufferdImage?
  4. 如果我不能得到第 3 个问题,我该如何做 If 语句 使用 Timer.stop() 停止捕获?还是我又走错了路?
  5. 我的 JPanel in Scanner class 将被制作并成为一个查看器 对于我的缓冲图像?

P.S。很抱歉,问题太多了,我尽量不做多个 post,所以我做一个 post 有多个问题。如果之前有答案请通知我,老实说我找不到它或者用错误的标签搜索它。

我认为有一种更简单的方法可以做您想做的事。按顺序回答您的问题

  1. 将主要 class 与您的 Window class 分开可以让您 re-use 您的 Windows class随处可见。最好只在主 class

  2. 上初始化 GUI 对象
  3. 你为什么不让你的 JToggleButton 私有和一个可以访问他的状态的方法?此外,对于静态字段,Windows 的所有实例都将共享相同的 JToggleButton。

  4. 这是一个匿名的 class,其中包含您的 actionPerformed 方法。想看就得造个内class。

  5. 我认为你的做法是错误的。使用一个线程,它会以特定的延迟启动你的重绘会更好。如果您创建一个扩展 Runnable 的 class,您可以检查按钮的状态,然后执行适当的操作

  6. 您的 JPanel 在 ActionListener 中,我从未见过,我认为它无法工作。

在较短的版本中

  1. 放入您的 Window class 您的 JPanel、BufferedImage 和 JToggleButton
  2. 创建一个特定的线程来在选择 JToggleButton 时进行重新绘制

这是我认为您想做的事情的简单版本。可以对其进行编辑以包含您的变量,例如 boardCaptured。这段代码主要描述了如何从不同的class.

中获取一个组件

Main.java(在一个 java 文件中包含所有 classes)

import javax.swing.JLabel;
import javax.swing.JToggleButton;
import javax.swing.JFrame;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.Timer;

class WindowScanner extends JFrame {
    private JLabel label;
    private JToggleButton captureButton = new JToggleButton("CAPTURE");

    WindowScanner() {
        super("Fist Window");
        setSize(150, 100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new FlowLayout());
        add(captureButton);
        setVisible(true);

        new Scanner(this);
    }

    public JToggleButton getCaptureButton() {
        return captureButton;
    }
}

class Scanner extends JFrame {
    private WindowScanner wS;
    private int delay = 1000;
    private Timer t = new Timer(delay, new taskPerformer());

    Scanner(WindowScanner wS) {
        super("Second Window");
        this.wS = wS;
        setBounds(200,0,500,500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        wS.getCaptureButton().addActionListener(new taskPerformer());
    }

    private Color randomColor() {
        Random rand = new Random();
        float r = rand.nextFloat() / 2f ;
        float g = rand.nextFloat() / 2f;
        float b = rand.nextFloat() / 2f;
        Color randomColor = new Color(r, g, b);
        return randomColor;
    }

    private class taskPerformer implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent captureEvent) {
            if(captureEvent.getSource() == wS.getCaptureButton()) {
                if (wS.getCaptureButton().isSelected()) {
                    t.start();
                } else {
                    t.stop();
                }
            }

            if(captureEvent.getSource() == t) {
                getContentPane().setBackground(randomColor());
                revalidate();
                repaint();
            }
        }
    }
}

public class Main {
    public static void main (String[] args) {
        new WindowScanner();
    }
}

这段特殊的代码使用 javax.swing.timer 中的计时器每秒将第二个 JFrame 中的背景颜色更改为随机颜色。此代码描述了如何从不同的 class.

获取组件或变量(如果您更改它)

主要是这些代码片段允许它。

1

public JToggleButton getCaptureButton() {
    return captureButton;
}

这允许其他 classes 获取组件。

2

private WindowScanner wS;

Scanner(WindowScanner wS) {
    ...
    this.wS = wS;
    ...
}

这使得 WindowScanner 的当前实例和 Scanner 中声明的 WindowScanner 的实例成为同一实例。

注意:考虑使用 public getters and setters.

至于你列出的 5 个问题。

1) Do I really have to make Main class separated from Window class? What the reason?

在大多数情况下,是的。正如 SebVb 所说,这是一种很好的做法。但是,如果您希望将它们放在同一个 class.

中,您可以这样做
import javax.swing.JToggleButton;
import javax.swing.JFrame;
import java.awt.FlowLayout;

public class Test extends JFrame {
    private JToggleButton captureButton = new JToggleButton("CAPTURE");

    Test() {
        super("Fist Window");
        setSize(150, 100);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new FlowLayout());
        add(captureButton);
        setVisible(true);
    }

    public JToggleButton getCaptureButton() {
        return captureButton;
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                Test frame = new Test();
            }
        });
    }
}

2) How to make my if statement in Scan method recognize state of my JToggleButton from Window class? Is it impossible and I had a wrong approach to do it?

您使用了错误的方法来执行此操作。请参阅我在上面放置的代码和代码片段,了解如何正确执行此操作。 (使用 public getters。)

3) In Scanner class, i can't make a get/set for my actionPerformed (Netbeans always checked it as an error), but why I can make one for BufferdImage?

我不能完全确定你在问什么,但请查看我上面的代码,看看是否有帮助。如果它没有留下评论试图完全解释你的意思。

4) If I can't get question number 3 happen, how can I make If statement to stop capturing using Timer.stop()? Or am I in wrong approach again?

在我的代码中,我向您展示了这与 JToggleButton 的关系。请参阅下面的代码片段

private class taskPerformer implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent captureEvent) {
        if(captureEvent.getSource() == wS.getCaptureButton()) {
            if (wS.getCaptureButton().isSelected()) {
                t.start();
            } else {
                t.stop();
            }
        }

        if(captureEvent.getSource() == t) {
            getContentPane().setBackground(randomColor());
            revalidate();
            repaint();
        }
    }
}

此代码表示当 JToggleButton 触发 ActionEvent 如果它被选中则启动计时器,t.start(),或者如果它未被选中则停止计时器,t.stop().

5) Do my JPanel in Scanner class would be produced and make a viewer for my buffered image?

同样,我不完全确定你在问什么,但这是我最好的猜测。你有两个选择。

1

boardCaptured直接放在相框上。

paint(graphic);
repaint();
revaildate();

2

像您一样创建一个 JPanel,但在 ActionListener

之外
JPanel panel = new JPanel()
boardCaptured = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphic = boardCaptured.createGraphics();
panel.setSize(500,500);
panel.paint(graphic);
add(panel);

private class taskPerformer implements ActionListener {
    if(captureEvent.getSource() == t) {
        panel.paint(graphic);
        panel.revalidate();
        panel.repaint();
    }
}