Currently the display works fine. I coded the minutes run act as seconds for simulation clock display. It's works fine but when it is 12:59, it should be 1 instead of 0. I couldn't figure it out to remove 00:00 should be 01:00 after 12:59.
clock.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Clock
{
private JFrame frame;
private JLabel label;
private ClockDisplay clock;
private boolean clockRunning = false;
private TimerThread timerThread;
/**
* Constructor for objects of class Clock
*/
public Clock()
{
makeFrame();
clock = new ClockDisplay();
}
/**
*
*/
private void start()
{
clockRunning = true;
timerThread = new TimerThread();
timerThread.start();
}
/**
*
*/
private void stop()
{
clockRunning = false;
}
/**
*
*/
private void step()
{
clock.timeTick();
label.setText(clock.getTime());
}
/**
* 'About' function: show the 'about' box.
*/
private void showAbout()
{
JOptionPane.showMessageDialog (frame,
"Clock Version 1.0\n" +
"A simple interface for the 'Objects First' clock display project",
"About Clock",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Quit function: quit the application.
*/
private void quit()
{
System.exit(0);
}
/**
* Create the Swing frame and its content.
*/
private void makeFrame()
{
frame = new JFrame("Clock");
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setBorder(new EmptyBorder(1, 60, 1, 60));
makeMenuBar(frame);
// Specify the layout manager with nice spacing
contentPane.setLayout(new BorderLayout(12, 12));
// Create the image pane in the center
label = new JLabel("00:00", SwingConstants.CENTER);
Font displayFont = label.getFont().deriveFont(96.0f);
label.setFont(displayFont);
//imagePanel.setBorder(new EtchedBorder());
contentPane.add(label, BorderLayout.CENTER);
// Create the toolbar with the buttons
JPanel toolbar = new JPanel();
toolbar.setLayout(new GridLayout(1, 0));
JButton startButton = new JButton("Start");
startButton.addActionListener(e -> start());
toolbar.add(startButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(e -> stop());
toolbar.add(stopButton);
JButton stepButton = new JButton("Step");
stepButton.addActionListener(e -> step());
toolbar.add(stepButton);
// Add toolbar into panel with flow layout for spacing
JPanel flow = new JPanel();
flow.add(toolbar);
contentPane.add(flow, BorderLayout.SOUTH);
// building is done - arrange the components
frame.pack();
// place the frame at the center of the screen and show
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(d.width/2 - frame.getWidth()/2, d.height/2 - frame.getHeight()/2);
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
*
* #param frame The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame)
{
final int SHORTCUT_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu menu;
JMenuItem item;
// create the File menu
menu = new JMenu("File");
menubar.add(menu);
item = new JMenuItem("About Clock...");
item.addActionListener(e -> showAbout());
menu.add(item);
menu.addSeparator();
item = new JMenuItem("Quit");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, SHORTCUT_MASK));
item.addActionListener(e -> quit());
menu.add(item);
}
class TimerThread extends Thread
{
public void run()
{
while (clockRunning) {
step();
pause();
}
}
private void pause()
{
try {
Thread.sleep(300); // pause for 300 milliseconds
}
catch (InterruptedException exc) {
}
}
}
}
clock.java should be locked as this is working properly.
numDisplay.java
/**
* The NumberDisplay class represents a digital number display that can hold
* values from zero to a given limit. The limit can be specified when
* creating the display. The values range from zero (inclusive) to limit-1.
* If used,
* for example, for the seconds on a digital clock, the limit would be 60,
* resulting in display values from 0 to 59. When incremented, the display
* automatically rolls over to zero when reaching the limit.
*/
public class NumberDisplay
{
private int limit = 13;
private int value;
/**
* Constructor for objects of class NumberDisplay.
* Set the limit at which the display rolls over.
*/
public NumberDisplay(int rollOverLimit)
{
limit = rollOverLimit;
value = 1;
}
/*
*
*/
/**
* Return the current value.
*/
public int getValue()
{
return value;
}
/**
* Return the display value (that is, the current value as a two-digit
* String. If the value is less than ten, it will be padded with a leading
* zero).
*/
public String getDisplayValue()
{
if(value < 10) {
return "0" + value; // stay 0 appears in left
}
else {
return "" + value; // none to show in right of the display
}
}
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public void setValue(int replacementValue)
{
if((replacementValue >= 2) & (replacementValue < limit)) {
value = replacementValue;
}
}
/**
* Increment the display value by one, rolling over to zero if the
* limit is reached.
*/
public void increment()
{
value = (value + 1) % limit; // this is already the time by 1
}
}
I also left comments to help understanding what they are running program.
This is last one called "Display" which is named ClockDisplay.java:
/**
* The ClockDisplay class implements a digital clock display for a
* European-style 24 hour clock. The clock shows hours and minutes. The
* range of the clock is 00:00 (midnight) to 23:59 (one minute before
* midnight).
*
* The clock display receives "ticks" (via the timeTick method) every minute
* and reacts by incrementing the display. This is done in the usual clock
* fashion: the hour increments when the minutes roll over to zero.
*/
public class ClockDisplay
{
private NumberDisplay hours; // runs from 1 am/pm to 11:59 am/pm
private NumberDisplay minutes; // This will running like
// seconds act as minutes.
private String displayString; // simulates the actual display
/**
* Constructor for ClockDisplay objects. This constructor
* creates a new clock set at 00:00.
*/
public ClockDisplay()
{
hours = new NumberDisplay(13); // set great than 13; runs from 1am to 12 noon
minutes = new NumberDisplay(60); // 60 minutes is one hour
updateDisplay();
}
/**
* Constructor for ClockDisplay objects. This constructor
* creates a new clock set at the time specified by the
* parameters.
*/
public ClockDisplay(int hour, int minute)
{
hours = new NumberDisplay(13);
minutes = new NumberDisplay(60);
setTime(hour, minute);
}
/**
* This method should get called once every minute - it makes
* the clock display go one minute forward.
*/
public void timeTick()
{
minutes.increment();
if(minutes.getValue() == 1) { // on clock at after 12 am or pm.
hours.increment(); // after 60 mins, next per hour.
}
updateDisplay(); // updating to return
}
/**
* Set the time of the display to the specified hour and
* minute.
*/
public void setTime(int hour, int minute)
{
hours.setValue(hour); // hours will be set on display
minutes.setValue(minute); // minutes will be set on display
updateDisplay(); // updating the value to display
}
/**
* Return the current time of this display in the format HH:MM.
*/
public String getTime()
{
return displayString; // appears as messagebox to display the clock
}
/**
* Update the internal string that represents the display.
*/
private void updateDisplay()
{
displayString = hours.getDisplayValue() + ":" +
minutes.getDisplayValue(); //Updated the clock simulator
}
}
I'm still stuck with 00:00. need help?
There are a lot of areas in your code which could better managed.
Let's start with...
public void increment() {
value = (value + 1) % limit; // this is already the time by 1
}
I can see what you're trying to do, but remember 13 % 13 is 0, which is the starting point of your issues, while certainly clever, I would have used setValue(value + 1) and allowed setValue to perform the validation.
The reason for this is, you could supply a minimum and maximum allowable values, which setValue could then manage.
I would then change the increment method to return true when it "rolls" the value, this way it would be easier to determine when the value has reverted to its minimum state.
For brevity, these are the basic changes...
NumberDisplay
public class NumberDisplay {
private int minimum = 1;
private int maximum = 13;
private int value;
/**
* Constructor for objects of class NumberDisplay. Set the limit at
* which the display rolls over.
*/
public NumberDisplay(int maxumum, int minimum) {
this.maximum = maxumum;
this.minimum = minimum;
value = 1;
}
//...
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public boolean setValue(int replacementValue) {
if (replacementValue >= maximum) {
value = minimum;
return true;
} else {
value = replacementValue;
return false;
}
}
/**
* Increment the display value by one, rolling over to zero if the limit
* is reached.
*/
public boolean increment() {
// value = (value + 1) % maximum; // this is already the time by 1
return setValue(value + 1);
}
}
ClockDisplay
public class ClockDisplay {
//...
/**
* This method should get called once every minute - it makes the clock
* display go one minute forward.
*/
public void timeTick() {
if (minutes.increment()) { // on clock at after 12 am or pm.
hours.increment(); // after 60 mins, next per hour.
}
updateDisplay(); // updating to return
}
//...
}
Full example....
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class Clock {
private JFrame frame;
private JLabel label;
private ClockDisplay clock;
private boolean clockRunning = false;
private TimerThread timerThread;
public static void main(String[] args) {
System.out.println((13 % 13));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Clock();
}
});
}
/**
* Constructor for objects of class Clock
*/
public Clock() {
makeFrame();
clock = new ClockDisplay(12, 0);
}
/**
*
*/
private void start() {
clockRunning = true;
timerThread = new TimerThread();
timerThread.start();
}
/**
*
*/
private void stop() {
clockRunning = false;
}
/**
*
*/
private void step() {
clock.timeTick();
label.setText(clock.getTime());
}
/**
* 'About' function: show the 'about' box.
*/
private void showAbout() {
JOptionPane.showMessageDialog(frame,
"Clock Version 1.0\n"
+ "A simple interface for the 'Objects First' clock display project",
"About Clock",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Quit function: quit the application.
*/
private void quit() {
System.exit(0);
}
/**
* Create the Swing frame and its content.
*/
private void makeFrame() {
frame = new JFrame("Clock");
JPanel contentPane = (JPanel) frame.getContentPane();
contentPane.setBorder(new EmptyBorder(1, 60, 1, 60));
makeMenuBar(frame);
// Specify the layout manager with nice spacing
contentPane.setLayout(new BorderLayout(12, 12));
// Create the image pane in the center
label = new JLabel("12:00", SwingConstants.CENTER);
Font displayFont = label.getFont().deriveFont(96.0f);
label.setFont(displayFont);
//imagePanel.setBorder(new EtchedBorder());
contentPane.add(label, BorderLayout.CENTER);
// Create the toolbar with the buttons
JPanel toolbar = new JPanel();
toolbar.setLayout(new GridLayout(1, 0));
JButton startButton = new JButton("Start");
startButton.addActionListener(e -> start());
toolbar.add(startButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(e -> stop());
toolbar.add(stopButton);
JButton stepButton = new JButton("Step");
stepButton.addActionListener(e -> step());
toolbar.add(stepButton);
// Add toolbar into panel with flow layout for spacing
JPanel flow = new JPanel();
flow.add(toolbar);
contentPane.add(flow, BorderLayout.SOUTH);
// building is done - arrange the components
frame.pack();
// place the frame at the center of the screen and show
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(d.width / 2 - frame.getWidth() / 2, d.height / 2 - frame.getHeight() / 2);
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
*
* #param frame The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame) {
final int SHORTCUT_MASK
= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu menu;
JMenuItem item;
// create the File menu
menu = new JMenu("File");
menubar.add(menu);
item = new JMenuItem("About Clock...");
item.addActionListener(e -> showAbout());
menu.add(item);
menu.addSeparator();
item = new JMenuItem("Quit");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, SHORTCUT_MASK));
item.addActionListener(e -> quit());
menu.add(item);
}
class TimerThread extends Thread {
public void run() {
while (clockRunning) {
step();
pause();
}
}
private void pause() {
try {
Thread.sleep(300); // pause for 300 milliseconds
} catch (InterruptedException exc) {
}
}
}
public class NumberDisplay {
private int minimum = 1;
private int maximum = 13;
private int value;
/**
* Constructor for objects of class NumberDisplay. Set the limit at
* which the display rolls over.
*/
public NumberDisplay(int maxumum, int minimum) {
this.maximum = maxumum;
this.minimum = minimum;
value = 1;
}
/*
*
*/
/**
* Return the current value.
*/
public int getValue() {
return value;
}
/**
* Return the display value (that is, the current value as a two-digit
* String. If the value is less than ten, it will be padded with a
* leading zero).
*/
public String getDisplayValue() {
if (value < 10) {
return "0" + value; // stay 0 appears in left
} else {
return "" + value; // none to show in right of the display
}
}
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public boolean setValue(int replacementValue) {
if (replacementValue >= maximum) {
value = minimum;
return true;
} else {
value = replacementValue;
return false;
}
}
/**
* Increment the display value by one, rolling over to zero if the limit
* is reached.
*/
public boolean increment() {
// value = (value + 1) % maximum; // this is already the time by 1
return setValue(value + 1);
}
}
public class ClockDisplay {
private NumberDisplay hours; // runs from 1 am/pm to 11:59 am/pm
private NumberDisplay minutes; // This will running like
// seconds act as minutes.
private String displayString; // simulates the actual display
/**
* Constructor for ClockDisplay objects. This constructor creates a new
* clock set at 00:00.
*/
public ClockDisplay() {
hours = new NumberDisplay(13, 1); // set great than 13; runs from 1am to 12 noon
minutes = new NumberDisplay(60, 0); // 60 minutes is one hour
updateDisplay();
}
/**
* Constructor for ClockDisplay objects. This constructor creates a new
* clock set at the time specified by the parameters.
*/
public ClockDisplay(int hour, int minute) {
this();
setTime(hour, minute);
}
/**
* This method should get called once every minute - it makes the clock
* display go one minute forward.
*/
public void timeTick() {
if (minutes.increment()) { // on clock at after 12 am or pm.
hours.increment(); // after 60 mins, next per hour.
}
updateDisplay(); // updating to return
}
/**
* Set the time of the display to the specified hour and minute.
*/
public void setTime(int hour, int minute) {
System.out.println("setTime " + hour + ":" + minute);
hours.setValue(hour); // hours will be set on display
minutes.setValue(minute); // minutes will be set on display
updateDisplay(); // updating the value to display
}
/**
* Return the current time of this display in the format HH:MM.
*/
public String getTime() {
return displayString; // appears as messagebox to display the clock
}
/**
* Update the internal string that represents the display.
*/
private void updateDisplay() {
displayString = hours.getDisplayValue() + ":"
+ minutes.getDisplayValue(); //Updated the clock simulator
}
}
}
Side note
You also need a better understanding of concurrency in Swing. Swing is NOT thread safe and you should never modify the UI, or something the UI relies on, from outside the context of the Event Dispatching Thread, see Concurrency in Swing for more details. A Swing Timer would be a better choice then Thread in this case
Related
I am trying to make a java simulation of a train moving from station to station. I have the main code working but having trouble with the GUI. I have the basic layout with a start and stop button but as soon as the start button is selected, the main loop runs for the simulation and the GUI doesn't respond. I've been having trouble finding how to work around this. And help wpuld be much appreciated!
Here is the main simulation class:
/**
* Here is the main simulation class that runs the main loop.
* It uses instances of two classes : train and station.
* #author Ollie Jones
*
*/
public class SimEngine
{
/**
* Station object array and train object initialised.
* The line has 16 station so an array of 16 is needed.
*/
Station[] station = new Station[16];
Train train = new Train();
int forwardTimeArray[];
int backwardTimeArray[];
/**
* Constructor for objects of class SimEngine
*/
public SimEngine()
{
/**
* Here that values are initialised.
*/
train = new Train();
forwardTimeArray = new int[]{1,4,2,4,6,3,3,5,3,2,5,5,1,4,2};
backwardTimeArray = new int[]{3,2,4,5,2,2,4,3,4,2,5,2,1,4,5};
// A for loop is used to initialse the station number
for(int i=0; i<station.length; i++){
station[i] = new Station();
station[i].setStationNumber(i+1);
}
/**
* Each station name is initialised separately as
* they all have different names.
*/
station[0].setStationName("Name of 1st station");
station[1].setStationName("Name of 2nd station");
station[2].setStationName("Name of 3rd station");
station[3].setStationName("Name of 4th station");
station[4].setStationName("Name of 5ht station");
station[5].setStationName("Name of 6th station");
station[6].setStationName("Name of 7th station");
station[7].setStationName("Name of 8th station");
station[8].setStationName("Name of 9th station");
station[9].setStationName("Name of 10th station");
station[10].setStationName("Name of 11th station");
station[11].setStationName("Name of 12th station");
station[12].setStationName("Name of 13th station");
station[13].setStationName("Name of 14th station");
station[14].setStationName("Name of 15th station");
station[15].setStationName("Name of 16th station");
}
/**
* An example of a method - replace this comment with your own
*
* #param y a sample parameter for a method
* #return the sum of x and y
*/
/**
* This method stats the train simulation.
*
*/
public void start()
{
int x = 0;
System.out.println("Station Number:1"); //Print the first staion number.
while(x == 0){
int stationNumber = 0;
int time = 0;
Boolean forwards;
stationNumber = train.getStationNumber();
forwards = train.getDirection();
if (forwards == true){
time = forwardTimeArray[stationNumber-1];
sleep(time);
stationNumber = stationNumber + 1;
System.out.println("Station Nubmer:" + stationNumber);
train.setStationNumber(stationNumber);
}
else{
time = backwardTimeArray[stationNumber-2];
sleep(time);
stationNumber = stationNumber - 1;
System.out.println("Station Number:" + stationNumber);
train.setStationNumber(stationNumber);
}
if (stationNumber == 1){
forwards = true;
}
else if (stationNumber == 16){
forwards = false;
//train.setStationNumber(stationNumber-1);
}
train.setDirection(forwards);
}
}
public static void sleep(int time)
{
try{
time = time * 100;
Thread.sleep(time);
}
catch(Exception e) {}
}
public void stop()
{
System.exit(0);
}
}
Here is the sim class where the simulation is started.
public class Sim
{
private GUI gui;
private SimEngine engine;
/**
* Constructor for objects of class sim
*
*/
public Sim()
{
engine = new SimEngine();
gui = new GUI(engine);
}
/**
* Opens window if it has been closed.
*/
public void show()
{
gui.setVisable(true);
}
}
Here is the GUI, where the main issue is (i think).
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class GUI extends JFrame
{
// instance variables - replace the example below with your own
private JFrame frame;
private JTextField display;
private final SimEngine sim;
private JLabel infoLabel;
/**
* Constructor for objects of class GUI
*/
public GUI(SimEngine engine)
{
// initialise instance variables
makeFrame();
frame.setVisible(true);
sim = engine;
}
/**
* Creates GUI frame!
*/
public void makeFrame()
{
frame = new JFrame("Train Simulation");
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(new BorderLayout(8,8));
contentPane.setBorder(new EmptyBorder(10,10,10,10));
display = new JTextField();
contentPane.add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(1,2));
addButton(buttonPanel, "Start", () -> sim.start());
addButton(buttonPanel, "Stop", () -> sim.stop());
contentPane.add(buttonPanel, BorderLayout.CENTER);
frame.pack();
}
private void addButton(Container panel, String buttonText, ButtonAction
action)
{
JButton button = new JButton(buttonText);
button.addActionListener(e -> {action.act(); redisplay(); });
panel.add(button);
}
private interface ButtonAction
{
/**
* act on button press.
*/
void act();
}
private void redisplay()
{
}
/**
* Makes frame visable.
*/
public void setVisable(boolean visable){
frame.setVisible(visable);
}
}
You're running your simulation on the event dispatch thread. While your calculations are happening, they are monopolizing the thread that handles UI events, so it can't process anything and the UI freezes.
Use worker threads.
It looks like you have this usecase (from the linked tutorial):
The background task can provide intermediate results by invoking SwingWorker.publish, causing SwingWorker.process to be invoked from the event dispatch thread.
As explained in the comments and in this answer, running long processes on the The Event Dispatch Thread blocks it, so it does not respond to changes.
One alternative is to use a SwingWorker which does the background processing in its doInBackground() method, publishes interim values (publish method) and is capable of updating gui (process method).
The following is a basic implementation of a SwingWorker, based on your code.
It can be copy-pasted into one file (GUI.java) and run.
Note the comments in the code:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public class GUI extends JFrame
{
// instance variables - replace the example below with your own
private JFrame frame;
private JTextField display;
private final SimEngine sim;
private JLabel infoLabel;
/**
* Constructor for objects of class GUI
*/
public GUI(SimEngine engine)
{
// initialize instance variables
makeFrame();
frame.setVisible(true);
sim = engine;
}
/**
* Creates GUI frame!
*/
public void makeFrame()
{
frame = new JFrame("Train Simulation");
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setLayout(new BorderLayout(8,8));
contentPane.setBorder(new EmptyBorder(10,10,10,10));
display = new JTextField();
contentPane.add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel(new GridLayout(1,2));
addButton(buttonPanel, "Start", () -> sim.start());
addButton(buttonPanel, "Stop", () -> sim.stop());
contentPane.add(buttonPanel, BorderLayout.CENTER);
frame.pack();
}
private void addButton(Container panel, String buttonText, ButtonAction action)
{
JButton button = new JButton(buttonText);
button.addActionListener(e -> {action.act(); redisplay(); });
panel.add(button);
}
void updateDisplay(String newValue){
display.setText(newValue);
}
private interface ButtonAction
{
/**
* act on button press.
*/
void act();
}
private void redisplay() { }
/**
* Makes frame visible.
*/
public void setVisable(boolean visable){
frame.setVisible(visable);
}
public static void main(String[] args) {
Sim sim = new Sim();
sim.show();
}
}
//implements Listener so it can listen to SimEngine value changes
class Sim implements Listener
{
private final GUI gui;
private final SimEngine engine;
public Sim()
{
engine = new SimEngine(this);
gui = new GUI(engine);
}
/**
* make gui visible
*/
public void show()
{
gui.setVisable(true);
}
#Override
public void valueChanged(String newValue){
gui.updateDisplay(newValue);
}
}
class SimEngine {
/**
* Station object array and train object initialized.
* The line has 16 station so an array of 16 is needed.
*/
private final Station[] station = new Station[16];
private Train train = new Train();
private final int forwardTimeArray[], backwardTimeArray[];
private final Listener listener;
//accept a listener
public SimEngine(Listener listener)
{
this.listener = listener;
train = new Train();
forwardTimeArray = new int[] {1,4,2,4,6,3,3,5,3,2,5,5,1,4,2,3}; //needs 16 values, had only 16
backwardTimeArray = new int[]{3,2,4,5,2,2,4,3,4,2,5,2,1,4,5,4};
// A for loop is used to initialize the station number and name
for(int i=0; i<station.length; i++){
station[i] = new Station();
station[i].setStationNumber(i+1);
station[0].setStationName("Station #"+(i+1));
}
}
/**
* This method starts the train simulation.
*
*/
public void start()
{
//have all background processing done by a SwingWorker so GUI does not freeze
new SimulationWorker().execute();
}
public static void sleep(int time)
{
try{
Thread.sleep(time * 300);
}
catch(Exception e) {}
}
public void stop()
{
System.exit(0);
}
class SimulationWorker extends SwingWorker<Void,Integer>{
boolean stop = false; //use if you wish to stop
//do background processing
#Override
protected Void doInBackground() throws Exception {
while(! stop){
int stationNumber = 0;
int time = 0;
boolean forwards;
stationNumber = train.getStationNumber();
forwards = train.getDirection();
if (stationNumber == 1){
forwards = true;
train.setDirection(forwards);
}
else if (stationNumber == 15){
forwards = false;
train.setDirection(forwards);
}
if (forwards == true){
time = forwardTimeArray[stationNumber+1];//time = forwardTimeArray[stationNumber-1];
sleep(time);
stationNumber = stationNumber + 1;
//System.out.println("Station Number:" + stationNumber);
train.setStationNumber(stationNumber);
}
else{
time = backwardTimeArray[stationNumber-2];
sleep(time);
stationNumber = stationNumber - 1;
//System.out.println("Station Number:" + stationNumber);
train.setStationNumber(stationNumber);
}
publish(train.getStationNumber()); //publish result (station number)
}
return null;
}
//process published information
#Override
protected void process(List<Integer> stationsList) {
for(int stationNumber : stationsList){
listener.valueChanged("Train is at "+ stationNumber); //notify listener
}
}
}
}
class Train {
private int stationNumber = 0;
private boolean forwards = true ;
public int getStationNumber() {
return stationNumber;
}
public void setDirection(boolean forwards) {
this.forwards = forwards;
}
public void setStationNumber(int stationNumber) {
this.stationNumber = stationNumber;
}
public boolean getDirection() {
return forwards;
}
}
class Station {
private int stationNumber;
private String stationName;
public void setStationNumber(int stationNumber) {
this.stationNumber = stationNumber;
}
public void setStationName(String stationName) {
this.stationName = stationName;
}
}
//an interface use by Sim to listen to SimEngine changes
interface Listener {
void valueChanged(String newValue);
}
I am having trouble setting custom first-day-of-week, in JCalendar.
The first-day-of-week does change if I change locale.
However changing the first-day-of-week in the underlying calendar, has no effect.
Here is a short demonstration code:
public class TestJChooser extends JFrame {
/**
*
*/
public TestJChooser() {
setLayout(new BorderLayout(5,5));
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
Locale locale = Locale.forLanguageTag("de-DE");
Calendar calendar = Calendar.getInstance(locale);
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
JCalendar jCal = new JCalendar(calendar);
jCal.setLocale(locale);
jCal.setPreferredSize(new Dimension(500, 400));
jCal.getDayChooser().setDayBordersVisible(true);
jCal.setTodayButtonVisible(true);
getContentPane().add(jCal,BorderLayout.CENTER);
pack();
setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestJChooser();
}
}
Changing the value of
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
Does not change the first day of the week in JCalendar, nor the weekend day.
To achieve the functionality I needed with com.toedter.calendar.JDateChooser I had to extend it.
First a demo: set Sunday as the first day of the week (although it is set to Monday by the locale) . The test class:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser(){
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
getContentPane().setLayout(new BorderLayout(5,5));
//set locale and calendar
Locale locale = Locale.forLanguageTag("de-DE");
Calendar cal = Calendar.getInstance(locale);
cal.setTime(new Date());
//set first day of week
int firstWeekDay = Calendar.SUNDAY;
cal.setFirstDayOfWeek(firstWeekDay);
//-- Toedter JCalendar
JCalendar jCalendar = new JCalendarExt(null, locale, true, true, false);
jCalendar.setCalendar(cal);
jCalendar.setPreferredSize(new Dimension(120, 160));
jCalendar.getDayChooser().setDayBordersVisible(true);
jCalendar.setTodayButtonVisible(true);
jCalendar.setWeekOfYearVisible(false);
getContentPane().add(jCalendar,BorderLayout.CENTER);
//-- Toedter JDateChooser
JCalendar jCalendar2 = new JCalendarExt(null, locale, true, true, false);
jCalendar2.setCalendar(cal);
JDateChooser dateChooser = new JDateChooser(jCalendar2, null , "dd.mm.yyyy",null);
dateChooser.setLocale(locale);
getContentPane().add(dateChooser,BorderLayout.SOUTH);
pack();
setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
The result can be seen in the image.
The second image demonstrates setting the first-day-of-week to Tuesday.
Two classes were extended. The class extending JCalendar:
/**
* Extended to gain control on week-first-day.
* It also enables the option to display in different color the
* last-day-of-week, rather than <code>JCalendar</code> default which is
* always display Sunday in a different color.
*
* #version
* $Log: JCalendarExt.java,v $
*
*
* #author Ofer Yuval
* 27 Nov 2015
*
*/
public class JCalendarExt extends JCalendar {
/**
*
* #param date
* #param locale
* #param monthSpinner
* #param weekOfYearVisible
* #param colorWeekend
* <br>When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* <br>When true, week-last-day will be painted in red.
*/
public JCalendarExt(Date date, Locale locale, boolean monthSpinner, boolean weekOfYearVisible,
boolean colorWeekend) {
super(date, locale, monthSpinner, weekOfYearVisible);
remove(dayChooser);
//add the extended date chooser
dayChooser = new JDayChooserExt(weekOfYearVisible) ;
dayChooser.addPropertyChangeListener(this);
((JDayChooserExt) dayChooser).setColorWeekend(colorWeekend);
monthChooser.setDayChooser(dayChooser);
yearChooser.setDayChooser(dayChooser);
add(dayChooser, BorderLayout.CENTER);
}
#Override
public void setCalendar(Calendar c) {
getDayChooser().setCalendar(c);
super.setCalendar(c);
}
}
And the class extending JDayChooser:
/**
*
* #version
* $Log: JDayChooserExt.java,v $
*
*
* #author Ofer Yuval
* 27 Nov 2015
*
*/
public class JDayChooserExt extends JDayChooser {
/**
* When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* When true, week-last-day will be painted in red.
*/
private boolean isColorWeekend = false;
/**
* #param weekOfYearVisible
*/
public JDayChooserExt(boolean weekOfYearVisible) {
super(weekOfYearVisible);
}
/**
* Initializes the locale specific names for the days of the week.
*/
#Override
protected void init() {
JButton testButton = new JButton();
oldDayBackgroundColor = testButton.getBackground();
selectedColor = new Color(160, 160, 160);
drawDayNames();
drawDays();
}
/**
* Draws the day names of the day columns.
*/
private void drawDayNames() {
DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
dayNames = dateFormatSymbols.getShortWeekdays();
int Day = calendar.getFirstDayOfWeek();//firstDayOfWeek;
int coloredDay = (isColorWeekend ) ? Day -1 : Day;
if(coloredDay <= 0) {
coloredDay += 7;
}
for (int i = 0; i < 7; i++) {
if ((maxDayCharacters > 0) && (maxDayCharacters < 5)) {
if (dayNames[Day].length() >= maxDayCharacters) {
dayNames[Day] = dayNames[Day]
.substring(0, maxDayCharacters);
}
}
days[i].setText(dayNames[Day]);
if (Day == coloredDay) {
days[i].setForeground(sundayForeground);
} else {
days[i].setForeground(weekdayForeground);
}
if (Day < 7) {
Day++;
} else {
Day -= 6;
}
}
}
/**
* #param isColorWeekend the isColorWeekend to set
*/
public void setColorWeekend(boolean isColorWeekend) {
this.isColorWeekend = isColorWeekend;
}
// ///////////////////////////////////////////////////////////
// ////////////// DecoratorButton class //////////////////////
// ///////////////////////////////////////////////////////////
class DecoratorButton extends JButton {
private static final long serialVersionUID = -5306477668406547496L;
public DecoratorButton() {
setBackground(decorationBackgroundColor);
setContentAreaFilled(decorationBackgroundVisible);
setBorderPainted(decorationBordersVisible);
}
#Override
public void addMouseListener(MouseListener l) {
}
#Override
public boolean isFocusable() {
return false;
}
#Override
public void paint(Graphics g) {
if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
// this is a hack to get the background painted
// when using Windows Look & Feel
if (decorationBackgroundVisible) {
g.setColor(decorationBackgroundColor);
} else {
g.setColor(days[7].getBackground());
}
g.fillRect(0, 0, getWidth(), getHeight());
if (isBorderPainted()) {
setContentAreaFilled(true);
} else {
setContentAreaFilled(false);
}
}
super.paint(g);
}
};
}
Here's the dirty way using reflection, you just need to override JCalendar:
private class MyJCalendar extends JCalendar {
MyJCalendar(Calendar c) {
super(c);
}
public void setFirstDayOfWeek(int firstdayofweek) {
try {
// Dirty hack to set first day of week :-)
Field f = JDayChooser.class.getDeclaredField("calendar");
f.setAccessible(true);
Calendar c = (Calendar) f.get(dayChooser);
c.setFirstDayOfWeek(firstdayofweek);
Method m = JDayChooser.class.getDeclaredMethod("drawDayNames");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
m = JDayChooser.class.getDeclaredMethod("drawDays");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I found a way to achieve the functionality I need with swingx JXMonthView:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser() {
//set locale
Locale locale = Locale.forLanguageTag("de-DE");
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
UIManager.put(CalendarHeaderHandler.uiControllerID, SpinningCalendarHeaderHandler.class.getName());
UIManager.put(SpinningCalendarHeaderHandler.ARROWS_SURROUND_MONTH, Boolean.TRUE);
UIManager.put(SpinningCalendarHeaderHandler.FOCUSABLE_SPINNER_TEXT, Boolean.TRUE);
final JXMonthView monthView = new JXMonthView();
//needed for the month change and year change arrows
monthView.setZoomable(true);
monthView.setLocale(locale);
//set first day of week to Tuesday
monthView.setFirstDayOfWeek(Calendar.TUESDAY);
//set Tuesday color
monthView.setDayForeground(Calendar.TUESDAY, Color.MAGENTA);
getContentPane().add(monthView );
pack();
setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
I wasn't able to achieve it with com.toedter.calendar.JDateChooser.
This is probably an elementary question. However, I have completed reading the 12th Chapter of Java Programming for the Absolute Beginner and have approached the Challenges section. I cannot quite get the progam to display a labeled button with the extended class.
The specification states:
Extend the JPRButton3D class to create a button that displays a label just like
the AWT Button class you're so familiar with by now. As an extra test, override
the isFocusable() method so that your button class can be traversed and make sure you
paint some special graphic to make it obvious when your button has focus.
How can I edit my code of LabelButton3D and LabelButton3DTest to accomplish this task?
An answer to this specification can potentially aid many new Java programmers in extending their own classes.
Thank you very much for your time and cooperation reagrding this matter.
HERE IS THE CODE FOR JPRButton3D:
package jpr.lightweight;
import java.awt.*;
import java.awt.event.*;
/**
* A lightweight 3D Button class that fires actions when clicked.
* When it is enabled it appears {#link #RAISED RAISED}, when
* it is pressed it appears {#link #SUNK SUNK}, and when it is
* not enabled, it appears {#link #FLAT FLAT}.
*/
public class JPRButton3D extends JPRRectComponent3D {
private boolean pressed;
/**
* This <code>JPRButton3D</code>'s <code>ActionListener</code>.
*/
protected ActionListener actionListener;
private String actionCommand;
/**
* Constructs a new <code>JPRButton3D</code> with minimum size
*/
public JPRButton3D() {
this(ABSOLUTE_MIN_WIDTH, ABSOLUTE_MIN_HEIGHT, 1);
}
/**
* Constructs a new <code>JPRButton3D</code> with the given dimensions.
* #param wide the width
* #param high the height
*/
public JPRButton3D(int wide, int high) {
this(wide, high, 1);
}
/**
* Constructs a new <code>JPRButton3D</code> with the given dimensions
* and border magnitude.
* #param wide the width
* #param high the height
* #param border_magnitude the border's magnitude
*/
public JPRButton3D(int wide, int high, int border_magnitude) {
super(wide, high, RAISED, border_magnitude);
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
public void processMouseEvent(MouseEvent e) {
if (isEnabled() & e.getModifiers() == MouseEvent.BUTTON1_MASK) {
switch(e.getID()) {
case MouseEvent.MOUSE_PRESSED:
pressed = true;
current_appearance = SUNK;
repaint();
break;
case MouseEvent.MOUSE_EXITED:
if (pressed) {
pressed = false;
current_appearance = RAISED;
repaint();
}
break;
case MouseEvent.MOUSE_RELEASED:
if (pressed) {
current_appearance = RAISED;
repaint();
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, actionCommand,
e.getModifiers()));
}
}
break;
}
}
super.processMouseEvent(e);
}
/**
* Adds the specified <code>ActionListener</code>
* #param listener <code>ActionListener</code> to add
*/
public void addActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.add(actionListener, listener);
}
/**
* Removes the specified <code>ActionListener</code>
* #param listener <code>ActionListener</code> to remove
*/
public void removeActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.remove(actionListener,
listener);
}
/**
* Sets the action command associated with action events.
* #param command The action command.
*/
public void setActionCommand(String command) {
actionCommand = command;
}
/**
* Gets the action command associated with action events.
* #return the action command
*/
public String getActionCommand() {
return actionCommand;
}
/**
* Enables or disables this <code>JPRButton3D</code>.
* #param b <code>true</code> to enable, <code>false</code> to disable
*/
public void setEnabled(boolean b) {
if (b) current_appearance = RAISED;
else current_appearance = FLAT;
repaint();
super.setEnabled(b);
}
}
HERE IS MY CODE FOR LabelButton3DTest (to extend JPRButton3D):
import java.awt.*;
import java.awt.event.*;
import jpr.lightweight.JPRButton3D;
public class LabelButton3DTest extends GUIFrame {
LabelButton3D[] b;
String s;
public LabelButton3DTest() {
super("LabelButton3D Test");
setLayout(new FlowLayout());
b = new LabelButton3D[1];
b[0] = new LabelButton3D("Favorite Button");
b[0] = new LabelButton3D(75, 35, 1);
add(b[0]);
pack();
setVisible(true);
}
public static void main(String args[]) {
new LabelButton3DTest();
}
}
HERE IS MY CODE FOR LabelButton3D:
public class LabelButton3D extends JPRButton3D {
public LabelButton3D(String label) {
}
public LabelButton3D(int wide, int high, int border_magnitude) {
super(wide, high, border_magnitude);
}
}
I'm really stuck, thanks to my college.
I need code in Java to have a Stopwatch which shows time in 00:00:00(mm:ss:msms) format. I want to use Key events to run and pause and reset the timer. Like if I press S the stopwatch starts and P pauses and R resets.
the thing is the I also want to add key events on numbers for teams, like if I press 1, the "team 1" flashes, preferably with a beep, and so on with 2 3 4 5. im not able to understand how to do this.
i wrote this to print time in second only just to try...
import java.awt.event.*;
import javax.swing.*;
public class StopWatch2 extends JLabel
implements KeyListener, ActionListener {
private long startTime;
private boolean running;
private Timer timer;
public StopWatch2() {
super(" Press S ", JLabel.CENTER);
addKeyListener(this);
}
public void actionPerformed(ActionEvent evt) {
long time = (System.currentTimeMillis() - startTime) / 1000;
setText(Long.toString(time));
}
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
if (keyCode==KeyEvent.VK_S) {
running = true;
startTime = e.getWhen();
setText("Running: 0 seconds");
if (timer == null) {
timer = new Timer(100,this);
timer.start();
}
else
timer.restart();
}
if(keyCode==KeyEvent.VK_P)
{
timer.stop();
running = false;
long endTime = e.getWhen();
double seconds = (endTime - startTime) / 1000.0;
setText("Time: " + seconds + " sec.");
}
}
public void keyTyped(KeyEvent e)
{}
public void keyReleased(KeyEvent e)
{}
}
import java.awt.*;
import javax.swing.*;
public class Test2 extends JApplet {
public void init() {
StopWatch2 watch = new StopWatch2();
watch.setFont( new Font("SansSerif", Font.BOLD, 24) );
watch.setBackground(Color.white);
watch.setForeground( new Color(180,0,0) );
watch.setOpaque(true);
getContentPane().add(watch, BorderLayout.CENTER);
}
}
im trying stuff on my own n m pretty much self taught so im not able to understand whats going wrong
Do you mean something like:
/**
* Stopwatch is a simple timer.
*/
public class Stopwatch {
/**
* Stopwatch() Initialises a stopwatch.
*/
public Stopwatch() {
// Your code here.
}
/**
* elapsed() The elapsed time in milliseconds shown on the stopwatch.
*
* #return double The elapsed time in milliseconds as a double. Returns -1.0 if no meaningful
* value is available, i.e. if the watch is reset or has been started and not stopped.
*/
public double elapsed() {
// Your code here.
}
/**
* start() Starts the stopwatch and clears the previous elapsed time.
*/
public void start() {
// Your code here.
}
/**
* stop() If the stopwatch has been started this stops the stopwatch and calculates the
* elapsed time. Otherwise it does nothing.
*/
public void stop() {
// Your code here.
}
/**
* reset() Resets the stopwatch and clears the elapsed time.
*/
public void reset() {
// Your code here.
}
#Override
public String toString() {
// Your code here.
}
} // end class Stopwatch
I have to design a batleships game for friday but the course im doing seems to have skipped a few things because although i managed all the other assignments this final project is unbelievably above my grasp but i have to do something.
i have the following GUI code which gives me my playing grids but i have absolutely no idea how to do the following things
assign a ship to some cells - and color these cells to reflect this
how to do the actual hit,miss,sunk and update the grid
i figure if i can at least do these i can duplicate the code for the cpu but im sooooooo stuck so any help is really appreciated please guys work some magic :)
/**
* BattleGui:
*
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
public class BattleGui implements ActionListener
{
// Default filename to use for saving and loading files
// Possible improvement: replace with a FileChooser
private final static String DEFAULT_FILENAME = "battlegui.txt";
private int GRID_SIZE = 8;
private JButton [] buttonArray;
public JMenuBar createMenu()
{
JMenuBar menuBar = new JMenuBar();;
JMenu menu = new JMenu("Battle Menu");
JMenuItem menuItem;
menuBar.add(menu);
// A group of JMenuItems. You can create other menu items here if desired
menuItem = new JMenuItem("New Game");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem("Load Game");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem("Save Game");
menuItem.addActionListener(this);
menu.add(menuItem);
menuItem = new JMenuItem("Quit");
menuItem.addActionListener(this);
menu.add(menuItem);
//a submenu
menu.addSeparator();
return menuBar;
}
public Container createContentPaneCPU()
{
int numButtons = GRID_SIZE * GRID_SIZE;
JPanel grid = new JPanel(new GridLayout(GRID_SIZE,GRID_SIZE));
buttonArray = new JButton[numButtons];
for (int i=0; i<numButtons; i++)
{
buttonArray[i] = new JButton(" ");
// This label is used to identify which button was clicked in the action listener
buttonArray[i].setActionCommand("" + i); // String "0", "1" etc.
buttonArray[i].addActionListener(this);
grid.add(buttonArray[i]);
}
return grid;
}
public Container createContentPane()
{
int numButtons = GRID_SIZE * GRID_SIZE;
JPanel grid = new JPanel(new GridLayout(GRID_SIZE,GRID_SIZE));
buttonArray = new JButton[numButtons];
for (int i=0; i<numButtons; i++)
{
buttonArray[i] = new JButton(" ");
// This label is used to identify which button was clicked in the action listener
//buttonArray[i].setActionCommand("" + i); // String "0", "1" etc.
// buttonArray[i].addActionListener(this);
grid.add(buttonArray[i]);
}
return grid;
}
/**
* This method handles events from the Menu and the board.
*
*/
public void actionPerformed(ActionEvent e)
{
String classname = getClassName(e.getSource());
JComponent component = (JComponent)(e.getSource());
if (classname.equals("JMenuItem"))
{
JMenuItem menusource = (JMenuItem)(e.getSource());
String menutext = menusource.getText();
// Determine which menu option was chosen
if (menutext.equals("Load Game"))
{
/* BATTLEGUI Add your code here to handle Load Game **********/
LoadGame();
}
else if (menutext.equals("Save Game"))
{
/* BATTLEGUI Add your code here to handle Save Game **********/
SaveGame();
}
else if (menutext.equals("New Game"))
{
/* BATTLEGUI Add your code here to handle Save Game **********/
NewGame();
}
}
// Handle the event from the user clicking on a command button
else if (classname.equals("JButton"))
{
JButton button = (JButton)(e.getSource());
int bnum = Integer.parseInt(button.getActionCommand());
int row = bnum / GRID_SIZE;
int col = bnum % GRID_SIZE;
System.out.println(e.getSource());
/* BATTLEGUI Add your code here to handle user clicking on the grid ***********/
button.setBackground(Color.GREEN);
fireShot(row, col);
}
}
/**
* Returns the class name
*/
protected String getClassName(Object o)
{
String classString = o.getClass().getName();
int dotIndex = classString.lastIndexOf(".");
return classString.substring(dotIndex+1);
}
/**
* Create the GUI and show it.
* For thread safety, this method should be invoked from the event-dispatching thread.
*/
private static void createAndShowGUI()
{
// Create and set up the window.
JFrame frame = new JFrame("Battleships");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int maxGap = 20;
int ButtonWidth = 20;
int ButtonHeight = 1;
BattleGui battlegui = new BattleGui();
frame.setJMenuBar(battlegui.createMenu());
JPanel gui = new JPanel(new GridLayout(2,2,20,5));
gui.setBorder(new EmptyBorder(5,5,5,5));
//Set up components preferred size
JButton b = new JButton("Just fake button");
Dimension buttonSize = b.getPreferredSize();
gui.add(new JButton("Player"));
gui.add(new JButton("CPU"));
b.setPreferredSize(new Dimension(ButtonWidth, ButtonHeight));
gui.add(battlegui.createContentPane());
gui.add(battlegui.createContentPaneCPU());
frame.setContentPane(gui);
// Create and set up the content pane.
/*
BattleGui battlegui = new BattleGui();
frame.setJMenuBar(battlegui.createMenu());
frame.setContentPane(battlegui.createContentPane());
*/
// Display the window, setting the size
frame.setSize(800, 600);
frame.setVisible(true);
}
/**
* Sets a Gui grid square at row, col to display a character
*/
public boolean setGuiSquare(int row, int col, char c)
{
int bnum = row * GRID_SIZE + col;
if (bnum >= (GRID_SIZE*GRID_SIZE))
{
return false;
}
else
{
buttonArray[bnum].setText(Character.toString(c));
}
return true;
}
/**
* This is a standard main function for a Java GUI
*/
public static void main(String[] args)
{
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
//Deploy();
}
});
}
//************************************************************************
//*** BATTLEGUI: Modify the methods below to respond to Menu and Mouse click events
/**
* This method is called from the Menu event: New Game.
* BATTLEGUI
*/
public void NewGame()
{
System.out.println("New game selected");
}
/**
* This method is called from the Menu event: Load Game.
* BATTLEGUI
*/
public void LoadGame()
{
System.out.println("Load game selected");
}
/**
* This method is called from the Menu event: Save Game.
* BATTLEGUI
*/
public void SaveGame()
{
System.out.println("Save game selected");
}
/**
* This method is called from the Mouse Click event.
* BATTLEGUI
*/
public void fireShot(int row, int col)
{
System.out.println("Fire shot selected: at (" + row + ", " + col + ")");
}
}
I would suggest, take a step back and think about the problem domain.
You have a BattleScene, which contains BattleSquares. Each battleSquare can have atmost 1 ship, and can have a color. You also have Ship objects (which can belong to a particular player, indicates if it is damaged or not)...
BattleSquare needs to decide if it is a Hit or Miss, because it has all the information. It knows wether it has a ship or not.
/**true if had a ship, false if it was a miss
*/
public class BattleSquare{
public boolean processHit(){
if (hasShip()){
ship.setState(DESTROYED);
return true;
}
return false;
}
public void setShip(Ship ship){ .... }
public boolean hasShip() { ... } } ... methods for color too
If you isolate your code into manageable snippets, where some classes represent the model, you will be able to manage things better. You appear to be mixing everything in one class and hence are feeling lost.
Similarly, your BattleScene will contains a List of BattleSquares. Once you fire, you can individuall seek a particular BattleSquare and tell it to process itself. If it is a hit, you update the state.
Idea is that your model classes only are responsible for managing state. Your controller classes can fire events, which are intercepted by views, who update the models and refresh themselves.
hopefully it helps.