How would I properly implement a JScrollPane GUI into my Java game? - java

I've been trying for a few days to implement this "basic" GUI into my game of Tic-Tac-Toe. The outline of this code requires me to set up a basic JFrame containing a JTextArea, inside a JScrollPane GUI. All of this is in class TicTacToeFrame, which extends class TicTacToe (holds all the methods/constructor for the board, including a method that prints the board to the console). TicTacToeFrame needs to override the print() method, so the board, which is a string, will be printed to the GUI instead of the console.
Note, I'm required to keep:
public class TicTacToeFrame extends TicTacToe
They don't allow us extend from JFrame like:
public class TicTacToeFrame extends JFrame
What I have is shown below:
TicTacToe class (Works)
import java.util.*;
/**
* A class modelling a tic-tac-toe (noughts and crosses, Xs and Os) game.
*
* #author Supasta
* #version November 20, 2019
*/
public class TicTacToe
{
public static final String PLAYER_X = "X"; // player using "X"
public static final String PLAYER_O = "O"; // player using "O"
public static final String EMPTY = " "; // empty cell
public static final String TIE = "T"; // game ended in a tie
private String player; // current player (PLAYER_X or PLAYER_O)
private String winner; // winner: PLAYER_X, PLAYER_O, TIE, EMPTY = in progress
private int numFreeSquares; // number of squares still free
private String board[][]; // 3x3 array representing the board
private TicTacToeFrame gui;
/**
* Constructs a new Tic-Tac-Toe board.
*/
public TicTacToe()
{
board = new String[3][3];
}
/**
* Sets everything up for a new game. Marks all squares in the Tic Tac Toe board as empty,
* and indicates no winner yet, 9 free squares and the current player is player X.
*/
private void clearBoard()
{
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = EMPTY;
}
}
winner = EMPTY;
numFreeSquares = 9;
player = PLAYER_X; // Player X always has the first turn.
}
/**
* Plays one game of Tic Tac Toe.
*/
public void playGame()
{
int row, col;
Scanner sc;
clearBoard(); // clear the board
gui = new TicTacToeFrame();
// print starting board
gui.print();
// loop until the game ends
while (winner==EMPTY) { // game still in progress
// get input (row and column)
while (true) { // repeat until valid input
System.out.print("Enter row and column of chosen square (0, 1, 2 for each): ");
sc = new Scanner(System.in);
row = sc.nextInt();
col = sc.nextInt();
if (row>=0 && row<=2 && col>=0 && col<=2 && board[row][col]==EMPTY) break;
System.out.println("Invalid selection, try again.");
}
board[row][col] = player; // fill in the square with player
numFreeSquares--; // decrement number of free squares
// see if the game is over
if (haveWinner(row,col))
winner = player; // must be the player who just went
else if (numFreeSquares==0)
winner = TIE; // board is full so it's a tie
// print current board
print();
// change to other player (this won't do anything if game has ended)
if (player==PLAYER_X)
player=PLAYER_O;
else
player=PLAYER_X;
}
}
/**
* Returns true if filling the given square gives us a winner, and false
* otherwise.
*
* #param int row of square just set
* #param int col of square just set
*
* #return true if we have a winner, false otherwise
*/
private boolean haveWinner(int row, int col)
{
// unless at least 5 squares have been filled, we don't need to go any further
// (the earliest we can have a winner is after player X's 3rd move).
if (numFreeSquares>4) return false;
// Note: We don't need to check all rows, columns, and diagonals, only those
// that contain the latest filled square. We know that we have a winner
// if all 3 squares are the same, as they can't all be blank (as the latest
// filled square is one of them).
// check row "row"
if ( board[row][0].equals(board[row][1]) &&
board[row][0].equals(board[row][2]) ) return true;
// check column "col"
if ( board[0][col].equals(board[1][col]) &&
board[0][col].equals(board[2][col]) ) return true;
// if row=col check one diagonal
if (row==col)
if ( board[0][0].equals(board[1][1]) &&
board[0][0].equals(board[2][2]) ) return true;
// if row=2-col check other diagonal
if (row==2-col)
if ( board[0][2].equals(board[1][1]) &&
board[0][2].equals(board[2][0]) ) return true;
// no winner yet
return false;
}
/**
* Prints the board to standard out using toString().
*/
public void print()
{
System.out.println(toString());
}
/**
* Returns a string representing the current state of the game. This should look like
* a regular tic tac toe board, and be followed by a message if the game is over that says
* who won (or indicates a tie).
*
* #return String representing the tic tac toe game state
*/
public String toString()
{
String currentState = "";
String progress = "";
for(int i=0 ; i < 3; ++i){
currentState += board[i][0] + " | " + board[i][1] + " | " + board[i][2] + "\n";
if(i == 2){
break;
}
currentState += "------------\n";
}
/* Prints the winner, only if there is a winner */
if(winner != EMPTY){
if(this.winner == TIE){
progress = ("The games ends in a tie!");
}
else{
progress = ("Game over, " + player + " wins!");
}
}
else{
progress = "Game in progress";
}
return currentState + "\n" + progress + "\n";
}
}
TicTacToeFrame class (broken)
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* A class modelling a tic-tac-toe (noughts and crosses, Xs and Os) game in a very
* simple GUI window.
*
* #author Supasta
* #version November 20, 2019
*/
public class TicTacToeFrame extends TicTacToe
{
private JTextArea status; // text area to print game status
private JFrame frame;
private JScrollPane sta;
/**
* Constructs a new Tic-Tac-Toe board and sets up the basic
* JFrame containing a JTextArea in a JScrollPane GUI.
*/
public TicTacToeFrame()
{
super();
final JFrame frame = new JFrame("Tic Tac Toe");
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
status = new JTextArea(super.toString());
JScrollPane sta = new JScrollPane();
sta.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
sta.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
frame.getContentPane().add(sta);
frame.setVisible(true);
}
/**
* Prints the board to the GUI using toString().
*/
public void print()
{
status.replaceSelection(toString());
}
}
What should I change in my TicTacToeFrame? Right now the GUI won't even appear.. And during testing, if I got it to appear, it wouldn't print any text.

