gvsu/cs621/proj4/KnightsTour.java
josh 86ba8c63c1 reset button starts enabled
git-svn-id: svn://anubis/gvsu@94 45c1a28c-8058-47b2-ae61-ca45b979098e
2008-03-29 00:36:25 +00:00

279 lines
10 KiB
Java

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
/**
* This class implements a GUI interface to the KnightsTourBoard class
*/
public class KnightsTour extends JFrame
{
private KnightsTourBoard m_ktBoard = new KnightsTourBoard(5, 5);
private Thread m_tourThread;
/* GUI elements */
private ActionEventHandler m_handler = new ActionEventHandler(this);
private JTextField m_widthField;
private JTextField m_heightField;
private JTextField m_startXField;
private JTextField m_startYField;
private JButton m_startButton;
private JButton m_cancelButton;
private JButton m_exitButton;
private JButton m_resetButton;
private JPanel m_mainPanel;
private JPanel m_boardPanel;
private JLabel m_statusLabel;
/**
* Construct the KnightsTour GUI interface
*/
public KnightsTour()
{
super("Josh's Knight's Tour project for CS621");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 500);
/* set up the main window contents */
getContentPane().add(m_mainPanel = new JPanel(new BorderLayout()) {{
setBorder(BorderFactory.createEmptyBorder(9, 9, 9, 9));
add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 7));
add(new JPanel() {{ /* board size panel */
setBorder(BorderFactory.createTitledBorder("Board Size"));
add(new JPanel() {{
setBorder(BorderFactory.createEmptyBorder());
setLayout(new GridLayout(2, 2, 5, 5));
add(new JLabel("Width:", SwingConstants.RIGHT));
add(m_widthField = new JTextField("5"));
add(new JLabel("Height:", SwingConstants.RIGHT));
add(m_heightField = new JTextField("5"));
}});
}});
add(new Box.Filler(new Dimension(5, 0),
new Dimension(5, 0),
new Dimension(5, 0)));
add(new JPanel() {{ /* starting position panel */
setBorder(BorderFactory.createTitledBorder("Starting Position"));
add(new JPanel() {{
setBorder(BorderFactory.createEmptyBorder());
setLayout(new GridLayout(2, 2, 5, 5));
add(new JLabel("Column (X):", SwingConstants.RIGHT));
add(m_startXField = new JTextField("2"));
add(new JLabel("Row (Y):", SwingConstants.RIGHT));
add(m_startYField = new JTextField("2"));
}});
}});
add(new Box.Filler(new Dimension(5, 0),
new Dimension(5, 0),
new Dimension(5, 0)));
add(new JPanel() {{ /* start button panel */
setBorder(BorderFactory.createTitledBorder(
"Control Knight's Tour"));
add(new JPanel() {{
setBorder(BorderFactory.createEmptyBorder());
setLayout(new GridLayout(2, 2, 5, 5));
add(m_startButton = new JButton("Start"));
m_startButton.addActionListener(m_handler);
add(m_resetButton = new JButton("Reset"));
m_resetButton.addActionListener(m_handler);
add(m_cancelButton = new JButton("Cancel"));
m_cancelButton.addActionListener(m_handler);
m_cancelButton.setEnabled(false);
add(m_exitButton = new JButton("Exit"));
m_exitButton.addActionListener(m_handler);
}});
}});
add(new Box.Filler(new Dimension(0, 0),
new Dimension(Short.MAX_VALUE, 0),
new Dimension(10000, 10000)));
}});
add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(m_statusLabel = new JLabel("Ready."));
add(new Box.Filler(new Dimension(0, 0),
new Dimension(10000, 0),
new Dimension(10000, 10000)));
}});
}}, BorderLayout.NORTH);
}});
createBoardPanel();
setVisible(true);
}
/* Create a JPanel containing a grid showing the step number
* for each board position in the KnightsTourBoard object */
private void createBoardPanel()
{
int width = m_ktBoard.getWidth();
int height = m_ktBoard.getHeight();
JPanel oldBoardPanel = m_boardPanel;
m_boardPanel = new JPanel(new GridLayout(height, width, 1, 1));
m_boardPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
JLabel l = new JLabel(m_ktBoard.getStepAt(x, y) == 0
? ""
: new Integer(m_ktBoard.getStepAt(x, y)).toString(),
SwingConstants.CENTER);
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
m_boardPanel.add(l);
}
}
if (oldBoardPanel != null)
m_mainPanel.remove(oldBoardPanel);
m_mainPanel.add(m_boardPanel);
m_mainPanel.validate();
}
/* This helper class catches actions that occur on JButton objects */
private class ActionEventHandler implements ActionListener
{
private KnightsTour m_kt;
public ActionEventHandler(KnightsTour kt) { m_kt = kt; }
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == m_startButton)
{
setUpTour(true);
}
else if (e.getSource() == m_cancelButton)
{
if (m_tourThread != null)
{
m_tourThread.stop();
m_tourThread = null;
m_startButton.setEnabled(true);
m_cancelButton.setEnabled(false);
m_resetButton.setEnabled(true);
m_statusLabel.setText("Cancelled.");
}
}
else if (e.getSource() == m_resetButton)
{
setUpTour(false);
}
else if (e.getSource() == m_exitButton)
{
System.exit(0);
}
}
}
/**
* Helper method to set up the Knight's Tour GUI board
* @param runit whether to run the tour or not (false means just reset board)
*/
private void setUpTour(boolean runit)
{
/* first validate input text fields */
int width, height, startx, starty;
try
{
width = Integer.parseInt(m_widthField.getText());
height = Integer.parseInt(m_heightField.getText());
startx = Integer.parseInt(m_startXField.getText());
starty = Integer.parseInt(m_startYField.getText());
}
catch (NumberFormatException nfe)
{
m_statusLabel.setText("Non-numerical input!");
return;
}
if (width < 1 || height < 1 || startx < 0 || starty < 0 ||
startx >= width || starty >= height)
{
m_statusLabel.setText("Invalid input!");
return;
}
/* create a new KnightsTourBoard object */
m_ktBoard = new KnightsTourBoard(width, height);
createBoardPanel();
if (runit)
{
/* run the tour in a separate thread */
m_startButton.setEnabled(false);
m_cancelButton.setEnabled(true);
m_resetButton.setEnabled(false);
m_statusLabel.setText("Running...");
m_tourThread = new Thread(new TourThread(startx, starty));
m_tourThread.start();
}
else
{
m_statusLabel.setText("Reset.");
}
}
/* This class runs as a separate thread to actually call
* tour() on the KnightsTourBoard object. This way, the GUI
* stays responsive and the user can cancel the tour by clicking
* a button if it runs for too long. */
private class TourThread implements Runnable
{
int m_startx, m_starty;
/* create the tour thread with the given starting position */
public TourThread(int startx, int starty)
{
m_startx = startx;
m_starty = starty;
}
/* called when the thread starts executing */
public void run()
{
if (m_ktBoard.tour(m_startx, m_starty))
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
createBoardPanel();
m_statusLabel.setText("Finished.");
m_startButton.setEnabled(true);
m_cancelButton.setEnabled(false);
m_resetButton.setEnabled(true);
}
});
}
else
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
createBoardPanel();
m_statusLabel.setText("Solution not found!");
m_startButton.setEnabled(true);
m_cancelButton.setEnabled(false);
m_resetButton.setEnabled(true);
}
});
}
m_tourThread = null;
}
}
/**
* This method is invoked first when the program is run.
* It simply creates a KnightsTour GUI object
*/
public static void main(String[] args)
{
KnightsTour kt = new KnightsTour();
}
}