Java Run another class with a JButton - java

public class SocialNetwork extends Program
implements Constants {
Canvas canvas = new Canvas();
public void init() {
breakoutButton = new JButton("Play Breakout Game");
breakoutButton.setForeground(Color.WHITE);
breakoutButton.setBackground(Color.BLACK);
add(breakoutButton, WEST);
breakoutButton.addActionListener(this);
getContentPane().setBackground(Color.BLACK);
addActionListeners();
add(canvas);
}
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Play Breakout Game") || e.getSource() == breakoutButton) {
canvas.displayMessage("game started"); //displayMessage method displays the parameter string on the canvas.
Breakout bo = new Breakout();
bo.setVisible(true);
}
}
This is the main code which creates the button which is supposed to launch the breakout game. The code for breakout is :
public class Breakout extends GraphicsProgram {
public void run() {
setBackground(Color.BLACK);
setUpBricks();
points = new GLabel("Points: " + pointsCounter);
add(points, getWidth()/2 - points.getWidth()/2, getHeight() - points.getAscent());
points.setColor(Color.WHITE);
for(int i=0; i < NTURNS; i++) {
addMouseListeners();
setUpGame();
playGame();
if (brickCounter == 0) {
GLabel winner = new GLabel("You Win! You got " + pointsCounter + " points.");
winner.setFont("Times New Roman-25");
winner.setColor(Color.WHITE);
add(winner, getWidth()/2 - winner.getWidth()/2, getHeight()/2 - winner.getAscent()/2);
break;
}
}
if (ball.getY() > getHeight()) {
GLabel message = new GLabel("Game Over! You got " + pointsCounter + " points.");
message.setFont("Times New Roman-25");
message.setColor(Color.WHITE);
add(message, getWidth()/2 - message.getWidth()/2, getHeight()/2 - message.getAscent()/2);
}
}
The problem is that when I click on the button, it registers the click, opens a JFrame, but does not run the program. There is just a blank JFrame. What am I doing wrong?
Note: I have only posted the basic code for the breakout game part.

Your code creates the Breakout object and sets its visibility:
Breakout bo = new Breakout();
bo.setVisible(true);
However, you never invoke any other methods. For example you may want to invoke a run method or a main method. You have to call those methods somehow in order to execute the code.
Another option would be to add a listener to the Breakout class so that it executes your code when the window opens, something like this:
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowOpened(java.awt.event.WindowEvent evt) {
//call a method that runs the program here!
}
});

Related

How to make Minimax Alpha Beta algorithm play itself?