I think the real issue here is that you are new to swing GUI. You are trying to just apply your frame to your existing code and hoping to see it - but everything has to be added explicitly.
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Test {
/**
* Do this for thread safety
* #param args
*/
public static void main (String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI();
}
});
}
/**
* create the JFrame
*/
private static void createGUI() {
JFrame jf = new JFrame();
addComponents(jf.getContentPane());
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
}
/**
* add the components
* ALL YOUR NEW TIC TAC TOE RELATED JPANELS, JTEXTFIELDS, ETC. WILL GO HERE!
* #param pane
*/
private static void addComponents(Container pane) {
pane.setLayout(new FlowLayout());
JTextArea jta = new JTextArea("some text");
JScrollPane jsp = new JScrollPane(jta);
jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
pane.add(jsp);
}
}
To help you get started, here is a very basic program that will show you how I added a scrollable JTextArea. I would start from scratch, and add in your functionality from tic-tac-toe piece by piece. Adding items one at a time.
How do I get X to appear larger? Where I want it? When I want it?
These are all questions I expect you to have - and I recommend doing some research into the different layout managers of JPanels. You will undoubtedly find that getting swing to do what you want it to do is complicated as a beginner.

Related

Can not complete drawline on JButton [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
So I am making a simple tic tac toe game and ran into a problem at the last minute
I am trying to draw a line at the win location but on the final win location(index), the line gets hidden behind the JButton not entirly sure why it is doing this.
I know alot of people say do not use getGraphics(), and I am wondering if that is the source of my issues they say to override the paintComponent method but that is not working for me either
I have attached a pic of what the result is looking like and code snips of how I am trying to perform these actions
PS I am using a JFrame, if any more code is needed I will be glad to show it
if(win[i] == 264){ // if one of the the combinations equal 'X','X','X' which equals 264, then there is a winner
System.out.println("X is the winner!!!");
System.out.println("Game Over!");
number = i;
draw(); }// call draw method
private void draw(){ // drawing a line at winning location
Graphics2D g1 = (Graphics2D) GUI.getFrame().getGraphics(); // declaring graphics on our Jframe
Stroke stroke3 = new BasicStroke(12f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); // make our strokes cap off round
if(number == 0){ // statements will determine the win location, so at win0, XXX,
g1.setStroke(stroke3); // we will add stroke to our line
g1.drawLine(0,104,500,104); // draw the line starting at the 0,104 and end it at coordinates 500,104
}
here is a more runnable code, it is alot though
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class tic implements Runnable {
final static int row = 3; // our rows
final static int col = 3; // our col
final static int sizeOfBoard = row * col;
// the size of our board is not going to change so we make it final
static JButton[] clickButton;
char[] templateOfBoard; // our board, TicTacToe field, static
char userTurn; // users turn , only one letter, tracks whether it is a X or O
int count; // keeps track of user moves
static JFrame frame; // our JFrame
int number;
public tic(JFrame frame) {
tic.frame = new JFrame("TicTacToe GAME");
clickButton = new JButton[9];
count = 0; // number of turns starts at 0;
number = 0;
setUserTurn('X'); // first turn will always be X
setTemplateOfBoard(new char[sizeOfBoard]); // size of the board we are going to make it
try{
for(int spaces=0; spaces<sizeOfBoard; spaces++){ // size of Board is in the GUI class
getTemplateOfBoard()[spaces] = ' '; // the board is being created, looping through all rows and col
//every index of the board not has a char value equal to a space
//determine if everything came out correctly
//should equal of a total of 9
// 3x3
}
System.out.println("Board template created"); // means the board now has all spaces
}
catch(Exception e){
System.out.println("Could not initalize the board to empty char");
e.printStackTrace();
}
}
public static void main(String[] args){
try{
SwingUtilities.invokeLater(new tic(frame)); // run
}
catch(Exception e){ // wanted to test to ensure that Runnable could be invoked
System.out.println("Could not excute Runnable application");
e.printStackTrace();
}
}
public void run() {
setup(); // going to run out setup method, what our game is made out of
}
public void setup() {
// setting up the Board
// board is composed of JButton
// and a 3x3 frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the user closes the window JFrame will exit
//going to design the board now
//the dimensations of the board = sizeOfBoard
getFrame().setLayout(new GridLayout(row, col)); // this is the outline rows * col
// sizes out row * col based on what we define those numbers as
//i.e 3x3
getFrame().setBounds(0,0,500,500); // location at 0,0, size 500 x 500
Border border = new LineBorder(Color.DARK_GRAY, 2); // color of JButton border
System.out.println("Your board game is being created!");
try{
getFrame().setVisible(true); // shows the board,
// this is going to display everything to the screen
System.out.println("Board is now visable");
}
catch(Exception e){
System.out.println("Board was not displayed");
}
// 9 different buttons, for every index there will be a button
for(int i =0; i<sizeOfBoard;i++){ // going to fill the board with clickableButtons by looping through every index and placing a button there
final int move = i;
clickButton[i] = new JButton(); // at a certain index there is a new button
clickButton[i].setSize(250,250); // size of each button
clickButton[i].setBackground(Color.WHITE); // color of the JButton
getFrame().add(clickButton[i]); // we are going to add the actual the button at that index on the frame
clickButton[i].setFont(new Font("Arial", Font.BOLD, 70)); // size of the text
clickButton[i].setBorder(border); // adding border
clickButton[i].getModel().addChangeListener(new ChangeListener() { //going to overRide what happens when we rollover and press a Butotn
public void stateChanged(ChangeEvent e) {
ButtonModel button = (ButtonModel) e.getSource(); // manages the state of the button, i.e lets me control what happens to the button
if(clickButton[move] != null){ // if we do not include this argument
// the buttons are not made yet on the new game, meaning clickButton[i] = null
//so boolean(!button.isRollover()) will return true, since on the new game you can not have your mouse hovered over
// but when it returns true, it will return a null value, giving a null pointer exception
// so best thing to do, is to only run these cases below when the buttons are not null
if (button.isRollover()) { // when the mouse hovers over the index
clickButton[move].setBackground(Color.BLACK); // color will equal black
}
else if(!button.isRollover()){ // when the button is not hovered over
clickButton[move].setBackground(Color.WHITE); // color will be whte, just like our background
}
}
}
});
clickButton[i].addActionListener(new ActionListener() {
//our click events, going to override to let it know what we want to happen
//once we click on the button
public void actionPerformed(ActionEvent e) {
clickButton[move].setEnabled(false); //going to disable the button after it is clicked
//ORDER: button gets clicked first, then the test is added
mouseListener(e, move); // our mouseListenerEvent in game class
//
}
});
}
}
public static void playAgain() {
try{
System.out.println("NEW GAME");
SwingUtilities.invokeLater(new tic(frame)); // run the run(class) again
}
catch(Exception e){ // wanted to test to ensure that Runnable could be invoked
System.out.println("Could not excute Runnable application");
e.printStackTrace();
}
}
public static JFrame getFrame() {
return frame;
}
public tic userMove(int moveMade){
getTemplateOfBoard()[moveMade] = getUserTurn();
// index of the board, or in simpler terms, where the user
// inserts there turn i.e X or O, 0-8
//System.out.println(userMove);
//boolean statement to determine the turns
// So user X starts first
//if the turn is X, the nextTurn is now O,
if(getUserTurn() == 'X'){
setUserTurn('O');
}
else {
setUserTurn('X');
}
count++;
return this; // going to return the userTurn
// issue actually entering the userTurn is not giving right value, but using 'this' does
}
// for some odd reason the toString is causing some issues, keep getting #hash code
//saw online to override it like this
// will make the board out of emepty strings
// going to return a string representation of an object
public String toString(){
return new String(getTemplateOfBoard());
}
public void mouseListener(ActionEvent e, int moveMade){
// mouse click events
// what happens after a button is clicked
if(getTemplateOfBoard()[moveMade] == ' '){ // the user can only space a click, so an letter on the field if it is empty
((JButton)e.getSource()).setText(Character.toString(getUserTurn())); // when the button is clicked, we want an X placed there
if (getUserTurn() == 'X'){
UIManager.getDefaults().put("Button.disabledText",Color.RED); // when the but gets disabled the test will turn red
}
else{
UIManager.getDefaults().put("Button.disabledText",Color.BLUE);
}
//calling the method userTurn to determine who goes next
//problem is that is expects a String
//going to override the toString method
userMove(moveMade); // calling userMove in moveMade, moveMade is the index at which the user put either an X or a O
winner(); // we want to check each time to ensure there was/was not a winner
}
}
public tic winner() { // determines who is the winner
//list below defines all the possible win combinations
// the index of where a X or O can be place
// placed the locations to a int value
int win1 = templateOfBoard[0] + templateOfBoard[1] + templateOfBoard[2];
int win2 = templateOfBoard[3] + templateOfBoard[4] + templateOfBoard[5];
int win3 = templateOfBoard[6] + templateOfBoard[7] + templateOfBoard[8];
int win4 = templateOfBoard[0] + templateOfBoard[3] + templateOfBoard[6];
int win5 = templateOfBoard[1] + templateOfBoard[4] + templateOfBoard[7];
int win6 = templateOfBoard[2] + templateOfBoard[5] + templateOfBoard[8];
int win7 = templateOfBoard[0] + templateOfBoard[4] + templateOfBoard[8];
int win8 = templateOfBoard[2] + templateOfBoard[4] + templateOfBoard[6];
int[] win = new int[]{win1,win2,win3,win4,win5,win6,win7,win8};
// making a array to go through all the possibile wins
//possible total of wins is 8
for(int i = 0;i<win.length;i++){
// looping through the win possibilities
if(win[i] == 264){ // if one of the the combinations equal 'X','X','X' which equals 264, then there is a winner
System.out.println("X is the winner!!!");
System.out.println("Game Over!");
number = i;
draw(); // call draw method
return this; // if statement is true, it will return this(gameOver)
}
else if(win[i] == 237 ){ // if one of the the combinations equal 'O','O','O' which equals 234, then there is a winner
System.out.println("O is the winner!!!");
System.out.println("Game Over!");
number = i;
//draw(); // call draw method
return this;
}
if (count == 9) {
// if none of the statements above are true, it automatically comes done to here
//so if there is nine moves and no win, it is a draw
}
}
return this;
// going to return this method ;
}
private void draw(){ // drawing a line at winning location
Graphics2D g1 = (Graphics2D) getFrame().getGraphics(); // declaring graphics on our Jframe
Stroke stroke3 = new BasicStroke(12f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); // make our strokes cap off round
if(number == 0){ // statements will determine the win location, so at win0, XXX,
g1.setStroke(stroke3); // we will add stroke to our line
g1.drawLine(0,104,500,104); // draw the line starting at the 0,104 and end it at coordinates 500,104
}
else if(number == 1){
g1.setStroke(stroke3);
g1.drawLine(0,257,500,257);
}
else if(number == 2){
g1.setStroke(stroke3);
g1.drawLine(0,411,500,411);
}
else if(number == 3){
g1.setStroke(stroke3);
g1.drawLine(88,0,88,500);
}
else if(number == 4){
g1.setStroke(stroke3);
g1.drawLine(250,0,250,500);
}
else if(number == 5){
g1.setStroke(stroke3);
g1.drawLine(411,0,411,500);
}
else if(number == 6){
g1.setStroke(stroke3);
g1.drawLine(-22,0,500,500);
}
else if(number == 7){
g1.setStroke(stroke3);
g1.drawLine(520,0,0,500);
}
}
// want to be able to access the private variables
//so we will make getter and setter methods for the ones that we need
public char getUserTurn() { // getter method for userTurn
return userTurn;
}
public void setUserTurn(char userTurn) { // setter method
this.userTurn = userTurn;
}
public char[] getTemplateOfBoard() { //getter method
return templateOfBoard;
}
public void setTemplateOfBoard(char[] templateOfBoard) { // setter method
this.templateOfBoard = templateOfBoard;
}
}
Painting over the top of components can be troublesome, you can't override the paintComponent method of the container which contains the components, because this paints in the background, you can't override the paint method of the container, as child components can be painted without the parent container been notified...
You could add a transparent component over the whole lot, but this just introduces more complexity, especially when a component already already exists ...
public class ConnectTheDots {
public static void main(String[] args) {
new ConnectTheDots();
}
public ConnectTheDots() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
PaintPane pp = new PaintPane();
JFrame frame = new JFrame("Test");
frame.setGlassPane(pp);
pp.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DotsPane(pp));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private List<JButton[]> connections;
private JButton lastSelected;
public PaintPane() {
setOpaque(false);
connections = new ArrayList<>(25);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (lastSelected != null) {
g2d.setColor(Color.RED);
int x = lastSelected.getX() + ((lastSelected.getWidth() - 8) / 2);
int y = lastSelected.getY() + ((lastSelected.getHeight() - 8) / 2);
g2d.fillOval(x, y, 8, 8);
}
for (JButton[] group : connections) {
g2d.setColor(Color.BLUE);
Point startPoint = group[0].getLocation();
Point endPoint = group[1].getLocation();
startPoint.x += (group[0].getWidth() / 2);
startPoint.y += (group[1].getHeight()/ 2);
endPoint.x += (group[0].getWidth() / 2);
endPoint.y += (group[1].getHeight()/ 2);
g2d.draw(new Line2D.Float(startPoint, endPoint));
}
g2d.dispose();
}
protected void buttonClicked(JButton btn) {
if (lastSelected == null) {
lastSelected = btn;
} else {
connections.add(new JButton[]{lastSelected, btn});
lastSelected = null;
}
revalidate();
repaint();
}
}
public class DotsPane extends JPanel {
private PaintPane paintPane;
public DotsPane(final PaintPane pp) {
paintPane = pp;
ActionListener al = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
paintPane.buttonClicked(btn);
}
};
setLayout(new GridLayout(6, 6));
for (int index = 0; index < 6 * 6; index++) {
JButton btn = new JButton(".");
add(btn);
btn.addActionListener(al);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Take a look at How to Use Root Panes for more details

JLabel.setText("__") will not print multiple times while in for loop

I have placed my JLabel.setText("__") inside a for loop so it can print the length of a word replacing each letter with a 'space' . It is for a hangman game to display the length of the word using blank spaces. However it is only printing once. Any tips on why? Also, if you have any tips on better organizing my code that would be appreciated. Thanks in advance.
/*PACKAGE DECLARATION*/
package Game;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/************************
* GAME MECHANICS CLASS *
* **********************/
public class GameStructure {
/* INSTANCE DECLARATIONS */
private String []wordList = {"computer","java","activity","alaska","appearance","article",
"automobile","basket","birthday","canada","central","character","chicken","chosen",
"cutting","daily","darkness","diagram","disappear","driving","effort","establish","exact",
"establishment","fifteen","football","foreign","frequently","frighten","function","gradually",
"hurried","identity","importance","impossible","invented","italian","journey","lincoln",
"london","massage","minerals","outer","paint","particles","personal","physical","progress",
"quarter","recognise","replace","rhythm","situation","slightly","steady","stepped",
"strike","successful","sudden","terrible","traffic","unusual","volume","yesterday"};
private int []length = new int [64];
private JTextField tf;//text field instance variable (used)
private JLabel jl2;//label instance variable (used)
private JLabel jl3;//label instance (working on)
private String letter;
/*****************
* LENGTH METHOD *
* ***************/
public void length(){
jl3 = new JLabel();
int j = 0;
for(j = 0; j<64; j++) {
length[j] = wordList[j].length();//gets length of words in wordList
}//end for
int l = 0;
for(int m = 0; m<length[l]; m++) {//supposed to print length of word with '__' as each letter
jl3.setText("__ ");//instead only printing once
l++;
}//end for
}//end length method
/*****************
* WINDOW METHOD *
* ***************/
public void window() {
LoadImageApp i = new LoadImageApp();//calling image class
JFrame gameFrame = new JFrame();//declaration
JPanel jp = new JPanel();
JPanel jp2 = new JPanel();//jpanel for blanks
JLabel jl = new JLabel("Enter a Letter:");//prompt with label
tf = new JTextField(1);//length of text field by character
jl2 = new JLabel("Letters Used: ");
jp2.add(jl3);
jp.add(jl);//add label to panel
jp.add(tf);//add text field to panel
jp.add(jl2);//add letters used
gameFrame.add(i); //adds background image to window
i.add(jp); // adds panel containing label to background image panel
i.add(jp2);
gameFrame.setTitle("Hangman");//title of frame window
gameFrame.setSize(850, 600);//sets size of frame
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//exit when 'x' button pressed
gameFrame.setIconImage(new ImageIcon("Hangman-Game-grey.png").getImage());//set the frame icon to an image loaded from a file
gameFrame.setLocationRelativeTo(null);//window centered
gameFrame.setResizable(false);//user can not resize window
gameFrame.setVisible(true);//display frame
}//end window method
/*********************
* USER INPUT METHOD *
* *******************/
public void userInput() {
tf.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {//when enter key pressed
JTextField tf = (JTextField)e.getSource();
letter = tf.getText();
jl2.setText(jl2.getText() + letter + " ");//sets jlabel text to users entered letter
}//end actionPerformed method
});
}//end userInput method
}//end GameMechanics class
"However it is only printing once. Any tips on why?"
setText will only set the text once. So all you're doing in the loop is setting the text over and over. Here is a suggestion. Concatenate the Strings in the loop, then set the text. Like this:
String line = "";
for(int m = 0; m<length[l]; m++) {
line += "__ ";
l++;
}
jl3.setText(line);
" Also, if you have any tips on better organizing my code that would be appreciated. "
Try Code Review for this.

