1

I was just messing around with GUI in Java and created a little game. In it, 105 randomly placed buttons are created and then an instruction screen pops up, telling the user which button to find. I've tried to figure out how to program a "Loading..." JDialog, which will pop up while the buttons are being created in the background. The trouble is, when I run the program the JDialog doesn't load until AFTER all the buttons have been created, which kind of defeats the purpose of the box in the first place. How can I force the "Loading..." box to load BEFORE the buttons begin to be created??? Thanks in advance. Because I've just been tinkering, my code is not perfect but here it is:

    import java.util.Scanner;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Random;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.ProgressMonitor;

public class ButtonGame {

    private static int butNum = 1;
    private static JFrame frame;
    private static ActionListener notIt;
    private static ActionListener it;
    private static Random rand = new Random();
    private static int butToFind = rand.nextInt(105);
    private static JFrame frameToClose;

    //private static int mouseClicks;
    //private static double time;

    public static void main(String[] args) {

    //actionlistener for all incorrect buttons (buttons that are "not it")
    notIt = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            Component component = (Component) e.getSource();
            JFrame frame5 = (JFrame) SwingUtilities.getRoot(component);
            frame5.dispose();
        }
        };

    //actionlistener for the correct button (the button that's "it")
    it = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            JFrame youWin = new JFrame("YOU WON!");

            //removes all panels to begin game again
            JButton again = new JButton("Play again");
            again.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                java.awt.Window windows[] = java.awt.Window.getWindows(); 
                for(int i=0;i<windows.length;i++){
                    if (windows[i] != frame) { windows[i].dispose(); }
                    butToFind = rand.nextInt(105);
                    butNum = 1;
                    youWin.dispose();
                }
                frame.setVisible(true);
                }
            });

            //quits game
            JButton win = new JButton("Quit");
            win.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                System.exit(0);
                }
            });

            //layout
            youWin.setSize(775, 300);
            youWin.setLayout(new FlowLayout());

            JLabel label1 = new JLabel("Fantastic!");
            Font font1 = new Font("Courier", Font.BOLD,120);
            label1.setFont(font1);
            label1.setHorizontalAlignment(JLabel.CENTER);

            JLabel label2 = new JLabel("You beat the game!");
            Font font2 = new Font("Courier", Font.BOLD,60);
            label2.setFont(font2);
            label2.setHorizontalAlignment(JLabel.CENTER);

            youWin.add(label1);
            youWin.add(label2);

            JPanel panel = new JPanel();
            youWin.add(panel);
            panel.add(again);
            panel.add(win);
            youWin.setLocation(260, 100);
            youWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            youWin.setVisible(true);
            java.awt.Window windows[] = java.awt.Window.getWindows(); 
        }
        };

    //start window
    frame = new JFrame("Window");

    frame.setLocation(400, 200);

    JButton button1 = new JButton("Click to begin");

    //button to begin game
    button1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
        // JDialog load = new JDialog();
        // load.setAlwaysOnTop(true);
        // load.setSize(500,500);
        // load.setVisible(true);
        //     load.add(new Label("Loading..."));
        //     load.pack();
        frame.setVisible(false);  // "start" window's visibility
        // try {
        //     Thread.sleep(100000);
        // } catch (Exception t) {
        // }

        // creates buttons
        for (int i = 0; i < 105; i++) {
            JFrame nextFrame = newFrame(butNum);
            nextFrame.setVisible(true);
            butNum++;
        }
        //creates instructions and tells user what button to find
        JFrame instructions = new JFrame("How to play");
        instructions.setSize(300,175);
        instructions.setLayout(new GridLayout(4,1));
        JPanel instPanel = new JPanel();

        //button to remove instruction panel
        JButton ok = new JButton("Ok");
        ok.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                instructions.dispose();
            }
            });
        instPanel.add(ok);
        instructions.setLocation(400,200);

        //layout of instruction panel
        JLabel find = new JLabel("Your goal is to find Button " + butToFind + ".");
        find.setHorizontalAlignment(JLabel.CENTER);

        JLabel find2 = new JLabel("Click a button to make it disappear.");
        find2.setHorizontalAlignment(JLabel.CENTER);

        JLabel find3 = new JLabel("Good luck!");
        find3.setHorizontalAlignment(JLabel.CENTER);

        instructions.add(find);
        instructions.add(find2);
        instructions.add(find3);
        instructions.add(instPanel);
        instructions.setVisible(true);
        }
    });

    frame.add(button1);
    frame.setSize(150,100);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    }

    //creates frame with button in it
    public static JFrame newFrame(int num) {
    JFrame frame2 = new JFrame();
    JButton button = new JButton("Button " + num);
    if (num == butToFind) {
        button.addActionListener(it);
        frameToClose = frame2;
    } else {
        button.addActionListener(notIt);
    }
    frame2.add(button);
    frame2.setSize(randNum(90,200), randNum(50,100));
    frame2.setLocation(rand.nextInt(1200), rand.nextInt(800));
    frame2.getContentPane().setBackground(new Color(rand.nextInt(255),
                            rand.nextInt(255),
                            rand.nextInt(255)));
    frame2.setVisible(true);
    return frame2;
    }

    //provides random number between high and low
    public static int randNum(int low, int high) {
    int result = -1;
    while (result < low || result > high) {
        result = rand.nextInt(high);
    }
    return result;
    }
}

