2

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.

punkdawa
  • 23
  • 1
  • 7

2 Answers2

1

I think there's an easier way do do what do you want. Taking your questions by order

  1. Having the main class separated from your Window class allow you to re-use your Windows class everywhere you want. It's a good pratice to only init your GUI objects on your main class

  2. Why don't you have your JToggleButton private and a mehtod wwhich will access to his status ? also, with a static field, all your instaces of Windows will share the same JToggleButton.

  3. It's an anonymous class that contains your actionPerformed method. If you want to see it, you have to create an inner class.

  4. I think your approch is wrong. Using a thread, which will launch your repaint with a specific delay is better. If you create a class which extends Runnable, you can check the state of your button and then do the appropriate action

  5. Your JPanel is inside an ActionListener, i've never seen that and i don't think that it can works.

In a shorter version

  1. Put in your Window class your JPanel, BufferedImage and JToggleButton
  2. Create a specific thread to do your repainting when the JToggleButton is selected
SebVb
  • 187
  • 1
  • 3
  • 14
1

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();
    }
}
Community
  • 1
  • 1
Dan
  • 7,286
  • 6
  • 49
  • 114
  • thank you very much, I'll test your code later. I see, so it is better to put you gui class inside the main class then. – punkdawa Jan 19 '16 at 10:41
  • @punkdawa Well I did in this case but you separate into 3 different files or merge it all into one (see edit) In my edit I will attempt to answer each of your questions – Dan Jan 19 '16 at 14:52
  • @punkdawa I completely edited my answer to explain things a bit better for you – Dan Jan 19 '16 at 16:00
  • 1
    wow, such a very good answer, never thought I can get a specific answer like this :) I have seen example of EventQueue here, tried to learn java slowly and skip it, never though I should have practice it now. Let me try to understand and implement it bit by bot, to get a better understanding of java and programming. Thank you again. – punkdawa Jan 19 '16 at 16:19