can't find source of inadvertent loop

I started refactoring this program I was working on and hit a major road block... I have one class that acts as a nucleus, with about 6 other smaller (but still important) classes working together to run the program... I took one method [called 'populate()'] out the nucleus class and made an entirely new class with it [called 'PopulationGenerator'], but when I try to create an object of the newly created class anywhere in the nucleus class I get stuck in a never ending loop of that new class
I've never had this issue when trying to create objects before... Here's the nucleus class before refactoring:
public class Simulator
{
// Constants representing configuration information for the simulation.
// The default width for the grid.
private static final int DEFAULT_WIDTH = 120;
// The default depth of the grid.
private static final int DEFAULT_DEPTH = 80;
// The probability that a fox will be created in any given grid position.
private static final double FOX_CREATION_PROBABILITY = 0.02;
// The probability that a rabbit will be created in any given grid position.
private static final double RABBIT_CREATION_PROBABILITY = 0.08;
// List of animals in the field.
private List<Animal> animals;
// The current state of the field.
private Field field;
// The current step of the simulation.
private int step;
// A graphical view of the simulation.
private SimulatorView view;
/**
* Construct a simulation field with default size.
*/
public Simulator()
{
this(DEFAULT_DEPTH, DEFAULT_WIDTH);
}
/**
* Create a simulation field with the given size.
* #param depth Depth of the field. Must be greater than zero.
* #param width Width of the field. Must be greater than zero.
*/
public Simulator(int depth, int width)
{
if(width <= 0 || depth <= 0) {
System.out.println("The dimensions must be greater than zero.");
System.out.println("Using default values.");
depth = DEFAULT_DEPTH;
width = DEFAULT_WIDTH;
}
animals = new ArrayList<Animal>();
field = new Field(depth, width);
// Create a view of the state of each location in the field.
view = new SimulatorView(depth, width);
view.setColor(Rabbit.class, Color.orange);
view.setColor(Fox.class, Color.blue);
// Setup a valid starting point.
reset();
}
/**
* Run the simulation from its current state for a reasonably long period,
* (4000 steps).
*/
public void runLongSimulation()
{
simulate(4000);
}
/**
* Run the simulation from its current state for the given number of steps.
* Stop before the given number of steps if it ceases to be viable.
* #param numSteps The number of steps to run for.
*/
public void simulate(int numSteps)
{
for(int step = 1; step <= numSteps && view.isViable(field); step++) {
simulateOneStep();
}
}
/**
* Run the simulation from its current state for a single step.
* Iterate over the whole field updating the state of each
* fox and rabbit.
*/
public void simulateOneStep()
{
step++;
// Provide space for newborn animals.
List<Animal> newAnimals = new ArrayList<Animal>();
// Let all rabbits act.
for(Iterator<Animal> it = animals.iterator(); it.hasNext(); ) {
Animal animal = it.next();
animal.act(newAnimals);
if(! animal.isAlive()) {
it.remove();
}
}
// Add the newly born foxes and rabbits to the main lists.
animals.addAll(newAnimals);
view.showStatus(step, field);
}
/**
* Reset the simulation to a starting position.
*/
public void reset()
{
step = 0;
animals.clear();
populate();
// Show the starting state in the view.
view.showStatus(step, field);
}
/**
* Randomly populate the field with foxes and rabbits.
*/
private void populate()
{
Random rand = Randomizer.getRandom();
field.clear();
for(int row = 0; row < field.getDepth(); row++) {
for(int col = 0; col < field.getWidth(); col++) {
if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Fox fox = new Fox(true, field, location);
animals.add(fox);
}
else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Rabbit rabbit = new Rabbit(true, field, location);
animals.add(rabbit);
}
// else leave the location empty.
}
}
}
}
EDIT:
Here's this same class AFTER refactoring ...
import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Color;
/**
* A simple predator-prey simulator, based on a rectangular field
* containing rabbits and foxes.
*
* Update 10.40:
* Now *almost* decoupled from the concrete animal classes.
*
* #TWiSTED_CRYSTALS
*/
public class Simulator
{
// Constants representing configuration information for the simulation.
// The default width for the grid.
private static final int DEFAULT_WIDTH = 120;
// The default depth of the grid.
private static final int DEFAULT_DEPTH = 80;
// The current state of the field.
private Field field;
// The current step of the simulation.
private int step;
// A graphical view of the simulation.
private SimulatorView view;
//Population Generator class... coupled to fox and rabbit classes
private PopulationGenerator popGenerator;
// Lists of animals in the field. Separate lists are kept for ease of iteration.
private List<Animal> animals;
/**
* Construct a simulation field with default size.
*/
public Simulator()
{
this(DEFAULT_DEPTH, DEFAULT_WIDTH);
}
/**
* Create a simulation field with the given size.
* #param depth Depth of the field. Must be greater than zero.
* #param width Width of the field. Must be greater than zero.
*/
public Simulator(int depth, int width)
{
if(width <= 0 || depth <= 0) {
System.out.println("The dimensions must be greater than zero.");
System.out.println("Using default values.");
depth = DEFAULT_DEPTH;
width = DEFAULT_WIDTH;
}
animals = new ArrayList<Animal>();
field = new Field(depth, width);
// Create a view of the state of each location in the field.
//
// view.setColor(Rabbit.class, Color.orange); // PG
// view.setColor(Fox.class, Color.blue); // PG
// Setup a valid starting point.
reset();
}
/**
* Run the simulation from its current state for a reasonably long period,
* (4000 steps).
*/
public void runLongSimulation()
{
simulate(4000);
}
/**
* Run the simulation from its current state for the given number of steps.
* Stop before the given number of steps if it ceases to be viable.
* #param numSteps The number of steps to run for.
*/
public void simulate(int numSteps)
{
for(int step = 1; step <= numSteps && view.isViable(field); step++) {
simulateOneStep();
}
}
/**
* Run the simulation from its current state for a single step.
* Iterate over the whole field updating the state of each
* fox and rabbit.
*/
public void simulateOneStep()
{
step++;
// Provide space for animals.
List<Animal> newAnimals = new ArrayList<Animal>();
// Let all animals act.
for(Iterator<Animal> it = animals.iterator(); it.hasNext(); ) {
Animal animal = it.next();
animal.act(newAnimals);
if(! animal.isAlive()) {
it.remove();
}
}
animals.addAll(newAnimals);
}
/**
* Reset the simulation to a starting position.
*/
public void reset()
{
PopulationGenerator popGenerator = new PopulationGenerator();
step = 0;
animals.clear();
popGenerator.populate();
// Show the starting state in the view.
view.showStatus(step, field);
}
public int getStep()
{
return step;
}
}
... and the new class
import java.util.ArrayList;
import java.util.Random;
import java.util.List;
import java.awt.Color;
public class PopulationGenerator
{
// The default width for the grid.
private static final int DEFAULT_WIDTH = 120;
// The default depth of the grid.
private static final int DEFAULT_DEPTH = 80;
// The probability that a fox will be created in any given grid position.
private static final double FOX_CREATION_PROBABILITY = 0.02;
// The probability that a rabbit will be created in any given grid position.
private static final double RABBIT_CREATION_PROBABILITY = 0.08;
// Lists of animals in the field. Separate lists are kept for ease of iteration.
private List<Animal> animals;
// The current state of the field.
private Field field;
// A graphical view of the simulation.
private SimulatorView view;
/**
* Constructor
*/
public PopulationGenerator()
{
animals = new ArrayList<Animal>();
field = new Field(DEFAULT_DEPTH, DEFAULT_WIDTH);
}
/**
* Randomly populate the field with foxes and rabbits.
*/
public void populate()
{
// Create a view of the state of each location in the field.
view = new SimulatorView(DEFAULT_DEPTH, DEFAULT_WIDTH);
view.setColor(Rabbit.class, Color.orange); // PG
view.setColor(Fox.class, Color.blue); // PG
Simulator simulator = new Simulator();
Random rand = Randomizer.getRandom();
field.clear();
for(int row = 0; row < field.getDepth(); row++) {
for(int col = 0; col < field.getWidth(); col++) {
if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Fox fox = new Fox(true, field, location);
animals.add(fox);
}
else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Rabbit rabbit = new Rabbit(true, field, location);
animals.add(rabbit);
}
// else leave the location empty.
}
}
view.showStatus(simulator.getStep(), field);
}
}
here's the Field class that the PopulationGenerator calls... I havent changed this class in any way
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
/**
* Represent a rectangular grid of field positions.
* Each position is able to store a single animal.
*
* #TWiSTED_CRYSTALS
*/
public class Field
{
// A random number generator for providing random locations.
private static final Random rand = Randomizer.getRandom();
// The depth and width of the field.
private int depth, width;
// Storage for the animals.
private Object[][] field;
/**
* Represent a field of the given dimensions.
* #param depth The depth of the field.
* #param width The width of the field.
*/
public Field(int depth, int width)
{
this.depth = depth;
this.width = width;
field = new Object[depth][width];
}
/**
* Empty the field.
*/
public void clear()
{
for(int row = 0; row < depth; row++) {
for(int col = 0; col < width; col++) {
field[row][col] = null;
}
}
}
/**
* Clear the given location.
* #param location The location to clear.
*/
public void clear(Location location)
{
field[location.getRow()][location.getCol()] = null;
}
/**
* Place an animal at the given location.
* If there is already an animal at the location it will
* be lost.
* #param animal The animal to be placed.
* #param row Row coordinate of the location.
* #param col Column coordinate of the location.
*/
public void place(Object animal, int row, int col)
{
place(animal, new Location(row, col));
}
/**
* Place an animal at the given location.
* If there is already an animal at the location it will
* be lost.
* #param animal The animal to be placed.
* #param location Where to place the animal.
*/
public void place(Object animal, Location location)
{
field[location.getRow()][location.getCol()] = animal;
}
/**
* Return the animal at the given location, if any.
* #param location Where in the field.
* #return The animal at the given location, or null if there is none.
*/
public Object getObjectAt(Location location)
{
return getObjectAt(location.getRow(), location.getCol());
}
/**
* Return the animal at the given location, if any.
* #param row The desired row.
* #param col The desired column.
* #return The animal at the given location, or null if there is none.
*/
public Object getObjectAt(int row, int col)
{
return field[row][col];
}
/**
* Generate a random location that is adjacent to the
* given location, or is the same location.
* The returned location will be within the valid bounds
* of the field.
* #param location The location from which to generate an adjacency.
* #return A valid location within the grid area.
*/
public Location randomAdjacentLocation(Location location)
{
List<Location> adjacent = adjacentLocations(location);
return adjacent.get(0);
}
/**
* Get a shuffled list of the free adjacent locations.
* #param location Get locations adjacent to this.
* #return A list of free adjacent locations.
*/
public List<Location> getFreeAdjacentLocations(Location location)
{
List<Location> free = new LinkedList<Location>();
List<Location> adjacent = adjacentLocations(location);
for(Location next : adjacent) {
if(getObjectAt(next) == null) {
free.add(next);
}
}
return free;
}
/**
* Try to find a free location that is adjacent to the
* given location. If there is none, return null.
* The returned location will be within the valid bounds
* of the field.
* #param location The location from which to generate an adjacency.
* #return A valid location within the grid area.
*/
public Location freeAdjacentLocation(Location location)
{
// The available free ones.
List<Location> free = getFreeAdjacentLocations(location);
if(free.size() > 0) {
return free.get(0);
}
else {
return null;
}
}
/**
* Return a shuffled list of locations adjacent to the given one.
* The list will not include the location itself.
* All locations will lie within the grid.
* #param location The location from which to generate adjacencies.
* #return A list of locations adjacent to that given.
*/
public List<Location> adjacentLocations(Location location)
{
assert location != null : "Null location passed to adjacentLocations";
// The list of locations to be returned.
List<Location> locations = new LinkedList<Location>();
if(location != null) {
int row = location.getRow();
int col = location.getCol();
for(int roffset = -1; roffset <= 1; roffset++) {
int nextRow = row + roffset;
if(nextRow >= 0 && nextRow < depth) {
for(int coffset = -1; coffset <= 1; coffset++) {
int nextCol = col + coffset;
// Exclude invalid locations and the original location.
if(nextCol >= 0 && nextCol < width && (roffset != 0 || coffset != 0)) {
locations.add(new Location(nextRow, nextCol));
}
}
}
}
// Shuffle the list. Several other methods rely on the list
// being in a random order.
Collections.shuffle(locations, rand);
}
return locations;
}
/**
* Return the depth of the field.
* #return The depth of the field.
*/
public int getDepth()
{
return depth;
}
/**
* Return the width of the field.
* #return The width of the field.
*/
public int getWidth()
{
return width;
}
}
your problem is not in the Field class but below it. The Simulator constructor calls reset() which creates a new PopulationGenerator object, then calls populate() on that object. The populate() method calls Simulator simulator = new Simulator(); which creates a new Simulator object which continues the cycle. Solution: don't create a new Simulator object in PopulationGenerator, but instead pass the existing simulator to PopulationGenerator through its constructor or through a setSimulator(...) method.
e.g.,
class PopulationGenerator {
// ... etc...
private Simulator simulator; // null to begin with
// pass Simulator instance into constructor.
// Probably will need to do the same with SimulatorView
public PopulationGenerator(Simulator simulator, int depth, int width) {
this.simulator = simulator; // set the instance
// ... more code etc...
}
public void populate() {
// don't re-create Simulator here but rather use the instance passed in
}
}

