Why wont this threading code work properly with the GUI? [Java Swing] [Threading]









up vote
0
down vote

favorite












My project uses Java Swing as a GUI. I am making a Towers of Hanoi game. I've just about got the GUI all working, but my solve command wont work properly.



Without threading calls, it immediately solves the towers as expected. I added a couple Thread.waits expected it to solve it step by step so the user can see how it does but instead, it waits some time, then solves the entire puzzle at once. I'm thinking it might not be repainting, but I'm not sure why. Does anyone know what is going on?



Heres the code for the solve:



public class Solver {

public Solver()
// nothing



public void solve(
int numberBlocks,
int startPin,
int auxiliaryPin,
int endPin)
if (numberBlocks == 1)
movePin(startPin, endPin);
try
Thread.sleep(200);

catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();


else
solve(numberBlocks - 1, startPin, endPin, auxiliaryPin);
movePin(startPin, endPin);
try
Thread.sleep(200);

catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();

solve(numberBlocks - 1, auxiliaryPin, startPin, endPin);




private void movePin(int startPin, int endPin)
TowersOfHanoiGame.moveTopBlock(startPin, endPin);



Here is the code from the GUI that does the work:
I know its terribly written, this is my first time writing with Java Swing, Im learning it as I go. If anyone has any pointers on how to better structure this, I'd love to hear about that also.
I'm pasting the whole class, but the important methods are initListeners, and moveTopBlock, and the methods they call.



import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class TowersOfHanoiGame
private static JFrame mainWindow;
private static JPanel mainContentPanel;
private static JPanel content;

private static ArrayList<Block> pegOneBlocks = new ArrayList<Block>();
private static ArrayList<Block> pegTwoBlocks = new ArrayList<Block>();
private static ArrayList<Block> pegThreeBlocks = new ArrayList<Block>();
private Color randomColors = new Color[8];

private Dimension menuSize = new Dimension(100, 100);
private static final int DISCSTEXTSIZE = 20;
private static final int MOVESTEXTSIZE = 30;

private ActionListener downButtonListener;
private ActionListener upButtonListener;
private ActionListener solveButtonListener;

private JLabel discs;
private JLabel moves;

private int discsNumber = 3;
private int movesNumber = 0;

private Solver solver = new Solver();


public TowersOfHanoiGame()
// do nothing
initRandomColors();
initBlocks(3);



/**
* Initialize and display the game
*/
public void display()
initListeners();
initWindow();
mainWindow.setVisible(true);



private void initListeners()
downButtonListener = new ActionListener()
@Override
public void actionPerformed(ActionEvent arg0)
if (discsNumber > 3)
discsNumber--;
updateLabels();
// clearContentFrame();
clearBlockArrays();
initBlocks(discsNumber);
reDrawContentFrame();



;
upButtonListener = new ActionListener()
public void actionPerformed(ActionEvent arg0)
if (discsNumber < 8)
discsNumber++;
updateLabels();
// clearContentFrame();
clearBlockArrays();
initBlocks(discsNumber);
reDrawContentFrame();


;

solveButtonListener = new ActionListener()
public void actionPerformed(ActionEvent arg0)
solver.solve(discsNumber, 0, 1, 2);

;



private void updateLabels()
discs.setText("DISCS: " + discsNumber);
moves.setText("MOVES: " + movesNumber);



/**
* Init the main window
*/
private void initWindow()
mainWindow = new JFrame("Towers Of Hanoi");
initContentPanel();
mainWindow.setContentPane(mainContentPanel);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(1000, 1000);
mainWindow.setResizable(false);
mainWindow.getContentPane().setBackground(Color.WHITE);



/**
* Init the main content panel
*/
private void initContentPanel()
mainContentPanel = new JPanel(new BorderLayout(50, 50));
JPanel menu = initMenuFrame();
content = initContentFrame();
mainContentPanel.add(menu, BorderLayout.PAGE_START);
mainContentPanel.add(content, BorderLayout.CENTER);



private static JPanel initContentFrame()
JPanel ret = new JPanel(new BorderLayout());
JPanel pegs = new JPanel(new BorderLayout());
pegs.setBackground(Color.WHITE);
ret.setBackground(Color.WHITE);

Peg peg1 = new Peg(25, 500, 1.2);
Peg peg2 = new Peg(50, 500, 1.2);
Peg peg3 = new Peg(0, 500, 1.2);

peg1.addBlocks(pegOneBlocks);
peg2.addBlocks(pegTwoBlocks);
peg3.addBlocks(pegThreeBlocks);

pegs.add(peg1, BorderLayout.LINE_START);
pegs.add(peg2, BorderLayout.CENTER);
pegs.add(peg3, BorderLayout.LINE_END);

ret.add(pegs, BorderLayout.CENTER);
return ret;



private Color randomColor()
int R = (int)(Math.random() * 256);
int G = (int)(Math.random() * 256);
int B = (int)(Math.random() * 256);
Color color = new Color(R, G, B); // random color, but can be bright or
// dull

// to get rainbow, pastel colors
Random random = new Random();
final float hue = random.nextFloat();
final float saturation = 0.9f;// 1.0 for brilliant, 0.0 for dull
final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
color = Color.getHSBColor(hue, saturation, luminance);
return color;



private void initRandomColors()
for (int i = 0; i < 8; i++)
randomColors[i] = randomColor();




private void initBlocks(int numBlocks)
int startWidth = Block.LONGESTWIDTH;
for (int i = 0; i < numBlocks; i++)
Block b = new Block((startWidth - (i * 15)), randomColors[i]);
pegOneBlocks.add(b);




private static void clearContentFrame()
mainContentPanel.remove(content);
mainContentPanel.repaint();



private void clearBlockArrays()
pegOneBlocks.clear();
pegTwoBlocks.clear();
pegThreeBlocks.clear();



public static void reDrawContentFrame()
content = initContentFrame();
mainContentPanel.add(content, BorderLayout.CENTER);
mainContentPanel.repaint();



public static void moveTopBlock(int startPin, int destinationPin)
Block b = null;
if (startPin == 0)
b = pegOneBlocks.get(pegOneBlocks.size() - 1);
pegOneBlocks.remove(pegOneBlocks.size() - 1);

else if (startPin == 1)
b = pegTwoBlocks.get(pegTwoBlocks.size() - 1);
pegTwoBlocks.remove(pegTwoBlocks.size() - 1);

else if (startPin == 2)
b = pegThreeBlocks.get(pegThreeBlocks.size() - 1);
pegThreeBlocks.remove(pegThreeBlocks.size() - 1);


if (destinationPin == 0)
pegOneBlocks.add(b);

else if (destinationPin == 1)
pegTwoBlocks.add(b);

else if (destinationPin == 2)
pegThreeBlocks.add(b);


reDrawContentFrame();
content.validate();
mainContentPanel.validate();
mainWindow.validate();



/**
* Build the menu panel
*
* @return menu panel
*/
private JPanel initMenuFrame()
JPanel ret = new JPanel(new BorderLayout());
ret.setPreferredSize(menuSize);

// left
JPanel left = new JPanel(new FlowLayout());
left.setPreferredSize(menuSize);
JLabel label = new JLabel("DISCS: 3");
discs = label;
label.setFont(new Font("Serif", Font.BOLD, DISCSTEXTSIZE));
Button down = new Button("Decrease");
down.addActionListener(downButtonListener);
Button up = new Button("Increase");
up.addActionListener(upButtonListener);
left.add(label);
left.add(up);
left.add(down);

// mid
moves = new JLabel("MOVES: 0");
moves.setHorizontalAlignment(JLabel.CENTER);
moves.setFont(new Font("Serif", Font.BOLD, MOVESTEXTSIZE));

// right
JPanel right = new JPanel(new FlowLayout());
Button solve = new Button("Solve");
solve.addActionListener(solveButtonListener);
Button reset = new Button("Reset");
right.add(solve);
right.add(reset);

// sync
JPanel menu = new JPanel(new BorderLayout());
menu.add(left, BorderLayout.LINE_START);
menu.add(moves, BorderLayout.CENTER);
menu.add(right, BorderLayout.LINE_END);

ret.add(menu, BorderLayout.CENTER);
return ret;











share|improve this question



























