0

So I've done a lot of searching and I can't quite find a solution to the problem I'm having. Designing GUIs with Java's JFrame seems fairly straight-forward, but updating them visually when it's more than just a setText call seems much more tricky, especially when you want to simulate some wait time for visual recognition in between. I'm not familiar with multi-threading and all of the solutions I found, I couldn't seem to get to work how I needed them to.

What I'm trying to do is to simulate dice rolling before landing on a particular side for a simple dice game. To do this, I'm just switching between different sides of dice images a set number of times (10, for example) every fraction of a second (150 ms in this case).

The interesting thing is that this code at its current state works EXACTLY how I want it to on start-up (which does a full 10 roll cycle once before accepting any user-input, but every component of the GUI is visible and working as expected). The problem is that when re-rolling, the GUI goes blank until all the thread sleeping is completed.

With my lack of knowledge about how this sort of thing, I don't understand why it would work the way I want the first time, but not any time after. Hopefully I can get some assistance about the right way to accomplish this or a fix for what I'm currently doing. Thanks!

private void rollDice()
{        
    for(int i = 0; i < 10; i++)
    {
        dice1 = (int) (Math.random() * 6) + 1;
        dice2 = (int) (Math.random() * 6) + 1;

        img1 = new ImageIcon(dice1 + ".png");
        img2 = new ImageIcon(dice2 + ".png");

        try
        {
            Thread.sleep(150);
        } 
        catch(Exception e) 
        {

        }

        lbl1.setIcon(img1);
        lbl2.setIcon(img2);
    }
}
Charles
  • 35
  • 1
  • 5
  • Switch to JavaFx. – SedJ601 Apr 15 '17 at 05:36
  • Your problem is that you are running that for loop on the main thread and it's causing your GUI to freeze. – SedJ601 Apr 15 '17 at 05:38
  • @SedrickJefferson I would, but this is for a Java assignment – Charles Apr 15 '17 at 05:40
  • @SedrickJefferson So would running this in another thread solve my issue? My multi-threading knowledge is practically non-existent. Also, why does this work on the initial run? – Charles Apr 15 '17 at 05:42
  • Yea. That's what you have to do. – SedJ601 Apr 15 '17 at 05:43
  • @SedrickJefferson Alright, thanks. Any explanation for why it works before any user input? – Charles Apr 15 '17 at 05:47
  • Go [here](http://stackoverflow.com/questions/7229284/refreshing-gui-by-another-thread-in-java-swing) and try the code that says, "Here is a little snippet." – SedJ601 Apr 15 '17 at 05:49
  • @Charles because of JavaFX's philosophy, you can run the loop in a differen thread, but you neet to delegate the actual update of the GUI (`refreshGUI()`) to the original GUI-Thread. For this, you can call [`Platform.runLater(Runnable runnable)`](https://docs.oracle.com/javafx/2/api/javafx/application/Platform.html#runLater(java.lang.Runnable)). – Turing85 Apr 15 '17 at 06:04

1 Answers1

0

Try this I found here.

new Thread(new Runnable
{
    public void run()
    {
        for(int count = 0; count < PREROLLS; count++)
        {
            //Add your for loop logic here!

            SwingUtilities.invokeLater(new Runnable() {
                 public void run()
                 {
                       //then update you icon here. I would start with one die if I were you.
                       imgDice1 = new ImageIcon(path + dice1 + ".png");
                 }
            });
            try { Thread.sleep(100); } catch(Exception e) {}
        }
    }
}).start();
Community
  • 1
  • 1
SedJ601
  • 12,173
  • 3
  • 41
  • 59
  • Though I wasn't able to solve my problems with this answer (may have been doing something wrong), your previous comments helped me to find a solution that did do what I wanted, so I'm marking this as the accepted answer. Essentially, all I did was this: new Thread(){ public void run() { /*all my previous dice roll code + thread ending code*/ } }.start(); Much simpler than your answer, yet it works just as I needed. Thanks! – Charles Apr 15 '17 at 19:30
  • @Charles This is not a good solution, you should take a look to swing timer or swingworker to achieve what you want to do – nachokk Apr 15 '17 at 19:57
  • Actually you should't accept this answer as correct if it isn't. I can delete this answer and you can post what you did to solve the problem. That way if someone in the future have the same problem, they can have a good answer. – SedJ601 Apr 15 '17 at 19:58
  • @nachokk I attempted a swing timer and couldn't get it to do what I needed. If you have a code example, feel free to post it and I'll test it out. Again, my experience with this sort of thing is little to none. Thanks. – Charles Apr 15 '17 at 21:07
  • @SedrickJefferson I accepted your answer because the hover message of the accept button stated, "Click to accept this answer because it solved your problem or was the most helpful in finding your solution." It was the most helpful in finding my solution. If need be, I can post my own solution, but I was just following the acceptance hover message reasoning. – Charles Apr 15 '17 at 21:10
  • As long as it's within the rules. Thank! – SedJ601 Apr 15 '17 at 21:29