I've developed a working chess engine with minimax and alpha-beta, however I want to test my algorithm by playing itself, computer vs computer. I have tried everything to no avail. Just wondering how I would go about this?
public class Main {
static JTextArea textField;
public static void main(String[] args) {
while ( 'K' != ABChess.board[ABChess.kingLocationUU/8][ABChess.kingLocationUU%8]) {ABChess.kingLocationUU++;}
while ( 'k' != ABChess.board[ABChess.kingLocationLL/8][ABChess.kingLocationLL%8]) {ABChess.kingLocationLL++;}
Asset.init("/images/ChessPiecess.png");
ABChess.updateKingLocations();
//print();
JPanel depthPanel = depthPanel();
JPanel optionPanel = optionPanel();
JPanel logPanel = logPanel();
JPanel menuPanel = new JPanel();
menuPanel.setPreferredSize(new Dimension(140, 100));
menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS));
menuPanel.add(depthPanel);
menuPanel.add(optionPanel);
menuPanel.add(logPanel);
GUInterface gui = new GUInterface();
JPanel panel = new JPanel(new BorderLayout());
panel.add(gui);
panel.add(menuPanel, BorderLayout.EAST);
JFrame frame = new JFrame(ABChess.title);
frame.setSize(ABChess.width, ABChess.height);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.out.println(ABChess.possibleMoves());
ABChess.playerChoice = JOptionPane.showOptionDialog(null, "Who wants to make the first move?", "Who moves first?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, ABChess.options, ABChess.options[0]);
if (ABChess.playerChoice == 0){
ABChess.flipBoard();
long startTime=System.currentTimeMillis();
Move autoMove = AlphaBeta.alphaBeta(ABChess.gameDepth, 1000000, -1000000, new Move(), 0);
long endTime=System.currentTimeMillis();
ABChess.makeMove(autoMove);
ABChess.flipBoard();
System.out.println("COMPUTER'S MOVE TOOK "+((endTime-startTime)/1000.0)+" SECONDS");
ABChess.printBoard();
frame.repaint();
displayMessage("Took "+((endTime-startTime)/1000.0)+" seconds");
}
}
This is the initial call to the algorithm when the file is ran.
public void mousePressed(MouseEvent event) {
if ( event.getX() < 8*sizeOfSquare && event.getY() < 8*sizeOfSquare) {
mouseX = event.getX();
mouseY = event.getY();
repaint();
}
}
public void mouseReleased(MouseEvent event) {
if (event.getX() < 8*sizeOfSquare && event.getY() < 8*sizeOfSquare) {
newMouseX = event.getX();
newMouseY = event.getY();
if (event.getButton() == MouseEvent.BUTTON1) {
// Regular move
Move legalMovesMove = new Move(mouseY/sizeOfSquare, mouseX/sizeOfSquare, newMouseY/sizeOfSquare, newMouseX/sizeOfSquare, Test6.board[newMouseY/sizeOfSquare][newMouseX/sizeOfSquare]);
java.util.List<Move> legalMoves = ABChess.possibleMoves();
for(Move m : legalMoves) {
if (m.equals(legalMovesMove)) {
ABChess.makeMove(legalMovesMove);
ABChess.flipBoard();
long startTime=System.currentTimeMillis();
Move autoMove = AlphaBeta.alphaBeta(ABChess.gameDepth, 1000000, -1000000, new Move(), 0);
long endTime=System.currentTimeMillis();
ABChess.makeMove(autoMove);
ABChess.flipBoard();
System.out.println("COMPUTER'S MOVE TOOK "+((endTime-startTime)/1000.0)+" SECONDS");
ABChess.printBoard();
repaint();
}
}
checkMate = ABChess.kingSafe();
if(checkMate == false){
int yes = JOptionPane.showOptionDialog(null, "Do you want to make the first move?", "Who moves first?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, JOptionPane.YES_OPTION);
if (yes == JOptionPane.YES_OPTION){
ABChess.resetGame();
repaint();
} else if (yes == JOptionPane.NO_OPTION){
System.exit(0);
}
}
legalMoves = ABChess.possibleMoves();
if (legalMoves.size() == 0) {
ABChess.playAgain = JOptionPane.showOptionDialog(null, "Stalemate! Wanna play again?", "Draw!", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, ABChess.choice, ABChess.choice[1]);
if (ABChess.playAgain == 0) {
System.out.println("Yes I will");
ABChess.resetGame();
repaint();
} else {
System.exit(0);
}
}
}
}
}
This is where the algorithm is called every time the mouse is released. Not sure how to code to where it plays itself with the white pieces instead of me.
I would normally seperate the Player from the Game, and the Game would request the interaction from the Player object. The Player object would either be a Human (so the needed input is delegated to some UI) or an AI so it would be delegated to some implementation which decides which move is best.
I would recommend using an object for the ABChess Game instead of static methods.
So with a bit of refactoring and seperating the UI from the logic as well, it could look like this:
interface Player {
Move decide(List<Move> legalMoves);
}
class ChessGame {
ABChess game;
Player player1;
Player player2;
UIInterface ui;
ChessGame(Player player1, Player player2, UIInterface ui) {
this.player1 = player1;
this.player2 = player2;
this.ui = ui;
game = ...
}
public void simulate() {
// ... initial ui ...
boolean player1Turn = true;
do {
Move move = null;
if (player1Turn) {
move = player1.decide(game.possibleMoves());
} else {
move = player2.decide(game.possibleMoves());
}
game.makeMove(move);
// ... update ui ...
player1Turn = !player1Turn;
// check if somebody has won ...
} while (game.isRunning());
// ... update ui with the game result ...
}
}
Once that is done simulating games becomes easy. You just need to initiate the ChessGame with the proper players and call the simulate method. At that point you could also decide to skip the UI presentation completly (so the learning will be much faster).

Swing going from menu to actual gameplay

So I am making a space invaders clone. Originally I had no problem getting my game to work with a simple main class that created the frame, created the gameplay and started the thread.
But then I tried to implement a start menu and it all went to crap. The menu appears with success but the gameplay does not appear when I press start.
I am running out of ideas and I am completely stumped. I am somewhat new as well to SO, so if there is anything I left out, I appreciate any help.
Here is the original with no menu that worked fine:
public static void main(String[] args) {
JFrame frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Gameplay gameplay = new Gameplay();
frame.add(gameplay);
frame.setVisible(true);
Thread t1 = new Thread(gameplay);
t1.start();
}
However, the moment I tried to implement a menu to then play the game, I am running into all sorts of trouble. I created a UI class as well as an actual "game" class like so:
public class UI {
JFrame frame, f2;
JPanel titrePanel, startButtonPanel, loadButtonPanel, p2;
JLabel nomJeu;
JButton startButton, loadButton;
Font fontTitre, fontStart;
Gameplay gameplay;
public void createUI(ChoixJeu cj) {
frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.black);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//------------------ECRAN MENU---------------------
//Titre
titrePanel = new JPanel();
titrePanel.setBounds(100, 100, 400, 100);
titrePanel.setBackground(Color.BLUE);
Font fontTitre = new Font("Times New Roman", Font.BOLD, 50);
Font fontStart = new Font("Times New Roman", Font.PLAIN, 20);
nomJeu = new JLabel("SpaceRaiders");
nomJeu.setForeground(Color.white);
nomJeu.setFont(fontTitre);
titrePanel.add(nomJeu);
//Start button
startButtonPanel = new JPanel();
startButtonPanel.setBounds(200, 400, 200, 40);
startButtonPanel.setBackground(Color.BLACK);
startButton = new JButton("START");
startButton.setBackground(Color.BLACK);
startButton.setForeground(Color.WHITE);
startButton.setFont(fontStart);
startButton.setFocusPainted(false);
startButton.addActionListener(cj);
startButton.setActionCommand("start");
startButtonPanel.add(startButton);
//Load Button
loadButtonPanel = new JPanel();
loadButtonPanel.setBounds(200, 440, 200, 100);
loadButtonPanel.setBackground(Color.BLACK);
loadButton = new JButton("LOAD");
loadButton.setBackground(Color.BLACK);
loadButton.setForeground(Color.WHITE);
loadButton.setFont(fontStart);
loadButton.setFocusPainted(false);
titrePanel.add(nomJeu);
loadButtonPanel.add(loadButton);
frame.add(startButtonPanel);
frame.add(titrePanel);
//------------------ECRAN MENU FIN---------------------
frame.setVisible(true);
}
And the game class...
public class Jeu {
ChoixJeu cj = new ChoixJeu();
UI ui = new UI();
Ecrans e = new Ecrans(ui);
Gameplay gp;
public static void main(String[] args) {
new Jeu();
}
public Jeu() {
ui.createUI(cj);
Gameplay gameplay = new Gameplay();
this.gp = gameplay;
}
public class ChoixJeu implements ActionListener {
#Override
public void actionPerformed(ActionEvent ae) {
String yourChoice = ae.getActionCommand();
switch (yourChoice) {
case "start":
e.montrerEcranJeu();
new Thread(gp).start();
ui.frame.add(gp);
break;
default:
break;
}
}
}
}
I also tried to make a class/method that hides the menu panels
public void montrerEcranJeu() {
//Cache Menu
ui.titrePanel.setVisible(false);
ui.startButtonPanel.setVisible(false);
//Montre Jeu
// ui.frame.add(gameplay);
}
And just in case the Gameplay class. The run() method is at the bottom
public class Gameplay extends JPanel implements KeyListener, ActionListener, Runnable {
private Ship player = new Ship(new Point(200, 555));
Timer t = new Timer(5, this);
private ArrayList<Laser> lasers = new ArrayList<Laser>();
private int laserNb;
private boolean readytofire;
private boolean shot = false;
private ArrayList<Invader> invaders = new ArrayList<Invader>();
private boolean pause;
public Gameplay() {
super();
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
for (int j = 0; j < 80; j += 20) {
for (int i = 0; i < 20; i++) {
invaders.add(new Invader(5 + i * 30, j));
}
}
}
public boolean addLaser(Laser a) {
lasers.add(a);
return true;
}
public boolean addPlayer(Ship p) {
this.player = p;
return true;
}
#Override
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_RIGHT == e.getKeyCode()) {
moveRight();
}
if (KeyEvent.VK_LEFT == e.getKeyCode()) {
moveLeft();
}
if (KeyEvent.VK_SPACE == e.getKeyCode()) {
shoot();
System.out.println("Space Action from Gameplay is working");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void actionPerformed(ActionEvent ae) {
repaint();
}
public void moveRight() {
if (player.getCentre().getX() >= 580) {
player.setX(580);
} else {
double movement = player.getCentre().getX();
movement += 10;
player.setX(movement);
}
this.repaint();
}
public void moveLeft() {
if (player.getCentre().getX() <= 20) {
player.setX(20);
} else {
double movement = player.getCentre().getX();
movement -= 10;
player.setX(movement);
}
this.repaint();
}
public void shoot() {
shot = true;
if (readytofire) {
Point top = new Point(player.getTopX(), player.getTopY());
Laser laser = new Laser(top);
addLaser(laser);
}
}
public void moveShot() {
if (shot) {
for (Laser l : lasers) {
l.setY(l.getTopLeft().getY() - 1);
}
}
}
#Override
public void paint(Graphics g) {
setBackground(Color.black);
super.paint(g);
player.draw(g);
for (Laser l : lasers) {
l.draw(g);
}
for (Invader i : invaders) {
i.draw(g);
}
}
// public void paintComponent (Graphics g){
// Controle Thread
public void run() {
while (true) {
moveShot();
for (Invader i : invaders) {
i.moveAndUpdate();
}
// for (Invader i : invaders) {
// if (){
// System.out.println("YOU ARE DEAD!");
// }
// }
try {
Thread.sleep(10);
readytofire = true;
} catch (InterruptedException ex) {
Logger.getLogger(Gameplay.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
So, using null layouts is the beginning of your problems. I might recommend using CardLayout which is designed to help you dynamically switch between views. See How to Use CardLayout for more details. I'd also suggest taking the time to read through Laying Out Components Within a Container and finding one or more appropriate layouts to support your menu.
You're also making a lot of fundamental mistakes. Swing is not thread safe, so you should avoid updating the UI (or something the UI depends on) from outside the context of the EDT - see Concurrency in Swing for more information and How to Use Swing Timers for a possible solution.
As a general recommendation, you should avoid overriding paint and, in the case of classes which extend from JComponent, prefer paintComponent instead. You should also avoid call methods which might change the state of the component during a paint cycle, this can increase the number of repaint requests and degrade the performance of your program (ie, don't call setBackground inside paint).
Have a look at Performing Custom Painting and Painting in AWT and Swing for more details about how the paint system works and how best you can work with it.
You should also avoid KeyListener, this is likely to cause you issues when you introduce other, focusable, components into the picture. Instead, you should favour the Key bindings API instead
I've read through [insert link or tutorial], but it still doesn't help...
And forgive me if this doesn't happen all the time.
The point of providing you the tutorial links is to encourage you to learn something;
Learn where to find answers to your questions
Learn how the APIs work
Expand your knowledge and understanding of how the APIs work
Having said that, they're not always "obvious" as to the solution. What I do when I'm in this situation is start with one or more new projects, dedicated to just working on that aspect of the API I'm trying to understand. For here I can explore the concepts in isolation and when I "think" I understand them, try and implement them into the project I'm working on. This might take a number of iterations, but once it works, I have gained a much deeper understanding and appreciation of the API then I would have gained from a simple "copy-n-paste" solution

Every time I pressed Roll(JButton) it left a picture of roll button on

I'm trying to make a snakes and ladders game. It doesn't done yet(no swap turn, no use of ladder and snake) and have so many bug.
But My point is that
I found a problem that make me very curious(Picture Below). It about making a token move. My strategy is that I add a[10][10] array of JPanal(I named it class as Cell) on a big JPanel(I named it class as Board) whose I set its bg as a picture of snakes and ladders game from google and set the layout to gridlayout(10,10). And on every Cell there's one token which is hiding and will only reveal when press the roll button and the output point to that Cell.
This is where the problem happened.
Image of the program when execute
When I press roll button for sometimes
There's a button appear every time I press!(They are not clickable though.)
I know that my start point doesn't even on the left bottom square but where is all that jbutton came from!
This is my main class
public class Main extends JFrame {
TextField text = new TextField();
Dice dice = new Dice();
int tempi = -1, tempj = -1,sum =0;
//Main Method
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Main mPage = new Main();
mPage.setVisible(true);
}
});
}
//Constructor
public Main(){
super("Snakes and Ladders");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(1280,768);
setLocation(400,150);
setLayout(new FlowLayout(FlowLayout.LEFT,30,100));
Board board = new Board();
getContentPane().add(board);
getContentPane().add(dice);
getContentPane().add(text);
//my problem is here.
dice.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int score = Dice.rollDice();
text.setText(String.valueOf(score));
if (tempi != -1 || tempj != -1){
board.cell[9-tempi][9-tempj].fade();
}
if (tempi == -1 && tempj == -1){
sum = sum + score - 1;
}
else sum = sum + score;
tempj = sum%10;
tempi = (sum - tempj)/10;
board.cell[9-tempi][9-tempj].reveal();
}
});
pack();
setMinimumSize(this.getSize());
}
}
This is Cell class
public class Cell extends JPanel implements Cloneable {
private Token pl1 = new Token();
//constructor
public Cell(){
setOpaque(true);
setBackground(new Color(0,0,0,0));
setLayout(new GridLayout(2,2));
this.fade();
this.add(pl1);
}
public void fade(){
pl1.setVisible(false);
}
public void reveal(){
pl1.setVisible(true);
}
}
This is Token class
public class Token extends JLabel {
private BufferedImage image = null;
public Token(){
try {
image = ImageIO.read(new File("C:\\Users\\myacc\\IdeaProjects\\Snakes and Ladders\\src\\Token.png"));
} catch (IOException e) {
e.printStackTrace();
}
Image player = image.getScaledInstance(20,20,Image.SCALE_SMOOTH);
this.setIcon(new ImageIcon(player));
}
}
setBackground(new Color(0,0,0,0));
Don't use backgrounds with transparency. Swing does not know how to paint transparent backgrounds properly.
For full transparency you just make the component non-opaque:
//setOpaque(true);
//setBackground(new Color(0,0,0,0));
setOpaque(false);
If you need semi-transparency, then you need to do custom painting yourself. Check out Background With Transparency for more information on this topic.
Also don't use a TextField. That is an AWT component. Use a JTextField which is the Swing component.