    up vote
    0
    down vote

    favorite












    My project uses Java Swing as a GUI. I am making a Towers of Hanoi game. I've just about got the GUI all working, but my solve command wont work properly.



    Without threading calls, it immediately solves the towers as expected. I added a couple Thread.waits expected it to solve it step by step so the user can see how it does but instead, it waits some time, then solves the entire puzzle at once. I'm thinking it might not be repainting, but I'm not sure why. Does anyone know what is going on?



    Heres the code for the solve:



    public class Solver {

    public Solver()
    // nothing



    public void solve(
    int numberBlocks,
    int startPin,
    int auxiliaryPin,
    int endPin)
    if (numberBlocks == 1)
    movePin(startPin, endPin);
    try
    Thread.sleep(200);

    catch (InterruptedException e)
    // TODO Auto-generated catch block
    e.printStackTrace();


    else
    solve(numberBlocks - 1, startPin, endPin, auxiliaryPin);
    movePin(startPin, endPin);
    try
    Thread.sleep(200);

    catch (InterruptedException e)
    // TODO Auto-generated catch block
    e.printStackTrace();

    solve(numberBlocks - 1, auxiliaryPin, startPin, endPin);




    private void movePin(int startPin, int endPin)
    TowersOfHanoiGame.moveTopBlock(startPin, endPin);



    Here is the code from the GUI that does the work:
    I know its terribly written, this is my first time writing with Java Swing, Im learning it as I go. If anyone has any pointers on how to better structure this, I'd love to hear about that also.
    I'm pasting the whole class, but the important methods are initListeners, and moveTopBlock, and the methods they call.



    import java.awt.BorderLayout;
    import java.awt.Button;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.Random;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextField;

    public class TowersOfHanoiGame
    private static JFrame mainWindow;
    private static JPanel mainContentPanel;
    private static JPanel content;

    private static ArrayList<Block> pegOneBlocks = new ArrayList<Block>();
    private static ArrayList<Block> pegTwoBlocks = new ArrayList<Block>();
    private static ArrayList<Block> pegThreeBlocks = new ArrayList<Block>();
    private Color randomColors = new Color[8];

    private Dimension menuSize = new Dimension(100, 100);
    private static final int DISCSTEXTSIZE = 20;
    private static final int MOVESTEXTSIZE = 30;