Also, as a side-question, which of the variables defined before main should be static? And how can I get the program to compile without being static? Thanks!

park618
  • 27
  • 6
  • You could use a SwingWorker, but you need to be careful, as y really shouldn't be creating or modifying ui components from outside of the context of the EDT – MadProgrammer May 29 '15 at 23:06

2 Answers2

1

First take a look at The Use of Multiple JFrames, Good/Bad Practice? and understand why I freaked out when I ran your code...

Instead of creating a bunch of frames, why not use something like JButton on another JPanel and add it to the current frame (this would also be a good use for a CardLayout)

JPanel panel = new JPanel(new GridLayout(10, 0));
Random rnd = new Random();
// creates buttons
for (int i = 0; i < 105; i++) {
    JButton btn = new JButton(String.valueOf(i));
    panel.add(btn);
    //JFrame nextFrame = newFrame(butNum);
    //nextFrame.setVisible(true);
    //butNum++;
}

frame.getContentPane().removeAll();
frame.add(panel);
frame.revalidate();
frame.pack();

Alternatively, if you're really hell bent on using "frames", consider using a JDesktopPane and JInternalFrame instead.

See How to Use Internal Frames for more details

Also, as a side-question, which of the variables defined before main should be static? And how can I get the program to compile without being static?

As much as possible, none. Instead of trying to create the whole thing in the main method, use the classes constructor to initialise the UI and use another method to actually get the game rolling...

public class ButtonGame {

    private int butNum = 1;
    private JFrame frame;
    private ActionListener notIt;
    private ActionListener it;
    private Random rand = new Random();
    private int butToFind = rand.nextInt(105);
    private JFrame frameToClose;

    //private static int mouseClicks;
    //private static double time;
    public static void main(String[] args) {
        ButtonGame game = new ButtonGame();
        game.start();
    }

    public ButtonGame() {
        //... All the code that was once in main...
        frame.add(button1);
        frame.setSize(150, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void start() {
        frame.setVisible(true);     
    }
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I see what you mean about having multiple JFrames. But for the sake of practice, how can I make my "Loading..." JFrame load BEFORE the buttons are created? I tried messing around with different threads and using the Thread.sleep() function (of which I'm not too familiar), but nothing I did allowed me to load the "Loading..." JFrame before the buttons started being created. – park618 May 30 '15 at 22:13
  • Problem - Swing is single threaded AND not thread safe, so you really shouldn't be creating or modifying the UI from outside the context of the EDT... – MadProgrammer May 30 '15 at 22:40
  • Does that make it impossible to do using my method? – park618 May 30 '15 at 23:29
  • It makes it dangerous and difficult – MadProgrammer May 30 '15 at 23:29
  • I attempted using a SwingWorker, but again the JFrame appears blank until all buttons are loaded. Why does this occur? It seems to me that SwingWorker/Thread-influencing classes don't do anything... Is it just a more subtle and advanced aspect of coding? – park618 May 30 '15 at 23:32
  • Probably because you're suffocating the EDT – MadProgrammer May 30 '15 at 23:34
0

Answering to your side questions:

  • a static method can only accept static global variables
  • You can put all your code in the constructor and use main to only run the program.

Constructor:

public ButtonGame() {
 // All of your code goes here - except the static methods
}

You should also make all other methods non-static.

To run the program:

public static void main(String[] args) {
    new ButtonGame();
}
Nazmul
  • 103
  • 8