I'm probably doing this incorrectly. Is there a better way?

So usually when I make mock-up programs (like this one) I look for things I can improve on in case the situation happens again.
Today I thought I'd brush up on basic OOP (I understand the concept of OOP, just haven't messed around with it for a bit and wanted to freshen my memory). So I decided to make a little game that just creates 3 monsters on a 10x10 plane and 1 player (you), you are able to move your player in any x/y direction. My program works but I can't help but feel that I'm doing something incorrectly.
So the basic layout of my program was to have 5 classes. A GUI class that shows the game and gives you directional buttons for movement control, a class that creates the monsters, a class that creates the players, a class that creates the 10x10 board and keeps track of monster/player locations, and of course a main class that creates all the objects and has the main game loop and whatnot.
I was having a bit of a hard time interacting with my main class and my GUI class. What I ended up doing was doing a while loop in my main class and waiting until the player presses the start button, and once the player presses it (via action listener) the GUI class sets a public variable (running) from false to true, and I am able to act accordingly once the variable is changed.
HERE is where I feel like I am doing something wrong: At first my while loop would not terminate unless I printed out to the console. I Googled the issue and apparently people have said that it's some sort of issue with threading or "active polling", which I did not understand. I went to my program and added a small 10ms thread sleep in my while loops and everything started working great.
My question to you guys is, what is active polling? Why is it bad? How/why/where was this going on in my program? And finally if there's a better way of interacting with a GUI class and a main class. Sorry for the giant wall of text but I like to be thorough when explaining a situation!
TL;DR: Am I interacting correctly with my GUI class and my main class? If not what is the proper way to do it?
My main class:
public class MainGame {
public static void main(String[] args) throws InterruptedException{
ShowGUI gui = new ShowGUI();
while(!gui.running){
Thread.sleep(10);
}
Board gameBoard = new Board();
gui.setLabelText(gameBoard.getBoard());
//Add Player
Player playerOne = new Player(1000, "Player 1");
//Add monsters
Monster monstMatt = new Monster(1000, "Matt");
Monster monstJon = new Monster(1000, "Jon");
Monster monstAbaad = new Monster(1000, "Abaad");
while(gui.running){
Thread.sleep(10);
int x, y;
x = playerOne.getX();
y = playerOne.getY();
if(gui.buttonPress != -1){
if(gui.buttonPress == 1){
playerOne.move(x, --y);
}else if(gui.buttonPress == 2){
playerOne.move(x, ++y);
}else if(gui.buttonPress == 3){
playerOne.move(--x, y);
}else if(gui.buttonPress == 4){
playerOne.move(++x, y);
}
gui.buttonPress = -1;
gui.setLabelText(gameBoard.getBoard());
}
}
}
}
My GUI Class:
public class ShowGUI{
private JTextArea board;
private JButton moveUp;
private JButton moveDown;
private JButton moveLeft;
private JButton moveRight;
public boolean running = false;
public int buttonPress = -1;
public ShowGUI(){
System.out.println("GUI Successfully Loaded");
createAndShow();
}
private void createAndShow(){
JFrame mainFrame = new JFrame("Bad Game");
addComponents(mainFrame.getContentPane());
mainFrame.setSize(500, 400);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLocationRelativeTo(null);
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
private void addComponents(Container pane){
pane.setLayout(null);
board = new JTextArea(1, JLabel.CENTER);
moveUp = new JButton("Up");
moveDown = new JButton("Down");
moveLeft = new JButton("Left");
moveRight = new JButton("Right");
moveUp.setBounds(185, 225, 130, 35);
moveLeft.setBounds(115, 280, 130, 35);
moveRight.setBounds(255, 280, 130, 35);
moveDown.setBounds(185, 335, 130, 35);
board.setEditable(false);
board.setBounds(115, 30, 270, 145);
board.setFont(new Font("Consolas", Font.BOLD, 12));
addActionListeners();
pane.add(board);
pane.add(moveUp);
pane.add(moveRight);
pane.add(moveLeft);
pane.add(moveDown);
}
private void addActionListeners(){
moveUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
running = true;
buttonPress = 1;
}
});
moveDown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPress = 2;
}
});
moveLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPress = 3;
}
});
moveRight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPress = 4;
}
});
}
public void setLabelText(char[][] boardToShow){
board.setText(" ");
for(int i = 0; i < boardToShow.length; i++){
for(int j = 0; j < boardToShow[i].length; j++){
board.append(boardToShow[i][j] + " ");
}
board.append("\n ");
}
}
}
If you require my Board/Monster/Player classes I can post them, but I don't think the problem is with those classes.
Active polling (a.k.a. busy waiting) is when a program checks over and over whether some condition is true, and since we're talking about computers, this is usually done many times a second. It's bad because it means the process is constantly using up CPU to check for this condition, and, even worse, because it uses up so much of the CPU, it can prevent the condition from being able to become true in the first place (this is what is happening in your case).
I'll try to explain this with a metaphor, where your Main class (specifically your while(gui.running) loop) is the boss, and the GUI class is the employee. Imagine the boss comes to his employee every second and asks "Have you done what I asked you to do?". By doing so every second, not only is the boss wasting his time, but is actually preventing his employee from being able to do what he was asked to do.
That is exactly what is happening between your Main and GUI class. The value of buttonPress can not change when the while loop keeps running, and that's why sleeping (and printing to console, because that requires an IO operation which also blocks the thread for a while) makes it work, because the while loop stops executing for a short amount of time, giving your program the chance to change the value of buttonPress.
The solution
In order to solve this, let's go back to the boss/employee metaphor. Instead of checking every second, the boss should say, "When you are done doing this, come and tell me". That way he doesn't need to keep checking on the employee and the employee has time to do the task. Similarly, your GUI class should call a method in your Main class when the actionListeners are fired. Ultimately, as other people pointed out, your structure needs quite a bit of work and clean up, I would recommend you look into using the Model-View-Controller pattern.
However I will propose a solution which will work for the setup you currently have. Your Main class should look something like:
public class Main {
private Player playerOne;
private Monster monstMatt;
private Monster monstJon;
private Monster monstAbaad;
private ShowGUI gui;
private Board gameBoard;
public Main() {
//Add Player
playerOne = new Player(1000, "Player 1");
//Add monsters
monstMatt = new Monster(1000, "Matt");
monstJon = new Monster(1000, "Jon");
monstAbaad = new Monster(1000, "Abaad");
gui = new ShowGUI(this);
gameBoard = new Board();
gui.setLabelText(gameBoard.getBoard());
}
public movePlayerUp() {
movePlayer(0, -1);
}
public movePlayerDown() {
movePlayer(0, 1);
}
public movePlayerLeft() {
movePlayer(-1, 0);
}
public movePlayerRight() {
movePlayer(1, 0);
}
private movePlayer(x, y) {
playerOne.move(playerOne.getX() + x, playerOne.getY() + y);
}
}
And the GUI class:
public class ShowGUI {
private Main main;
public ShowGui(Main main) {
this.main = main;
createAndShow();
System.out.println("GUI Successfully Loaded");
}
private void addActionListeners(){
moveUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
main.movePlayerUp();
}
});
moveDown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
main.movePlayerDown();
}
});
moveLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
main.movePlayerLeft();
}
});
moveRight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
main.movePlayerRight();
}
});
}
/* All the other methods you have */
...
}
So instead of using flags (buttonPress=2), use methods which will be called when a certain action occurs. Again, this is not a perfect long-term solution, but it has the right gist and is the sort of pattern you should follow.