    private ActionListener downButtonListener;
    private ActionListener upButtonListener;
    private ActionListener solveButtonListener;

    private JLabel discs;
    private JLabel moves;

    private int discsNumber = 3;
    private int movesNumber = 0;

    private Solver solver = new Solver();


    public TowersOfHanoiGame()
    // do nothing
    initRandomColors();
    initBlocks(3);



    /**
    * Initialize and display the game
    */
    public void display()
    initListeners();
    initWindow();
    mainWindow.setVisible(true);



    private void initListeners()
    downButtonListener = new ActionListener()
    @Override
    public void actionPerformed(ActionEvent arg0)
    if (discsNumber > 3)
    discsNumber--;
    updateLabels();
    // clearContentFrame();
    clearBlockArrays();
    initBlocks(discsNumber);
    reDrawContentFrame();



    ;
    upButtonListener = new ActionListener()
    public void actionPerformed(ActionEvent arg0)
    if (discsNumber < 8)
    discsNumber++;
    updateLabels();
    // clearContentFrame();
    clearBlockArrays();
    initBlocks(discsNumber);
    reDrawContentFrame();


    ;

    solveButtonListener = new ActionListener()
    public void actionPerformed(ActionEvent arg0)
    solver.solve(discsNumber, 0, 1, 2);

    ;



    private void updateLabels()
    discs.setText("DISCS: " + discsNumber);
    moves.setText("MOVES: " + movesNumber);



    /**
    * Init the main window
    */
    private void initWindow()
    mainWindow = new JFrame("Towers Of Hanoi");
    initContentPanel();
    mainWindow.setContentPane(mainContentPanel);
    mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mainWindow.setSize(1000, 1000);
    mainWindow.setResizable(false);
    mainWindow.getContentPane().setBackground(Color.WHITE);



    /**
    * Init the main content panel
    */
    private void initContentPanel()
    mainContentPanel = new JPanel(new BorderLayout(50, 50));
    JPanel menu = initMenuFrame();
    content = initContentFrame();
    mainContentPanel.add(menu, BorderLayout.PAGE_START);
    mainContentPanel.add(content, BorderLayout.CENTER);



    private static JPanel initContentFrame()
    JPanel ret = new JPanel(new BorderLayout());
    JPanel pegs = new JPanel(new BorderLayout());
    pegs.setBackground(Color.WHITE);
    ret.setBackground(Color.WHITE);

    Peg peg1 = new Peg(25, 500, 1.2);
    Peg peg2 = new Peg(50, 500, 1.2);
    Peg peg3 = new Peg(0, 500, 1.2);

    peg1.addBlocks(pegOneBlocks);
    peg2.addBlocks(pegTwoBlocks);
    peg3.addBlocks(pegThreeBlocks);

    pegs.add(peg1, BorderLayout.LINE_START);
    pegs.add(peg2, BorderLayout.CENTER);
    pegs.add(peg3, BorderLayout.LINE_END);

    ret.add(pegs, BorderLayout.CENTER);
    return ret;



    private Color randomColor()
    int R = (int)(Math.random() * 256);
    int G = (int)(Math.random() * 256);
    int B = (int)(Math.random() * 256);
    Color color = new Color(R, G, B); // random color, but can be bright or
    // dull

    // to get rainbow, pastel colors
    Random random = new Random();
    final float hue = random.nextFloat();
    final float saturation = 0.9f;// 1.0 for brilliant, 0.0 for dull
    final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
    color = Color.getHSBColor(hue, saturation, luminance);
    return color;



    private void initRandomColors()
    for (int i = 0; i < 8; i++)
    randomColors[i] = randomColor();




    private void initBlocks(int numBlocks)
    int startWidth = Block.LONGESTWIDTH;
    for (int i = 0; i < numBlocks; i++)
    Block b = new Block((startWidth - (i * 15)), randomColors[i]);
    pegOneBlocks.add(b);




    private static void clearContentFrame()
    mainContentPanel.remove(content);
    mainContentPanel.repaint();



    private void clearBlockArrays()
    pegOneBlocks.clear();
    pegTwoBlocks.clear();
    pegThreeBlocks.clear();



    public static void reDrawContentFrame()
    content = initContentFrame();
    mainContentPanel.add(content, BorderLayout.CENTER);
    mainContentPanel.repaint();



    public static void moveTopBlock(int startPin, int destinationPin)
    Block b = null;
    if (startPin == 0)
    b = pegOneBlocks.get(pegOneBlocks.size() - 1);
    pegOneBlocks.remove(pegOneBlocks.size() - 1);

    else if (startPin == 1)
    b = pegTwoBlocks.get(pegTwoBlocks.size() - 1);
    pegTwoBlocks.remove(pegTwoBlocks.size() - 1);

    else if (startPin == 2)
    b = pegThreeBlocks.get(pegThreeBlocks.size() - 1);
    pegThreeBlocks.remove(pegThreeBlocks.size() - 1);


    if (destinationPin == 0)
    pegOneBlocks.add(b);

    else if (destinationPin == 1)
    pegTwoBlocks.add(b);

    else if (destinationPin == 2)
    pegThreeBlocks.add(b);


    reDrawContentFrame();
    content.validate();
    mainContentPanel.validate();
    mainWindow.validate();



