1

I'm pretty new to Swing, but not to Java. Anyway, I have a chess program. Here's the part of the game loop class that matters:

public class game {
    static Board gameboard = new Board();
    public static boolean waitstatus = true;
    public static char currentfaction = 'w';
    public static boolean done = false;
    public static boolean resigned = false;
    public static boolean wplayern = false;
    public static boolean bplayern = false;
    public static gui boardwindow = new gui();

    public static void main(String[] args) {
        gameboard.init(8, 8);
        gui.startGUI(boardwindow);
        runner();
        while (true) {
            //spin
        }

    }

    public static void runner() {
        done = false;
        resigned = false;
        wplayern = false;
        bplayern = false;
        boolean stalemate = false;

        while (true) {
            //The loop stuff    
        }
    }

    public static void resetGame() {
        if (!done) {
            System.out.println("Game's not finished yet!");
        } else {
            gameboard.restart();
            waitstatus = true;
            currentfaction = 'w';
            done = false;
            resigned = false;
            wplayern = false;
            bplayern = false;
            boardwindow.redraw();
            rerun();
        }
    }

    public static void rerun() {
        runner();
    }
}

So that's the code in question. By the way, boardwindow is a gui object, gameboard is my internal logic gameboard array, redraw() has the gui redraw (to update the positions of the pieces), and restart() restarts the internal logic board to the original starting gamestate. The gui class is a swing gui that is pretty simple, and works pretty well. The problem is, in the game loop, when it's checkmate, the loop breaks and the runner() function ends. The user should then be able to press the new game button in the gui, to have the game restart after the checkmate. The new game button calls resetGame(). The problem is that the gui window freezes when runner() is called again, and I'm not sure why, it wouldn't need multiple threads for this, I thought. I have other buttons which call functions that I have not shown you, and those functions call other functions like restart() and such, and they have no problem, its only when runner() is called.

I know my other code is probably awful in formatting and convention, but please try to keep answers focused on the main problem.

Thanks

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
codechao
  • 67
  • 9
  • Did you notice any errors in the console log? – The Well Mar 06 '15 at 09:21
  • 1
    I'm not sure about your case, but almost all problems with freeze GUI in Java Swing related to wrong using EDT:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html – Vartlok Mar 06 '15 at 09:22
  • 2
    Don't rely on `static`, it's not a cross object communication mechanism and will blow up your face – MadProgrammer Mar 06 '15 at 09:24
  • No errors in the console log, I realize that most problems with GUI freezing in Swing come from mishandling threads, but my problem is different than most every other example I've seen of that. I'm not trying to run two methods at the same time at this point, and even in other cases when I run two methods at the same time, the GUI handles it just fine. I use static because I do not want to create a separate object for game, because it really does not need separate objects. – codechao Mar 06 '15 at 09:29
  • 1
    Don't block the EDT (Event Dispatch Thread). The GUI will 'freeze' when that happens. See [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for details and the fix. – Andrew Thompson Mar 06 '15 at 09:38
  • Does that block the EDT? I know I need to use invoke later, but what should I have as the action on that, and when should I call invoke later? The tutorial for chess swing gui that I used has the action as what the startGUI does, establishing the frame, and then having outside calls meant to start the gui go to invokeLater instead. Is this what I should do? I'm trying it now, but it'll take some time, because of scoping issues. – codechao Mar 06 '15 at 09:44
  • or should I use swingworker as stated in what you say its a duplicate of (although their problem is slightly different). Should I have my runner as the doInbackground? – codechao Mar 06 '15 at 09:47

1 Answers1

3

You should put a condition to control the loop rather than set it to true. Here the loop keeps running even after resetting the game from resetGame(); or use break;

public static void runner() {
    done = false;
    resigned = false;
    wplayern = false;
    bplayern = false;
    boolean stalemate = false;

    while (true) {
        //The loop stuff 
        if(newGameClicked == true){//just to literally make meaning
            break;
        }
    }
}

Or as a quick fix you could simply just call boardwindow.dispose(); and then create a new instance of gui() and set it visible() to restart the game when the new game button is clicked

Phil
  • 597
  • 11
  • 26
  • Which while loop, in runner or main? – codechao Mar 06 '15 at 09:40
  • in runner. or better yet see [How do I use SwingWorker in Java?](http://stackoverflow.com/questions/782265/how-do-i-use-swingworker-in-java) on how to use swing workers for things like this – Phil Mar 06 '15 at 09:47
  • so would I make my game class a swing worker, and then have my runner () as a do in background, and executed by the new game button? Does that sound right? Can I still have all of my other helper functions in there that can be called from the gui as I have it now? – codechao Mar 06 '15 at 09:58
  • yh. the runner() method should be as a do in backgroud as it handles the loop that runs in the background. your other helper functions updates variable so they don't have to be there except those that update your gui directly. As with what you currently have in the runner() method, use a condition there. see my updated ans – Phil Mar 06 '15 at 10:03
  • oh, did you not see, inside the while loop, I do break when it's checkmate. it's pretty much if(checkmate) break; And resetGame() will only run after the runner() function is over. So should I still use the run in background? – codechao Mar 06 '15 at 10:16
  • Using the run in the background will be more safe and ensures your app dosen't freeze. Also updated my ans to make things more clear as to what might have caused the freezing – Phil Mar 06 '15 at 10:48
  • I'm confused, what do you think might have caused the freezing? I know for a fact that it exits runner successfully, and the loop stops. Also, when I make a new instance of gui, it still freezes. – codechao Mar 06 '15 at 11:05
  • Ok, sorry for the mix up, from what up there in your question you did't really put up the full code inside the runner. just checking to make sure your loops exits as an infinite loop running could freeze your application. If they all exit, then the swing worker is the only solution to the problem. Thanks – Phil Mar 06 '15 at 11:10
  • okay, so I have my game class extending swing worker, and I've replaced runner with do in background, with the same code. Now, my question is, so can I have the rest of game execute normally, with the main function and all that, and then call the do in background with execute() in the gui whenever I want to recall runner()? – codechao Mar 06 '15 at 11:19
  • Well gosh darn, it works now. Thanks a lot, now my chess game is complete. – codechao Mar 06 '15 at 11:27
  • Your well come .. +1 – Phil Mar 06 '15 at 11:45
  • vote ans up @user3739187 – Phil Oct 09 '15 at 10:57