ZeroCool
ZeroCool

Reputation: 477

Opening a new JFrame using a JButton

I have two classes (Sampling and Stacker). The Sampling class (my Main class) is extends JFrame and has a JButton with an ActionListener to open the Stacker class.

The problem is when the button is clicked, the Stacker class will open but only a frame without any components. When I switch the main method into the Stacker class, the program works fine. What is the problem?

Here is the code:

The Sampling class:

public class Sampling extends JFrame implements ActionListener 
{

    private JButton openStacker;

    Stacker st;

    public Sampling()
    {
        setSize(300,300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new FlowLayout());
        setLocationRelativeTo(null);

        openStacker = new JButton("Start Stacker!");

        add(openStacker);
        openStacker.addActionListener(this);

        setVisible(true);
    }

    public void actionPerformed(ActionEvent e)
    {
        dispose();
        st = new Stacker();
    }

    public static void main (String args[])
    {
        new Sampling();
    }
}

The Stacker game class:

public class Stacker  extends JFrame implements KeyListener 
{
    int iteration = 1;
    double time = 200;
    int last = 0;
    int m = 10;
    int n = 20;
    JButton b[][];
    int length[] = {5,5};
    int layer = 19;
    int deltax[] = {0,0};
    boolean press = false;
    boolean forward = true;
    boolean start = true;


    public Stacker()
    {

        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setSize(400,580);
        this.setUndecorated(false);
        this.setLocationRelativeTo(null);



        b = new JButton [m][n];
        setLayout(new GridLayout(n,m));
        for (int y = 0;y<n;y++)
        {
            for (int x = 0;x<m;x++)
            {
                    b[x][y] = new JButton(" ");
                    b[x][y].setBackground(Color.DARK_GRAY);
                    add(b[x][y]);
                    b[x][y].setEnabled(false);
            }//end inner for
        }

        this.setFocusable(true); 
        this.pack();
        this.addKeyListener(this);
        this.setVisible(true); 

        go();

    }


    public void go()
    {
        int tmp = 0;
        Component temporaryLostComponent = null;
        do{
        if (forward == true)
        {
            forward();
        } else {
            back();
        }
        if (deltax[1] == 10-length[1])
        {
            forward = false;
        } else if (deltax[1] == 0)
        {
            forward = true;
        }
        draw();
        try 
        {
            Thread.sleep((long) time);
        } 
        catch (InterruptedException e) 
        {

            e.printStackTrace();
        }

        }while(press == false);
        if (layer>12)
        {
            time= 150-(iteration*iteration*2-iteration); 
        } else
        {
            time = time - 2.2;
        }
        iteration++;
        layer--;
        press = false;
        tmp = check();
        length[0] = length[1];
        length[1] = tmp;
        if (layer == -1)
        {
            JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");

            repeat();
        }
        if (length[1] <= 0)
        {   
            JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line "+(18-layer)+"!");

            repeat();
        }
        last = deltax[1];
        start = false;
        go();
    }
    public int check()
    {
        if (start == true)
        {
            return length[1];
        } 
        else if (last<deltax[1])
        {
            if (deltax[1]+length[1]-1 <= last+length[0]-1)
            {
                return length[1];
            } 
            else 
            {
                return length[1]-Math.abs((deltax[1]+length[1])-(last+length[0]));
            }
        } 
        else if (last>deltax[1])
        {
            return length[1]-Math.abs(deltax[1]-last);
        } 
        else 
        {
            return length[1];
        }
    }
    public void forward()
    {
        deltax[0] = deltax[1];
        deltax[1]++;
    }

    public void back()
    {
        deltax[0] = deltax[1];
        deltax[1]--;
    }

    public void draw()
    {
        for (int x = 0;x<length[1];x++)
        {
            b[x+deltax[0]][layer].setBackground(Color.DARK_GRAY);

        }
        for (int x = 0;x<length[1];x++)
        {
            b[x+deltax[1]][layer].setBackground(Color.CYAN);
        }
    }

    public void repeat()
    {
        if(JOptionPane.showConfirmDialog(null, "PLAY AGAIN?","WARNING",JOptionPane.YES_NO_OPTION)== JOptionPane.YES_OPTION)
        {
            dispose();
            new Stacker();
        }else{
            System.exit(0);
        }
    }


    public void keyPressed(KeyEvent e)
    {
        if (e.getKeyCode() == KeyEvent.VK_SPACE)
        {
            press = true;
        }

    }


    public void keyReleased(KeyEvent arg0)
    {

    }


    public void keyTyped(KeyEvent arg0) 
    {

    }

}

Upvotes: 1

Views: 223

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 208994

Just to put all my comments into an answer, and give you somewhere to start with:

Comment 1: Take out go(); see that happens. I tested it and it will work. If you leave it there, even the frame's close button is jammed. You're blocking the edt with the while->Thread.sleep junk. You'll want to do some refactoring. You're code it hard to follow and I have no idea what you're trying to do, so I didn't even attempt it

Comment 2: If you're wondering why it works when you just run the main from the Stacker class, it's probably because you are running it outside the EDT,

public static void main(String[] args) { new Stacker(); }.