    /**
    * Build the menu panel
    *
    * @return menu panel
    */
    private JPanel initMenuFrame()
    JPanel ret = new JPanel(new BorderLayout());
    ret.setPreferredSize(menuSize);

    // left
    JPanel left = new JPanel(new FlowLayout());
    left.setPreferredSize(menuSize);
    JLabel label = new JLabel("DISCS: 3");
    discs = label;
    label.setFont(new Font("Serif", Font.BOLD, DISCSTEXTSIZE));
    Button down = new Button("Decrease");
    down.addActionListener(downButtonListener);
    Button up = new Button("Increase");
    up.addActionListener(upButtonListener);
    left.add(label);
    left.add(up);
    left.add(down);

    // mid
    moves = new JLabel("MOVES: 0");
    moves.setHorizontalAlignment(JLabel.CENTER);
    moves.setFont(new Font("Serif", Font.BOLD, MOVESTEXTSIZE));

    // right
    JPanel right = new JPanel(new FlowLayout());
    Button solve = new Button("Solve");
    solve.addActionListener(solveButtonListener);
    Button reset = new Button("Reset");
    right.add(solve);
    right.add(reset);

    // sync
    JPanel menu = new JPanel(new BorderLayout());
    menu.add(left, BorderLayout.LINE_START);
    menu.add(moves, BorderLayout.CENTER);
    menu.add(right, BorderLayout.LINE_END);

    ret.add(menu, BorderLayout.CENTER);
    return ret;











    share|improve this question

























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      My project uses Java Swing as a GUI. I am making a Towers of Hanoi game. I've just about got the GUI all working, but my solve command wont work properly.



      Without threading calls, it immediately solves the towers as expected. I added a couple Thread.waits expected it to solve it step by step so the user can see how it does but instead, it waits some time, then solves the entire puzzle at once. I'm thinking it might not be repainting, but I'm not sure why. Does anyone know what is going on?



      Heres the code for the solve:



      public class Solver {

      public Solver()
      // nothing



      public void solve(
      int numberBlocks,
      int startPin,
      int auxiliaryPin,
      int endPin)
      if (numberBlocks == 1)
      movePin(startPin, endPin);
      try
      Thread.sleep(200);

      catch (InterruptedException e)
      // TODO Auto-generated catch block
      e.printStackTrace();


      else
      solve(numberBlocks - 1, startPin, endPin, auxiliaryPin);
      movePin(startPin, endPin);
      try
      Thread.sleep(200);

      catch (InterruptedException e)
      // TODO Auto-generated catch block
      e.printStackTrace();

      solve(numberBlocks - 1, auxiliaryPin, startPin, endPin);




      private void movePin(int startPin, int endPin)
      TowersOfHanoiGame.moveTopBlock(startPin, endPin);



      Here is the code from the GUI that does the work:
      I know its terribly written, this is my first time writing with Java Swing, Im learning it as I go. If anyone has any pointers on how to better structure this, I'd love to hear about that also.
      I'm pasting the whole class, but the important methods are initListeners, and moveTopBlock, and the methods they call.



      import java.awt.BorderLayout;
      import java.awt.Button;
      import java.awt.Color;
      import java.awt.Dimension;
      import java.awt.FlowLayout;
      import java.awt.Font;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.util.ArrayList;
      import java.util.Random;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      import javax.swing.JTextField;

      public class TowersOfHanoiGame
      private static JFrame mainWindow;
      private static JPanel mainContentPanel;
      private static JPanel content;

      private static ArrayList<Block> pegOneBlocks = new ArrayList<Block>();
      private static ArrayList<Block> pegTwoBlocks = new ArrayList<Block>();
      private static ArrayList<Block> pegThreeBlocks = new ArrayList<Block>();
      private Color randomColors = new Color[8];

      private Dimension menuSize = new Dimension(100, 100);
      private static final int DISCSTEXTSIZE = 20;
      private static final int MOVESTEXTSIZE = 30;

      private ActionListener downButtonListener;
      private ActionListener upButtonListener;
      private ActionListener solveButtonListener;

      private JLabel discs;
      private JLabel moves;

      private int discsNumber = 3;
      private int movesNumber = 0;

      private Solver solver = new Solver();


      public TowersOfHanoiGame()
      // do nothing
      initRandomColors();
      initBlocks(3);



      /**
      * Initialize and display the game
      */
      public void display()
      initListeners();
      initWindow();
      mainWindow.setVisible(true);



      private void initListeners()
      downButtonListener = new ActionListener()
      @Override
      public void actionPerformed(ActionEvent arg0)
      if (discsNumber > 3)
      discsNumber--;
      updateLabels();
      // clearContentFrame();
      clearBlockArrays();
      initBlocks(discsNumber);
      reDrawContentFrame();



      ;
      upButtonListener = new ActionListener()
      public void actionPerformed(ActionEvent arg0)
      if (discsNumber < 8)
      discsNumber++;
      updateLabels();
      // clearContentFrame();
      clearBlockArrays();
      initBlocks(discsNumber);
      reDrawContentFrame();


      ;

      solveButtonListener = new ActionListener()
      public void actionPerformed(ActionEvent arg0)
      solver.solve(discsNumber, 0, 1, 2);

      ;



      private void updateLabels()
      discs.setText("DISCS: " + discsNumber);
      moves.setText("MOVES: " + movesNumber);