Java Swing Timer Not Clear

I have been having some problems with using the Timer function of Java swing. I am fairly new to programming with Java, so any help is greatly appreciated. I have looked over many other Timer questions on this site but none of them have answered my question. I have made a GUI that allows you to play rock paper scissors, where you can choose from clicking three buttons. I want my program to sleep for around 1 second after you click the button, and again after it displays a message. After I realized Thread.sleep() wouldn't work for my GUI, I tried to implement a timer.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.Border;
import java.io.*;
public class rps {
//ROCK PAPER SCISSORS
static JLabel middle = new JLabel();
static JLabel them = new JLabel();
static JLabel yourWins = new JLabel();
static JLabel theirWins = new JLabel();
static JPanel yourPanel = new JPanel();
static JPanel middlePanel = new JPanel();
static JLabel blank1 = new JLabel();
static JLabel blank2 = new JLabel();
static JButton rock = new JButton("Rock");
static JButton paper = new JButton("Paper");
static JButton scissors = new JButton("Scissors");
static int yw = 0;
static int tw = 0;
static ButtonHandler listener = new ButtonHandler();
public static void main(String[] args) {
//Create the frame
JFrame frame = new JFrame("Rock Paper Scissors");
frame.setSize(500, 500); //Setting the size of the frame
middle.setFont(new Font("Serif", Font.PLAIN, 30));
middle.setHorizontalAlignment(SwingConstants.CENTER);
them.setFont(new Font("Serif", Font.PLAIN, 15));
them.setHorizontalAlignment(SwingConstants.CENTER);
yourWins.setHorizontalAlignment(SwingConstants.CENTER);
theirWins.setHorizontalAlignment(SwingConstants.CENTER);
//Creating panels
JPanel bigPanel = new JPanel();
Border border = BorderFactory.createLineBorder(Color.BLACK, 1);
Border wlb = BorderFactory.createLineBorder(Color.RED, 1);
them.setBorder(border);
yourPanel.setBorder(border);
bigPanel.setBorder(border);
yourWins.setBorder(wlb);
theirWins.setBorder(wlb);
middlePanel.setBorder(border);
//Creating grid layouts
GridLayout yourGrid = new GridLayout(1,3,10,10);
GridLayout theirGrid = new GridLayout(1,1); //One row, one column
GridLayout middleGrid = new GridLayout(5,1);
GridLayout bigGrid = new GridLayout(3,1);//Two rows, one column
//Setting the layouts of each panel to the grid layouts created above
yourPanel.setLayout(yourGrid); //Adding layout to buttons panel
them.setLayout(theirGrid); //Adding layout to label panel
middlePanel.setLayout(middleGrid);
bigPanel.setLayout(bigGrid);
//Adding r/p/s to your grid.
yourPanel.add(rock);
yourPanel.add(paper);
yourPanel.add(scissors);
//Adding w/l rations to middlegrid.
middlePanel.add(theirWins);
middlePanel.add(blank1);
middlePanel.add(middle);
middlePanel.add(blank2);
middlePanel.add(yourWins);
//Attaching the listener to all the buttons
rock.addActionListener(listener);
paper.addActionListener(listener);
scissors.addActionListener(listener);
bigPanel.add(them);
bigPanel.add(middlePanel);
bigPanel.add(yourPanel);
//Shows the score at 0-0.
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
frame.getContentPane().add(bigPanel); //panel to frame
frame.setVisible(true); // Shows frame on screen
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//Class represents what do when a button is pressed
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
Timer timer = new Timer(1000, this);
String tc = random();
them.setText("They chose: " + tc + "!");
if (e.getSource() == rock) {
whoWins("rock", tc);
} else if (e.getSource() == paper) {
whoWins("paper", tc);
} else if (e.getSource() == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
timer.setRepeats(false);
timer.start();
}
}
public static String random() {
int random = (int) (Math.random() * 3);
if (random == 0) {
return "Rock";
} else if (random == 1) {
return "Paper";
} else if (random == 2) {
return "Scissors";
}
return "";
}
public static void whoWins(String yc, String tc) {
if (yc.equals("rock")) {
if (tc.equals("Rock")) {
middle.setText("It's a tie!");
} else if (tc.equals("Paper")) {
middle.setText("You lose!");
tw++;
} else if (tc.equals("Scissors")) {
middle.setText("You win!");
yw++;
}
} else if (yc.equals("paper")) {
if (tc.equals("Rock")) {
middle.setText("You win!");
yw++;
} else if (tc.equals("Paper")) {
middle.setText("It's a tie!");
} else if (tc.equals("Scissors")) {
middle.setText("You lose!");
tw++;
}
} else if (yc.equals("scissors")) {
if (tc.equals("Rock")) {
middle.setText("You lose!");
tw++;
} else if (tc.equals("Paper")) {
middle.setText("You win!");
yw++;
} else if (tc.equals("Scissors")) {
middle.setText("It's a tie!");
}
}
}
}
What is actually happening is there is no delay from when I press the button to a message displaying, because clearly I am not using the timer correctly. I would like the timer to just run once, and after it runs the code will execute. However, when I click a button the timer will run on repeat although setRepeats is false. Therefore, the message I want to display, instead of being delayed, is displayed instantaneously but then goes on a loop and keeps displaying a message (the message is random) until I shut off the program. If I click the button again, it will double the tempo of the timer it seems, and the messages display twice as fast and so on and so forth.
them.setText("They chose: " + tc + "!");
This is the message that is displayed on repeat, with the variable tc changing every time. The timer seems to just be displaying this message every timer interval (1s).
Any help would be greatly appreciated.
EDIT:
So I added this section :
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
// I'd be disabling the buttons here to prevent
// the user from trying to trigger another
// update...
// This is an instance field which is used by your
// listener
Timer timer = new Timer(1000, listenert);
timer.setRepeats(false);
timer.start();
}
}
private static class timer implements ActionListener {
public void actionPerformed (ActionEvent e) {
String tc = random(); //A method that chooses a random word.
them.setText("They chose: " + tc + "!");
if (e.getSource() == rock) {
whoWins("rock", tc); //whoWins is a method that will display a message.
} else if (e.getSource() == paper) {
whoWins("paper", tc);
} else if (e.getSource() == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
// Start another Timer here that waits 1 second
// and re-enables the other buttons...
}
}
so what I believe happens now is when I click a button, the buttonhandler listener starts the timer which is attached to the timer listener (named listenert) which will run the code in the actionPerformed of the timer class. however the sleep function still is not working
EDIT 2.5:
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
final JButton button = (JButton)e.getSource();
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
String tc = random();
them.setText("They chose: " + tc + "!");
if (button == rock) {
whoWins("rock", tc);
} else if (button == paper) {
whoWins("paper", tc);
} else if (button == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
}
});
timer.setRepeats(false);
timer.start();
}
}
that is what I have so far, I just need to add antoher sleep after
them.setText("They chose: " + tc + "!");
where would I put a timer.restart() if any? the timer.start() is at the end of the method which I don't quite understand.
So, the ActionListener you supply to the Timer is notified when the timer "ticks", so you ButtonHandler actionPerformed should look more like...
public void actionPerformed (ActionEvent e) {
// I'd be disabling the buttons here to prevent
// the user from trying to trigger another
// update...
// This is an instance field which is used by your
// listener
choice = e.getSource();
Timer timer = new Timer(1000, listener);
timer.setRepeats(false);
timer.start();
}
And your listener should look more like
public void actionPerformed (ActionEvent e) {
String tc = random(); //A method that chooses a random word.
them.setText("They chose: " + tc + "!");
if (choice == rock) {
whoWins("rock", tc); //whoWins is a method that will display a message.
} else if (choice == paper) {
whoWins("paper", tc);
} else if (choice == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
// Start another Timer here that waits 1 second
// and re-enables the other buttons...
}
For example...
You may consider taking a look at How to use Swing Timers for more details
Updated
Start with a simple example...
public class TestPane extends JPanel {
private JLabel label;
private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel();
add(label);
tick();
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tick();
}
});
timer.start();
}
protected void tick() {
label.setText(sdf.format(new Date()));
}
}
This just calls the tick method every half second to update the time on the JLabel...
firstly import the following ;
import java.awt.event.ActionEvent ;
import java.awt.event.ActionListener ;
import javax.swing.Timer ;
then initialize the timer at the end of the form like this ;
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new mainprogramme().setVisible(true);
}
});
}
private Timer timer ;
then after initializing the timer add a public class like following;
public class progress implements ActionListener {
public void actionPerformed(ActionEvent evt){
int n = 0 ;
if (n<100){
n++ ;
System.out.println(n) ;
}else{
timer.stop() ;
}
}
}
after you do this go to the j Frame>right click and select>Events>window>window Opened and type the following ;
private void formWindowOpened(java.awt.event.WindowEvent evt) {
timer = new Timer(100,new progress()) ;
and after you do all this take a button name it as anything and type the following in its void like following ;
timer.start();
AND THAT'S IT CODE IT AND THEN REPLY ME...

Categories