javaswingif-statementjtogglebutton

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 :)

I am learning java for a month now and already had simple project for learning but now I have problems with JToggleButton, ItemEvent, and actionPerformed included in If-statement.

I've searching for a week for examples on using actionPerformed within if-statement that have ItemEvent from another class but i can't find a same problem to produce a working result.

I'm trying to make a window scanner that will scan only if toggle button is selected then paint JPanel using buffered image (repaint every 100 millisecond) and disposed it if toggle button is deselected, but I think my approach to do it is wrong. I have one main class and two sub-classes like these:

Main 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);
    }
}

Scanner 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
        }
    }
}

So here is my questions:

  1. Do I really have to make Main class separated from Window class? What the reason?
  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?
  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?
  5. Do my JPanel in Scanner class would be produced and make a viewer for my buffered image?

P.S. I'm sorry it cramped with questions, I tried not to make multiple post, so I make single post with multiple questions. Please notice me if there's answer before, I'm honestly can't find it or had search it with wrong tags.


Solution

  • Here is a simple version of what I think you want to do. This can be edited to include your variables, such as boardCaptured. This code mainly portrays how to get a component from a different class.

    Main.java (Contains all the classes in one java file)

    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();
        }
    }
    

    This particular piece of code changes the color of the background in the second JFrame to a random color every second using a timer from javax.swing.timer. This code portrays how to get a component, or a variable if you change it, from a different class.

    It is mainly these code fragments which allow it.

    1

    public JToggleButton getCaptureButton() {
        return captureButton;
    }
    

    This allows other classes to get the component.

    2

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

    This makes the current instance of WindowScanner and the instance of WindowScanner declared in Scanner the same instance.

    Note: Look into using public getters and setters.

    As for your 5 listed questions.

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

    In most cases yes you do. As SebVb said it is good practice. However you can do something like this if you wish to have them in the same 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?

    You were using the wrong approach to do this. See the code and code fragments I have put above for how to do it correctly. (Using 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?

    I can't entirely say I'm sure what you are asking but see my code above to see if that helps. If it doesn't leave a comment trying to fully explain what you mean.

    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?

    In my code I show you how this can be related to the JToggleButton. See code fragment below

    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();
            }
        }
    }
    

    This code says when the JToggleButton fires an ActionEvent if it is selected then start the timer, t.start(), or if it is not selected stop the timer, t.stop().

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

    Again I'm not entirely sure what you are asking but here is my best guess. You have two options.

    1

    Put boardCaptured directly on the frame.

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

    2

    Create a JPanel like you did but outside the 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();
        }
    }