      /**
      * Init the main window
      */
      private void initWindow()
      mainWindow = new JFrame("Towers Of Hanoi");
      initContentPanel();
      mainWindow.setContentPane(mainContentPanel);
      mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mainWindow.setSize(1000, 1000);
      mainWindow.setResizable(false);
      mainWindow.getContentPane().setBackground(Color.WHITE);



      /**
      * Init the main content panel
      */
      private void initContentPanel()
      mainContentPanel = new JPanel(new BorderLayout(50, 50));
      JPanel menu = initMenuFrame();
      content = initContentFrame();
      mainContentPanel.add(menu, BorderLayout.PAGE_START);
      mainContentPanel.add(content, BorderLayout.CENTER);



      private static JPanel initContentFrame()
      JPanel ret = new JPanel(new BorderLayout());
      JPanel pegs = new JPanel(new BorderLayout());
      pegs.setBackground(Color.WHITE);
      ret.setBackground(Color.WHITE);

      Peg peg1 = new Peg(25, 500, 1.2);
      Peg peg2 = new Peg(50, 500, 1.2);
      Peg peg3 = new Peg(0, 500, 1.2);

      peg1.addBlocks(pegOneBlocks);
      peg2.addBlocks(pegTwoBlocks);
      peg3.addBlocks(pegThreeBlocks);

      pegs.add(peg1, BorderLayout.LINE_START);
      pegs.add(peg2, BorderLayout.CENTER);
      pegs.add(peg3, BorderLayout.LINE_END);

      ret.add(pegs, BorderLayout.CENTER);
      return ret;



      private Color randomColor()
      int R = (int)(Math.random() * 256);
      int G = (int)(Math.random() * 256);
      int B = (int)(Math.random() * 256);
      Color color = new Color(R, G, B); // random color, but can be bright or
      // dull

      // to get rainbow, pastel colors
      Random random = new Random();
      final float hue = random.nextFloat();
      final float saturation = 0.9f;// 1.0 for brilliant, 0.0 for dull
      final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
      color = Color.getHSBColor(hue, saturation, luminance);
      return color;



      private void initRandomColors()
      for (int i = 0; i < 8; i++)
      randomColors[i] = randomColor();




      private void initBlocks(int numBlocks)
      int startWidth = Block.LONGESTWIDTH;
      for (int i = 0; i < numBlocks; i++)
      Block b = new Block((startWidth - (i * 15)), randomColors[i]);
      pegOneBlocks.add(b);




      private static void clearContentFrame()
      mainContentPanel.remove(content);
      mainContentPanel.repaint();



      private void clearBlockArrays()
      pegOneBlocks.clear();
      pegTwoBlocks.clear();
      pegThreeBlocks.clear();



      public static void reDrawContentFrame()
      content = initContentFrame();
      mainContentPanel.add(content, BorderLayout.CENTER);
      mainContentPanel.repaint();



      public static void moveTopBlock(int startPin, int destinationPin)
      Block b = null;
      if (startPin == 0)
      b = pegOneBlocks.get(pegOneBlocks.size() - 1);
      pegOneBlocks.remove(pegOneBlocks.size() - 1);

      else if (startPin == 1)
      b = pegTwoBlocks.get(pegTwoBlocks.size() - 1);
      pegTwoBlocks.remove(pegTwoBlocks.size() - 1);

      else if (startPin == 2)
      b = pegThreeBlocks.get(pegThreeBlocks.size() - 1);
      pegThreeBlocks.remove(pegThreeBlocks.size() - 1);


      if (destinationPin == 0)
      pegOneBlocks.add(b);

      else if (destinationPin == 1)
      pegTwoBlocks.add(b);

      else if (destinationPin == 2)
      pegThreeBlocks.add(b);


      reDrawContentFrame();
      content.validate();
      mainContentPanel.validate();
      mainWindow.validate();



      /**
      * Build the menu panel
      *
      * @return menu panel
      */
      private JPanel initMenuFrame()
      JPanel ret = new JPanel(new BorderLayout());
      ret.setPreferredSize(menuSize);

      // left
      JPanel left = new JPanel(new FlowLayout());
      left.setPreferredSize(menuSize);
      JLabel label = new JLabel("DISCS: 3");
      discs = label;
      label.setFont(new Font("Serif", Font.BOLD, DISCSTEXTSIZE));
      Button down = new Button("Decrease");
      down.addActionListener(downButtonListener);
      Button up = new Button("Increase");
      up.addActionListener(upButtonListener);
      left.add(label);
      left.add(up);
      left.add(down);

      // mid
      moves = new JLabel("MOVES: 0");
      moves.setHorizontalAlignment(JLabel.CENTER);
      moves.setFont(new Font("Serif", Font.BOLD, MOVESTEXTSIZE));

      // right
      JPanel right = new JPanel(new FlowLayout());
      Button solve = new Button("Solve");
      solve.addActionListener(solveButtonListener);
      Button reset = new Button("Reset");
      right.add(solve);
      right.add(reset);

      // sync
      JPanel menu = new JPanel(new BorderLayout());
      menu.add(left, BorderLayout.LINE_START);
      menu.add(moves, BorderLayout.CENTER);
      menu.add(right, BorderLayout.LINE_END);

      ret.add(menu, BorderLayout.CENTER);
      return ret;