What happens when you click the button, that action is performed within the EDT, and hence your new Stacker() will be run on the EDT. In which case the EDT gets blocked by your while loop. If you try run the program from the Stacker class, but wrap it in a SwingUtilities.invokeLater, you will also notice the program fails to work. Swing programs should be run on the EDT though.

Comment 2: Read the first few sections on Concurrency with Swing

So what you can do is use a Swing Timer (which operates on the EDT) for the game loop. What I did was refactor your code a bit. It doesn't operate the way you want it to yet, only because I didn't really understand the logic of your code. So I couldn't get it to work. What I did though, is put some of the logic into the Timer.

Timer timer = new Timer((int)time, new ActionListener(){
    public void actionPerformed(ActionEvent event) {
        if (forward == true) {
            forward();
        } else {
            back();
        }
        if (deltax[1] == 10 - length[1]) {
            forward = false;
        } else if (deltax[1] == 0) {
            forward = true;
        }
        draw();
    }
});

And when the go() method is called, it just starts the timer by calling timer.start(). Basically what you need to know about the timer, is that every tick (the milliseconds you pass it), the actionPerformed will be called. So you can update the game state in that method, just like you did in the while loop each iteration.

Take some time to go over How to Use Swing Timers

To get the game working properly, you still need to make some adjustments, but this should give you a head start.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Sampling extends JFrame implements ActionListener {

    private JButton openStacker;

    Stacker st;

    public Sampling() {
        setSize(300, 300);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new FlowLayout());
        setLocationRelativeTo(null);

        openStacker = new JButton("Start Stacker!");

        add(openStacker);
        openStacker.addActionListener(this);

        setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        dispose();
        st = new Stacker();
    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new Sampling();
            }
        });
    }
}

class Stacker extends JFrame implements KeyListener {

    int iteration = 1;
    double time = 200;
    int last = 0;
    int m = 10;
    int n = 20;
    JButton b[][];
    int length[] = {5, 5};
    int layer = 19;
    int deltax[] = {0, 0};
    boolean press = false;
    boolean forward = true;
    boolean start = true;

    Timer timer = new Timer((int)time, new ActionListener(){
        public void actionPerformed(ActionEvent event) {
            if (forward == true) {
                forward();
            } else {
                back();
            }
            if (deltax[1] == 10 - length[1]) {
                forward = false;
            } else if (deltax[1] == 0) {
                forward = true;
            }
            draw();
        }
    });

    public Stacker() {

        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setSize(400, 580);
        this.setUndecorated(false);
        this.setLocationRelativeTo(null);

        b = new JButton[m][n];
        setLayout(new GridLayout(n, m));
        for (int y = 0; y < n; y++) {
            for (int x = 0; x < m; x++) {
                b[x][y] = new JButton(" ");
                b[x][y].setBackground(Color.DARK_GRAY);
                add(b[x][y]);
                b[x][y].setEnabled(false);
            }//end inner for
        }

        this.setFocusable(true);
        this.pack();
        JPanel panel = (JPanel)getContentPane();
        panel.addKeyListener(this);
        this.setVisible(true);
        panel.requestFocusInWindow();

        go();
    }

    public void go() {

        int tmp = 0;
        Component temporaryLostComponent = null;
        timer.start();
        if (layer > 12) {
            time = 150 - (iteration * iteration * 2 - iteration);
        } else {
            time = time - 2.2;
        }
        iteration++;
        layer--;
        press = false;
        tmp = check();
        length[0] = length[1];
        length[1] = tmp;
        if (layer == -1) {
            JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");

            repeat();
        }
        if (length[1] <= 0) {
            JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line " + (18 - layer) + "!");

            repeat();
        }
        last = deltax[1];
        start = false;
        //go();
    }

    public int check() {
        if (start == true) {
            return length[1];
        } else if (last < deltax[1]) {
            if (deltax[1] + length[1] - 1 <= last + length[0] - 1) {
                return length[1];
            } else {
                return length[1] - Math.abs((deltax[1] + length[1]) - (last + length[0]));
            }
        } else if (last > deltax[1]) {
            return length[1] - Math.abs(deltax[1] - last);
        } else {
            return length[1];
        }
    }

    public void forward() {
        deltax[0] = deltax[1];
        deltax[1]++;
    }

    public void back() {
        deltax[0] = deltax[1];
        deltax[1]--;
    }

    public void draw() {
        for (int x = 0; x < length[1]; x++) {
            b[x + deltax[0]][layer].setBackground(Color.DARK_GRAY);

        }
        for (int x = 0; x < length[1]; x++) {
            b[x + deltax[1]][layer].setBackground(Color.CYAN);
        }
    }

    public void repeat() {
        if (JOptionPane.showConfirmDialog(null, "PLAY AGAIN?", "WARNING", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
            dispose();
            new Stacker();
        } else {
            System.exit(0);
        }
    }

    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SPACE) {
            System.out.println("Pressed");
            press = true;
        }

    }

    public void keyReleased(KeyEvent arg0) {

    }

    public void keyTyped(KeyEvent arg0) {

    }

}

Notice the SwingUtilities.invokeLater in the main. That's how you can start up the program on the EDT. The link on Concurrency In Swing will give you more information.

Upvotes: 1

Related Questions