How to know what component was clicked from a grid?

I have created a grid that contains 10x10 buttons using 2d arrays. i tried x.getSource().getLabel() but compiler says they are not compatible. also i want to get the specific button that was clicked.
I want to get the exact button that was clicked from the grid i made and get its label. what method i need to use?
import javax.swing.JFrame; //imports JFrame library
import javax.swing.JButton; //imports JButton library
import java.awt.GridLayout; //imports GridLayout library
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class ButtonGrid extends JFrame implements ActionListener
{
JFrame frame=new JFrame(); //creates frame
JButton[][] grid; //names the grid of buttons
public int x;
public int y;
public ButtonGrid(int width, int length)
{ //constructor
char temp;
String charput;
frame.setLayout(new GridLayout(width,length)); //set layout
grid = new JButton[width][length]; //allocate the size of grid
for(int y=0; y<length; y++)
{ //start
for(int x=0; x<width; x++)
{
temp=charRand(); //get random character
charput = ""+temp; //converts character to string
grid[x][y]=new JButton(); //creates new button
frame.add(grid[x][y]); //adds button to grid
grid[x][y].addActionListener(this);
grid[x][y].setLabel(charput); //set charput as label
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack(); //sets appropriate size for frame
frame.setVisible(true); //makes frame visible
}
/* generates randomiz letter for the button of the grid*/
public char charRand()
{
String consonantList = new String("BCDFGHL"); //list 1
String consonantList2 = new String("MNPRSTWY"); //list 2
String consonantList3= new String("JQXZVK"); //list 3
String vowelList = new String("AEIOU"); //list of vowels
int vowelOrConsonant; //holder of random number
int chosen; //selects the chosen random letter
Random randGen = new Random(); //generates random int value
char selected; //gets the random letter chosen by variable chosen
vowelOrConsonant = randGen.nextInt(4);
if (vowelOrConsonant == 0)
{
chosen = randGen.nextInt(5); //list of vowels
selected = vowelList.charAt(chosen); //selects a char from vowels
}
else if(vowelOrConsonant == 1)
{
chosen = randGen.nextInt(7); //list 1
selected = consonantList2.charAt(chosen); //selects a char
}
else if(vowelOrConsonant == 2)
{
chosen = randGen.nextInt(8); //list 2
selected = consonantList2.charAt(chosen); //selects a char
}
else
{
chosen = randGen.nextInt(6); //list 3
selected = consonantList.charAt(chosen);
}
return selected; //returns the random letter
}
public static void main(String[] args)
{
new ButtonGrid(10,10);//makes new ButtonGrid with 2 parameters
}
public void actionPerformed(ActionEvent x)
{
/* i get wrong output on this line.
* i want to get the exact button that was clicked and get its label.
*/
if (x.getSource()==grid[x][y])
JOptionPane.showMessageDialog(null,x.getSource().getLabel);
}
}
getSource() returns an Object, so you need to cast it to JButton, like this:
public void actionPerformed(ActionEvent x) {
JOptionPane.showMessageDialog(null, ((JButton)x.getSource()).getText());
}
Also note that getLabel() and setLabel() are deprecated and should be replaced by getText() and setText().
You can make a class that extends Jbutton. and add two fields to it of type int(X & Y ). The constructor will look like this: public MyButton(int x, y);
And when you are filling your grid, don't use directly the Jbutton class. Use your class and for X & Y supply the i & j parameters of the two for cycles that you are using. Now when you are using Action Listener for your button you can use his X & Y fields as they represent its place on the grid. Hope this helps! It tottaly worked for me and its simple as hell.

HexapawnBoard class in Java

I have to complete 4 methods but I am having difficulty understanding them. I'm trying to complete whitemove(). I know that I have to iterate through the board, but I cannot totally understand how I'm supposed to do it!
import java.util.List;
import java.util.ArrayList;
public class HexapawnBoard {
private static final int WHITE_PIECE = 1;
private static final int BLACK_PIECE = 2;
private static final int EMPTY = 0;
private static final int BOARD_SIZE = 3;
private int[][] board;
/**
* Create a board position from a string of length BOARD_SIZE*BOARD_SIZE (9).
* The first BOARD_SIZE positions in the string correspond to the black player's home
* position. The last BOARD_SIZE positions in the string correspond ot the white player's
* home position. So, the string "BBB WWW" corresponds to a starting position.
*
* #param pos the string encoding the position of the board
*/
public HexapawnBoard(String pos)
{
if(pos.length() != BOARD_SIZE * BOARD_SIZE)
throw new RuntimeException("HexapawnBoard string must be of length BOARD_SIZExBOARD_SIZE");
board = new int[BOARD_SIZE][BOARD_SIZE];
for(int row=0;row<BOARD_SIZE;row++)
{
for(int col=0;col<BOARD_SIZE;col++)
{
switch(pos.charAt(row*BOARD_SIZE+col))
{
case 'B':
case 'b':
board[row][col] = BLACK_PIECE;
break;
case 'W':
case 'w':
board[row][col] = WHITE_PIECE;
break;
case ' ':
board[row][col] = EMPTY;
break;
default:
throw new RuntimeException("Invalid Hexapawn board pattern " + pos);
}
}
}
}
/**
* A copy constructor of HexapawnBoard
*
* #param other the other instance of HexapawnBoard to copy
*/
public HexapawnBoard(HexapawnBoard other)
{
board = new int[BOARD_SIZE][BOARD_SIZE];
for(int i=0;i<BOARD_SIZE;i++)
for(int j=0;j<BOARD_SIZE;j++)
this.board[i][j] = other.board[i][j];
}
/**
* Return a string version of the board. This uses the same format as the
* constructor (above)
*
* #return a string representation of the board.
*/
public String toString()
{
StringBuffer sb = new StringBuffer();
for(int row=0;row<BOARD_SIZE;row++)
{
for(int col=0;col<BOARD_SIZE;col++)
{
switch(board[row][col])
{
case BLACK_PIECE:
sb.append('B');
break;
case WHITE_PIECE:
sb.append('W');
break;
case EMPTY:
sb.append(' ');
break;
}
}
}
return sb.toString();
}
/**
* Determine if this board position corresponds to a winning state.
*
* #return true iff black has won.
*/
public boolean blackWins()
{
for(int col=0;col<BOARD_SIZE;col++)
if(board[BOARD_SIZE-1][col] == BLACK_PIECE)
return true;
return false;
}
/**
* Determine if this board position corresponds to a winning state
*
* #return true iff white has won
*/
public boolean whiteWins()
{
for(int col=0;col<BOARD_SIZE;col++)
if(board[0][col] == WHITE_PIECE)
return true;
return false;
}
/**
* Determine if black has a move
*
* # return truee iff black has a move
*/
public boolean blackCanMove()
{
return false;
}
/**
* Return a List of valid moves of white. Moves are represented as valid
* Hexapawn board positions. If white cannot move then the list is empty.
*
* #return A list of possible next moves for white
*/
public List<HexapawnBoard> whiteMoves()
{
return null
}
/**
* Determine if two board positions are equal
* #param other the other board position
* #return true iff they are equivalent board positions
*/
public boolean equals(HexapawnBoard other)
{
return true;
}
/**
* Determine if two board positions are reflections of each other
* #param other the other board position
* #return true iff they are equivalent board positions
*/
public boolean equalsReflection(HexapawnBoard other)
{
return true;
}
}
First of all, the code that you have so far seems to be correct.
Now, for the four methods that you have left, I can't really help you with the blackCanMove() or the whiteMoves() methods because I don't know what the rules for moving are in this hexapawn game. If you would explain the rules, I could help with that.
As far as the equals() and equalsReflection() methods go, you basically need to do what you did in the copy constructor, but instead of copying, do a conditional test. If two positions do not match up to what they are supposed to be, return false. Otherwise, once you have checked each square and they are all correct, return true.
As far as the whiteMoves() method, you need to iterate through the board and find all of the white pieces. For each white piece, there may be a few (at most 3) valid moves. Check each of those positions to see if they are possible. The piece may move diagonally if there is a black piece in that spot, or it may move forward if there is no piece at all in that spot. For each valid move, create a new HexapawnBoard representing what the board would look life following that move. At the end of the method, return a list of all of the HexapawnBoards that you created.

Categories

Resources