      share|improve this question















      My project uses Java Swing as a GUI. I am making a Towers of Hanoi game. I've just about got the GUI all working, but my solve command wont work properly.



      Without threading calls, it immediately solves the towers as expected. I added a couple Thread.waits expected it to solve it step by step so the user can see how it does but instead, it waits some time, then solves the entire puzzle at once. I'm thinking it might not be repainting, but I'm not sure why. Does anyone know what is going on?



      Heres the code for the solve:



      public class Solver {

      public Solver()
      // nothing



      public void solve(
      int numberBlocks,
      int startPin,
      int auxiliaryPin,
      int endPin)
      if (numberBlocks == 1)
      movePin(startPin, endPin);
      try
      Thread.sleep(200);

      catch (InterruptedException e)
      // TODO Auto-generated catch block
      e.printStackTrace();


      else
      solve(numberBlocks - 1, startPin, endPin, auxiliaryPin);
      movePin(startPin, endPin);
      try
      Thread.sleep(200);

      catch (InterruptedException e)
      // TODO Auto-generated catch block
      e.printStackTrace();

      solve(numberBlocks - 1, auxiliaryPin, startPin, endPin);




      private void movePin(int startPin, int endPin)
      TowersOfHanoiGame.moveTopBlock(startPin, endPin);



      Here is the code from the GUI that does the work:
      I know its terribly written, this is my first time writing with Java Swing, Im learning it as I go. If anyone has any pointers on how to better structure this, I'd love to hear about that also.
      I'm pasting the whole class, but the important methods are initListeners, and moveTopBlock, and the methods they call.



      import java.awt.BorderLayout;
      import java.awt.Button;
      import java.awt.Color;
      import java.awt.Dimension;
      import java.awt.FlowLayout;
      import java.awt.Font;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.util.ArrayList;
      import java.util.Random;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JPanel;
      import javax.swing.JTextField;

      public class TowersOfHanoiGame
      private static JFrame mainWindow;
      private static JPanel mainContentPanel;
      private static JPanel content;

      private static ArrayList<Block> pegOneBlocks = new ArrayList<Block>();
      private static ArrayList<Block> pegTwoBlocks = new ArrayList<Block>();
      private static ArrayList<Block> pegThreeBlocks = new ArrayList<Block>();
      private Color randomColors = new Color[8];

      private Dimension menuSize = new Dimension(100, 100);
      private static final int DISCSTEXTSIZE = 20;
      private static final int MOVESTEXTSIZE = 30;

      private ActionListener downButtonListener;
      private ActionListener upButtonListener;
      private ActionListener solveButtonListener;

      private JLabel discs;
      private JLabel moves;

      private int discsNumber = 3;
      private int movesNumber = 0;

      private Solver solver = new Solver();


      public TowersOfHanoiGame()
      // do nothing
      initRandomColors();
      initBlocks(3);



      /**
      * Initialize and display the game
      */
      public void display()
      initListeners();
      initWindow();
      mainWindow.setVisible(true);



      private void initListeners()
      downButtonListener = new ActionListener()
      @Override
      public void actionPerformed(ActionEvent arg0)
      if (discsNumber > 3)
      discsNumber--;
      updateLabels();
      // clearContentFrame();
      clearBlockArrays();
      initBlocks(discsNumber);
      reDrawContentFrame();



      ;
      upButtonListener = new ActionListener()
      public void actionPerformed(ActionEvent arg0)
      if (discsNumber < 8)
      discsNumber++;
      updateLabels();
      // clearContentFrame();
      clearBlockArrays();
      initBlocks(discsNumber);
      reDrawContentFrame();


      ;

      solveButtonListener = new ActionListener()
      public void actionPerformed(ActionEvent arg0)
      solver.solve(discsNumber, 0, 1, 2);

      ;



      private void updateLabels()
      discs.setText("DISCS: " + discsNumber);
      moves.setText("MOVES: " + movesNumber);



      /**
      * Init the main window
      */
      private void initWindow()
      mainWindow = new JFrame("Towers Of Hanoi");
      initContentPanel();
      mainWindow.setContentPane(mainContentPanel);
      mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mainWindow.setSize(1000, 1000);
      mainWindow.setResizable(false);
      mainWindow.getContentPane().setBackground(Color.WHITE);



      /**
      * Init the main content panel
      */
      private void initContentPanel()
      mainContentPanel = new JPanel(new BorderLayout(50, 50));
      JPanel menu = initMenuFrame();
      content = initContentFrame();
      mainContentPanel.add(menu, BorderLayout.PAGE_START);
      mainContentPanel.add(content, BorderLayout.CENTER);



      private static JPanel initContentFrame()
      JPanel ret = new JPanel(new BorderLayout());
      JPanel pegs = new JPanel(new BorderLayout());
      pegs.setBackground(Color.WHITE);
      ret.setBackground(Color.WHITE);

      Peg peg1 = new Peg(25, 500, 1.2);
      Peg peg2 = new Peg(50, 500, 1.2);
      Peg peg3 = new Peg(0, 500, 1.2);

      peg1.addBlocks(pegOneBlocks);
      peg2.addBlocks(pegTwoBlocks);
      peg3.addBlocks(pegThreeBlocks);

