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;
java swing awt border-layout towers-of-hanoi
add a comment |
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;
java swing awt border-layout towers-of-hanoi
add a comment |
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;
java swing awt border-layout towers-of-hanoi
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
java swing awt border-layout towers-of-hanoi
edited Nov 10 at 20:42
rishabh agarwal
692316
692316
asked Nov 10 at 18:24
Quentin Simoneaux
1
1
add a comment |
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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