      pegs.add(peg1, BorderLayout.LINE_START);
      pegs.add(peg2, BorderLayout.CENTER);
      pegs.add(peg3, BorderLayout.LINE_END);

      ret.add(pegs, BorderLayout.CENTER);
      return ret;



      private Color randomColor()
      int R = (int)(Math.random() * 256);
      int G = (int)(Math.random() * 256);
      int B = (int)(Math.random() * 256);
      Color color = new Color(R, G, B); // random color, but can be bright or
      // dull

      // to get rainbow, pastel colors
      Random random = new Random();
      final float hue = random.nextFloat();
      final float saturation = 0.9f;// 1.0 for brilliant, 0.0 for dull
      final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
      color = Color.getHSBColor(hue, saturation, luminance);
      return color;



      private void initRandomColors()
      for (int i = 0; i < 8; i++)
      randomColors[i] = randomColor();




      private void initBlocks(int numBlocks)
      int startWidth = Block.LONGESTWIDTH;
      for (int i = 0; i < numBlocks; i++)
      Block b = new Block((startWidth - (i * 15)), randomColors[i]);
      pegOneBlocks.add(b);




      private static void clearContentFrame()
      mainContentPanel.remove(content);
      mainContentPanel.repaint();



      private void clearBlockArrays()
      pegOneBlocks.clear();
      pegTwoBlocks.clear();
      pegThreeBlocks.clear();



      public static void reDrawContentFrame()
      content = initContentFrame();
      mainContentPanel.add(content, BorderLayout.CENTER);
      mainContentPanel.repaint();



      public static void moveTopBlock(int startPin, int destinationPin)
      Block b = null;
      if (startPin == 0)
      b = pegOneBlocks.get(pegOneBlocks.size() - 1);
      pegOneBlocks.remove(pegOneBlocks.size() - 1);

      else if (startPin == 1)
      b = pegTwoBlocks.get(pegTwoBlocks.size() - 1);
      pegTwoBlocks.remove(pegTwoBlocks.size() - 1);

      else if (startPin == 2)
      b = pegThreeBlocks.get(pegThreeBlocks.size() - 1);
      pegThreeBlocks.remove(pegThreeBlocks.size() - 1);


      if (destinationPin == 0)
      pegOneBlocks.add(b);

      else if (destinationPin == 1)
      pegTwoBlocks.add(b);

      else if (destinationPin == 2)
      pegThreeBlocks.add(b);


      reDrawContentFrame();
      content.validate();
      mainContentPanel.validate();
      mainWindow.validate();



      /**
      * Build the menu panel
      *
      * @return menu panel
      */
      private JPanel initMenuFrame()
      JPanel ret = new JPanel(new BorderLayout());
      ret.setPreferredSize(menuSize);

      // left
      JPanel left = new JPanel(new FlowLayout());
      left.setPreferredSize(menuSize);
      JLabel label = new JLabel("DISCS: 3");
      discs = label;
      label.setFont(new Font("Serif", Font.BOLD, DISCSTEXTSIZE));
      Button down = new Button("Decrease");
      down.addActionListener(downButtonListener);
      Button up = new Button("Increase");
      up.addActionListener(upButtonListener);
      left.add(label);
      left.add(up);
      left.add(down);

      // mid
      moves = new JLabel("MOVES: 0");
      moves.setHorizontalAlignment(JLabel.CENTER);
      moves.setFont(new Font("Serif", Font.BOLD, MOVESTEXTSIZE));

      // right
      JPanel right = new JPanel(new FlowLayout());
      Button solve = new Button("Solve");
      solve.addActionListener(solveButtonListener);
      Button reset = new Button("Reset");
      right.add(solve);
      right.add(reset);

      // sync
      JPanel menu = new JPanel(new BorderLayout());
      menu.add(left, BorderLayout.LINE_START);
      menu.add(moves, BorderLayout.CENTER);
      menu.add(right, BorderLayout.LINE_END);

      ret.add(menu, BorderLayout.CENTER);
      return ret;








      java swing awt border-layout towers-of-hanoi






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 10 at 20:42









      rishabh agarwal

      692316




      692316










      asked Nov 10 at 18:24









      Quentin Simoneaux

      1




      1






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote













          solveButtonListener = new ActionListener() 
          public void actionPerformed(ActionEvent arg0)
          solver.solve(discsNumber, 0, 1, 2);

          ;


          The problem is that code invoked for any listener is executed on the Event Dispatch Thread (EDT). The EDT is responsible for responding to event and repaint the GUI. The Thread.sleep() method causes the EDT to sleep and as a result the GUI can't repaint itself until all the code has finished executing.



          What you need to do is start a separate Thread when you invoke the solver.solve(...) method.



          Read the section from the Swing tutorial on Concurrency for more information.



          Note, the above suggestion to use a separate Thread is still not a proper solution. Swing was designed to be single Thread, which means that all updates to the state of your GUI and the repainting of the GUI should be done on the EDT. So this would mean you should also be using SwingUtilities.invokeLater() to add code to the EDT for processing. I have never tried doing this when using recursion, so I'm not sure the best way to do this.






          share|improve this answer




















          • Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
            – Quentin Simoneaux
            Nov 11 at 1:43










          • @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
            – camickr
            Nov 11 at 5:56










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53242086%2fwhy-wont-this-threading-code-work-properly-with-the-gui-java-swing-threading%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          1
          down vote













          solveButtonListener = new ActionListener() 
          public void actionPerformed(ActionEvent arg0)
          solver.solve(discsNumber, 0, 1, 2);

          ;


          The problem is that code invoked for any listener is executed on the Event Dispatch Thread (EDT). The EDT is responsible for responding to event and repaint the GUI. The Thread.sleep() method causes the EDT to sleep and as a result the GUI can't repaint itself until all the code has finished executing.



          What you need to do is start a separate Thread when you invoke the solver.solve(...) method.



          Read the section from the Swing tutorial on Concurrency for more information.



          Note, the above suggestion to use a separate Thread is still not a proper solution. Swing was designed to be single Thread, which means that all updates to the state of your GUI and the repainting of the GUI should be done on the EDT. So this would mean you should also be using SwingUtilities.invokeLater() to add code to the EDT for processing. I have never tried doing this when using recursion, so I'm not sure the best way to do this.






          share|improve this answer




















          • Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
            – Quentin Simoneaux
            Nov 11 at 1:43










          • @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
            – camickr
            Nov 11 at 5:56














          up vote
          1
          down vote













          solveButtonListener = new ActionListener() 
          public void actionPerformed(ActionEvent arg0)
          solver.solve(discsNumber, 0, 1, 2);

          ;


          The problem is that code invoked for any listener is executed on the Event Dispatch Thread (EDT). The EDT is responsible for responding to event and repaint the GUI. The Thread.sleep() method causes the EDT to sleep and as a result the GUI can't repaint itself until all the code has finished executing.



          What you need to do is start a separate Thread when you invoke the solver.solve(...) method.



          Read the section from the Swing tutorial on Concurrency for more information.



          Note, the above suggestion to use a separate Thread is still not a proper solution. Swing was designed to be single Thread, which means that all updates to the state of your GUI and the repainting of the GUI should be done on the EDT. So this would mean you should also be using SwingUtilities.invokeLater() to add code to the EDT for processing. I have never tried doing this when using recursion, so I'm not sure the best way to do this.






          share|improve this answer




















          • Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
            – Quentin Simoneaux
            Nov 11 at 1:43










          • @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
            – camickr
            Nov 11 at 5:56












          up vote
          1
          down vote










          up vote
          1
          down vote









          solveButtonListener = new ActionListener() 
          public void actionPerformed(ActionEvent arg0)
          solver.solve(discsNumber, 0, 1, 2);

          ;


          The problem is that code invoked for any listener is executed on the Event Dispatch Thread (EDT). The EDT is responsible for responding to event and repaint the GUI. The Thread.sleep() method causes the EDT to sleep and as a result the GUI can't repaint itself until all the code has finished executing.



          What you need to do is start a separate Thread when you invoke the solver.solve(...) method.



          Read the section from the Swing tutorial on Concurrency for more information.



          Note, the above suggestion to use a separate Thread is still not a proper solution. Swing was designed to be single Thread, which means that all updates to the state of your GUI and the repainting of the GUI should be done on the EDT. So this would mean you should also be using SwingUtilities.invokeLater() to add code to the EDT for processing. I have never tried doing this when using recursion, so I'm not sure the best way to do this.






          share|improve this answer












          solveButtonListener = new ActionListener() 
          public void actionPerformed(ActionEvent arg0)
          solver.solve(discsNumber, 0, 1, 2);

          ;


          The problem is that code invoked for any listener is executed on the Event Dispatch Thread (EDT). The EDT is responsible for responding to event and repaint the GUI. The Thread.sleep() method causes the EDT to sleep and as a result the GUI can't repaint itself until all the code has finished executing.



          What you need to do is start a separate Thread when you invoke the solver.solve(...) method.



          Read the section from the Swing tutorial on Concurrency for more information.



          Note, the above suggestion to use a separate Thread is still not a proper solution. Swing was designed to be single Thread, which means that all updates to the state of your GUI and the repainting of the GUI should be done on the EDT. So this would mean you should also be using SwingUtilities.invokeLater() to add code to the EDT for processing. I have never tried doing this when using recursion, so I'm not sure the best way to do this.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 10 at 19:41









          camickr

          272k14124237




          272k14124237











          • Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
            – Quentin Simoneaux
            Nov 11 at 1:43










          • @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
            – camickr
            Nov 11 at 5:56
















          • Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
            – Quentin Simoneaux
            Nov 11 at 1:43










          • @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
            – camickr
            Nov 11 at 5:56















          Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
          – Quentin Simoneaux
          Nov 11 at 1:43




          Thanks, this was very helpful and solved my issue. I ended up creating a new thread and starting it once you press solve. This thread will have its own wait and when it wants to repaint to the GUI it uses SwingUtilities.invokeLater(). I learned a bit about threading too :)
          – Quentin Simoneaux
          Nov 11 at 1:43












          @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
          – camickr
          Nov 11 at 5:56




          @QuentinSimoneaux, glad the suggestion helped. Don't forget to "accept" the answer by clicking on the checkmark so people know the problem has been solved.
          – camickr
          Nov 11 at 5:56

















           

          draft saved


          draft discarded















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53242086%2fwhy-wont-this-threading-code-work-properly-with-the-gui-java-swing-threading%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          What does pagestruct do in Eviews?

          Dutch intervention in Lombok and Karangasem

          Channel Islands