The game I am building involves switching panels after the start button is clicked when startGame() is called. The program freezes once the button is clicked and does nothing.
Here is code snippet:
public class ArtilleryGame extends JFrame {
private static final long serialVersionUID = 1L;
//TODO: fix clouds from updating with background
static StartPanel startPanel = new StartPanel();
public ArtilleryGame() throws InterruptedException
{
setSize(898,685);
setLocationRelativeTo(null);
setTitle("Tank Game");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
URL sound = this.getClass().getResource("Sounds/Intro_Screen.wav");
AudioClip drop = Applet.newAudioClip(sound);
drop.loop();
drop.play();
add(startPanel);
//add(new GamePanel());
buttons();
setVisible(true);
}
private void buttons()
{
URL startURL = this.getClass().getResource("imgg/StartBtn.png");
BufferedImage startI = new BufferedImage(170, 62, BufferedImage.TYPE_INT_RGB);
try
{
startI = ImageIO.read(startURL);
} catch (IOException e)
{
e.printStackTrace();
}
ImageIcon startImg = new ImageIcon(startI);
JButton startBtn = new JButton(startImg);
startBtn.setSize(170, 62);
startBtn.setBorder(BorderFactory.createEmptyBorder());
startBtn.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
startGame();
}
});
startBtn.setLocation(365, 310);
StartPanel.background.add(startBtn);
}
public void startGame()
{
remove(startPanel);
add(new GamePanel());
}
public static void displayCredits()
{
JOptionPane.showMessageDialog(null, new CreditsPanel(), "Tank Game", JOptionPane.PLAIN_MESSAGE);
}
public static void main(String[] args) throws InterruptedException
{
new ArtilleryGame();
//displayCredits();
}
}
Use a CardLayout. The CardLayout allows you to easily swap panels.
Read the section from the Swing tutorial on How to Use CardLayout for more information and working examples.
Related
I need to use a thread to change the position of my JLabel (movingDisplay) every second when I click on my button (btnDisplay) and for the thread to stop when I click on my other button (btnDStop). I have a class called MoveDisplay that implements Runnable and does this action when I click on btnDisplay. After MoveDisplay has randomized x and y for my JLabel, it's supposed to send x and y back to my main class where it updates the position of the JLabel. I have a method in my mainclass to update the JLabel position however I get a NullPointerException when trying to do so. In fact it doesn't work changing any component at all from MoveDisplay class.
public class Main {
public static void main(String[] args) {
GUIFrame test = new GUIFrame();
}
}
MoveDisplay class:
public class MoveDisplay implements Runnable {
private GUIFrame gui;
private boolean moving = true;
private Thread thread;
public void run() {
gui = new GUIFrame();
if (moving) {
Random rand = new Random();
while (moving) {
int x = rand.nextInt(150) + 1;
int y = rand.nextInt(150) + 1;
gui.moveDisplay(x, y, 100, 100);
try {
thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
}
public void start() {
thread = new Thread(new MoveDisplay());
thread.start();
}
public void stop() {
thread.interrupt();
System.out.println("Stopped");
}
}
GUIFrame class:
public class GUIFrame {
private JFrame frame; // The Main window
private JLabel movingDisplay;
private boolean playing = true;
private boolean moving = true;
private MoveDisplay moveDisplay = new MoveDisplay();
/**
* Starts the application
*/
public void Start() {
frame = new JFrame();
frame.setBounds(0, 0, 494, 437);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setTitle("Multiple Thread Demonstrator");
InitializeGUI(); // Fill in components
frame.setVisible(true);
frame.setResizable(false); // Prevent user from change size
frame.setLocationRelativeTo(null); // Start middle screen
}
public void InitializeGUI() {
// The moving display outer panel
JPanel pnlDisplay = new JPanel();
Border b2 = BorderFactory.createTitledBorder("Display Thread");
pnlDisplay.setBorder(b2);
pnlDisplay.setBounds(12, 118, 222, 269);
pnlDisplay.setLayout(null);
// Add buttons and drawing panel to this panel
btnDisplay = new JButton("Start Display");
btnDisplay.setBounds(10, 226, 121, 23);
pnlDisplay.add(btnDisplay);
btnDStop = new JButton("Stop");
btnDStop.setBounds(135, 226, 75, 23);
pnlDisplay.add(btnDStop);
pnlMove = new JPanel();
pnlMove.setBounds(10, 19, 200, 200);
Border b21 = BorderFactory.createLineBorder(Color.black);
pnlMove.setBorder(b21);
pnlDisplay.add(pnlMove);
// Then add this to main window
frame.add(pnlDisplay);
movingDisplay = new JLabel("DisplayThread");
pnlMove.add(movingDisplay);
btnDStop.setEnabled(false);
btnDisplay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = true;
btnDisplay.setEnabled(false);
btnDStop.setEnabled(true);
startMoveDisplay();
}
});
btnDStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = false;
btnDisplay.setEnabled(true);
btnDStop.setEnabled(false);
startMoveDisplay();
}
});
}
public void startMoveDisplay() {
if(moving) {
moveDisplay.start();
}
else {
moveDisplay.stop();
}
}
public void moveDisplay(int x, int y, int a, int b) {
movingDisplay.setBounds(10,10,150,150);
}
}
I've checked the code and in the MoveDisplay.run() you were creating a new frame, but in it's constructor the panel wasn't initialized, which triggered the NPE. Because of this I've refactored the GUIFrame constructor to initialeze all components (invoked the Start() method) and removed the new frame's initialization from the run method. Here are the modified classed
public class MoveDisplay {
private GUIFrame gui;
private volatile boolean moving;
public MoveDisplay(GUIFrame gui) {
this.gui = gui;
}
public void start() {
moving = true;
Random rand = new Random();
while (moving) {
int x = rand.nextInt(150) + 1;
int y = rand.nextInt(150) + 1;
gui.moveDisplay(x, y, 100, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop() {
moving = false;
}
}
And here is the new frame class
public class GUIFrame {
private JFrame frame; // The Main window
private JLabel movingDisplay;
private boolean playing = true;
private boolean moving = true;
private MoveDisplay moveDisplay;
public GUIFrame() {
Start();
}
/**
* Starts the application
*/
private void Start() {
frame = new JFrame();
frame.setBounds(0, 0, 494, 437);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setTitle("Multiple Thread Demonstrator");
InitializeGUI(); // Fill in components
frame.setVisible(true);
frame.setResizable(false); // Prevent user from change size
frame.setLocationRelativeTo(null); // Start middle screen
moveDisplay = new MoveDisplay(this);
}
public void InitializeGUI() {
// The moving display outer panel
JPanel pnlDisplay = new JPanel();
Border b2 = BorderFactory.createTitledBorder("Display Thread");
pnlDisplay.setBorder(b2);
pnlDisplay.setBounds(12, 118, 222, 269);
pnlDisplay.setLayout(null);
// Add buttons and drawing panel to this panel
JButton btnDisplay = new JButton("Start Display");
btnDisplay.setBounds(10, 226, 121, 23);
pnlDisplay.add(btnDisplay);
JButton btnDStop = new JButton("Stop");
btnDStop.setBounds(135, 226, 75, 23);
pnlDisplay.add(btnDStop);
JPanel pnlMove = new JPanel();
pnlMove.setBounds(10, 19, 200, 200);
Border b21 = BorderFactory.createLineBorder(Color.black);
pnlMove.setBorder(b21);
pnlDisplay.add(pnlMove);
// Then add this to main window
frame.add(pnlDisplay);
movingDisplay = new JLabel("DisplayThread");
pnlMove.add(movingDisplay);
btnDStop.setEnabled(false);
btnDisplay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = true;
btnDisplay.setEnabled(false);
btnDStop.setEnabled(true);
startMoveDisplay();
}
});
btnDStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
moving = false;
btnDisplay.setEnabled(true);
btnDStop.setEnabled(false);
startMoveDisplay();
}
});
}
public void startMoveDisplay() {
if(moving) {
new Thread(new Runnable() {
#Override
public void run() {
moveDisplay.start();
}
}).start();
} else {
moveDisplay.stop();
}
}
public void moveDisplay(int x, int y, int a, int b) {
movingDisplay.setBounds(x, y, a, b);
}
}
You have to get a reference to the existing GUIFrame instance instead of creating a new one, try this:
MoveDisplay
public class MoveDisplay implements Runnable {
private GUIFrame gui;
Random rand = new Random();
volatile boolean moving;
public MoveDispaly(GUIFrame gui){
this.gui = gui;
}
public void run() {
while (moving) {
int x = rand.nextInt(150) + 1;
int y = rand.nextInt(150) + 1;
try {
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
gui.moveDisplay(x, y, 100, 100);
}
});
thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
}
public void start() {
moving = true;
thread = new Thread(new MoveDisplay());
thread.start();
}
public void stop() {
moving = false;
}
}
GUIFrame
public class GUIFrame{
MoveDisplay moveDisplay = new MoveDisplay(this);
...
}
Also, you have to run the part of the code that changes the GUI on the EDT thread.
Is not a good idea to stop a thread by interrupting it, you can stop it by setting the moving variable to false.
Maybe you can also use the Singleton Pattern to get the original instance of GUIFrame:
public static class instanceClassA {
private static instanceClassA = null;
public static instanceClassA(){
if(instance == null){
instance = instanceClassA();
}
return instance;
}
}
How do I break a while loop if I click on my jframe shutdown? I 'm making a clicker that needs to be stopped at some point, but it'll just continue clicking even tho the exit has been pressed.
public class ClickWindow {
private JFrame frame;
private static Clicker click;
private static long currTime;
private static long totalTime;
private JTextField textField;
private static int textFieldValue = 0;
private static Boolean Bool = true;
/**
* Launch the application.
*/
public static void main(String[] args) throws InterruptedException {
click = new Clicker();
ClickWindow window = new ClickWindow();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClickWindow() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setBounds(100, 100, 289, 90);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btnNewButton_1 = new JButton("Press Space");
btnNewButton_1.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
Bool = false;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
if(textFieldValue == 0){
textFieldValue = 250;
}
try {
while (Bool) {
click.click();
textFieldValue = Integer.parseInt(textField.getText());
Thread.sleep(textFieldValue);
}
} catch (AWTException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
});
btnNewButton_1.setBounds(10, 25, 110, 23);
frame.getContentPane().add(btnNewButton_1);
textField = new JTextField();
textField.setBounds(127, 25, 141, 23);
frame.getContentPane().add(textField);
textField.setColumns(10);
}
public void windowClosing(WindowEvent event) {
Bool = false;
}
}
Clicker class
public class Clicker{
public static void click() throws AWTException{
Robot bot = new Robot();
bot.mousePress(InputEvent.BUTTON1_MASK);
bot.mouseRelease(InputEvent.BUTTON1_MASK);
}
}
Edited with the full code.
You should define the defaultCloseOperation for your JFrame:
JFrame myFrame = new JFrame("MyFrame");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
If you set the defaultCloseOperation, hitting the close button will trigger a call to System exit:
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
JFrame myFrame = new JFrame("MyFrame");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//...add components here
myFrame.pack();
myFrame.setVisible(true);
}
catch (Exception e)
{
System.exit(-1);
}
}
});
}
If you want to shutdown the entire application you can just do this:
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This will shutdown your application after the Jframe was closed.
You can also call System.exit(0) in your windowClosing method or whenever you want to shutdown your application
instead of adding the keyListener to your JButton try having your JFrame, i.e. ClickWindow implement it. I think this would work.
i have a fun project where i need to change the content of a text area inside a iteration.
Its a character, a "projectile", moving trought a string. The string is updated and sent to the textArea inside the iteration, and the iteration stops when the character reaches a wall.
But my textArea only updates (visually) when i leave the iteration. While im inside it, textArea freezes, as if its waiting for the iteration, even with Thread.sleep() inside it.
I made an MVCE exemplifing the problem bellow, notice the text only shows after the iteration, i want it to apper in every step of the while.
public class GUIProblem extends JFrame{
public GUIProblem() {
setSize(640, 480);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.CENTER);
final JTextArea textArea = new JTextArea();
textArea.setRows(10);
textArea.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
int i = 0;
while(i < 10){
textArea.setText("this text only appears after the iteration, i want it to appear in each step of the iteration!");
System.out.println("iterating..." + i++);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
textArea.setColumns(30);
panel.add(textArea);
}
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GUIProblem gui = new GUIProblem( );
gui.setVisible(true);
}
});
JOptionPane.showMessageDialog(null, "Click the textArea!");
}
}
You've a classic Swing threading issue where you stop the Swing event thread in its tracks with your iteration and its Thread.sleep() calls. The solution is the same as for similar questions: use a Swing Timer or background thread such as a SwingWorker. In your case, use the Timer.
For example, since you posted an MCVE
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUIProblem extends JFrame {
public GUIProblem() {
// setSize(640, 480);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.CENTER);
final JTextArea textArea = new JTextArea(20, 50);
textArea.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mEvt) {
int i = 0;
int timerDelay = 200;
new Timer(timerDelay, new ActionListener() {
int count = 0;
private final int MAX_COUNT = 10;
#Override
public void actionPerformed(ActionEvent e) {
if (count >= MAX_COUNT) {
((Timer) e.getSource()).stop(); // stop the timer
return;
}
textArea.append("Count is: " + count + "\n");
count++;
}
}).start();
}
});
panel.add(new JScrollPane(textArea));
}
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GUIProblem gui = new GUIProblem();
gui.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
gui.pack();
gui.setLocationRelativeTo(null);
gui.setVisible(true);
}
});
JOptionPane.showMessageDialog(null, "Click the textArea!");
}
}
I keep getting a stack overflow error when I run this short program I made! please help! Right now all it's supposed to do is take the users input and print their position (in X and Y coordinates). I'm not sure what Stack overflow error is or how to fix it.
import java.awt.*;
import javax.swing.*;
public class ExplorerPanel extends JFrame {
ExplorerEvent prog = new ExplorerEvent(this);
JTextArea dataa = new JTextArea(15, 20);
JTextField datain = new JTextField(20);
JButton submit = new JButton("Submit");
JTextField errors = new JTextField(30);
public ExplorerPanel() {
super("Explorer RPG");
setLookAndFeel();
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_…
BorderLayout bord = new BorderLayout();
setLayout(bord);
JPanel toppanel = new JPanel();
toppanel.add(dataa);
add(toppanel, BorderLayout.NORTH);
JPanel middlepanel = new JPanel();
middlepanel.add(datain);
middlepanel.add(submit);
add(middlepanel, BorderLayout.CENTER);
JPanel bottompanel = new JPanel();
bottompanel.add(errors);
add(bottompanel, BorderLayout.SOUTH);
dataa.setEditable(false);
errors.setEditable(false);
submit.addActionListener(prog);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLo…
);
} catch (Exception exc) {
// ignore error
}
}
public static void main(String[] args) {
ExplorerPanel frame = new ExplorerPanel();
}
}
public class ExplorerEvent implements ActionListener, Runnable {
ExplorerPanel gui;
Thread playing;
String command;
String gamedata;
ExplorerGame game = new ExplorerGame();
public ExplorerEvent(ExplorerPanel in) {
gui = in;
}
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals("Submit")) {
startPlaying();
}
}
void startPlaying() {
playing = new Thread(this);
playing.start();
}
void stopPlaying() {
playing = (null);
}
void clearAllFields() {
gui.dataa.setText("");
}
public void run() {
Thread thisThread = Thread.currentThread();
while (playing == thisThread) {
// Game code
game.Game();
}
}
}
public class ExplorerGame {
ExplorerPanel gui = new ExplorerPanel();
String command;
int x = 1;
int y = 1;
public void Game() {
command = gui.submit.getText().toLowerCase();
if (command.equals("east")) {x--;}
else if (command.equals("south")) {y--;}
else if (command.equals("west")) {x++;}
else if (command.equals("north")) {y++;}
System.out.println(x + y);
}
}
In ExplorerGame, you have declared: -
ExplorerPanel gui = new ExplorerPanel();
then, in ExplorerPanel: -
ExplorerEvent prog = new ExplorerEvent(this);
and then again, in ExplorerEvent: -
ExplorerGame game = new ExplorerGame();
This will fill the Stack with recursive creation of objects.
ExplorerGame -> ExplorerPanel -> ExplorerEvent --+
^ |
|____________________________________________|
You want to solve the Issue?
I'll Suggest you: -
Throw away the code, and re-design your application. Having a cyclic dependency in your application is a big loop hole, showing a very poor design.
I'm trying to capture the screen without including my application's window. To do this I first call setVisible(false), then I call the createScreenCapture method, and finally I call setVisible(true). This isn't working however and I'm still getting my applications window in the screen capture. If I add a call to sleep this seems to resolve the issue, but I know this is bad practice. What is the right way to do this?
Code:
setVisible(false);
BufferedImage screen = robot.createScreenCapture(rectScreenSize);
setVisible(true);
Have you tried to use SwingUtilities.invokeLater() and run the capture inside of the runnable passed as an argument? My guess is that the repaint performed to remove your application is performed right after the end of the current event in the AWT-EventQueue and thus invoking the call immediately still captures your window. Invoking the createCapture in a delayed event through invokeLater should fix this.
you have to delay this action by implements Swing Timer, for example
import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
public class CaptureScreen implements ActionListener {
private JFrame f = new JFrame("Screen Capture");
private JPanel pane = new JPanel();
private JButton capture = new JButton("Capture");
private JDialog d = new JDialog();
private JScrollPane scrollPane = new JScrollPane();
private JLabel l = new JLabel();
private Point location;
private Timer timer1;
public CaptureScreen() {
capture.setActionCommand("CaptureScreen");
capture.setFocusPainted(false);
capture.addActionListener(this);
capture.setPreferredSize(new Dimension(300, 50));
pane.add(capture);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(pane);
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
createPicContainer();
startTimer();
}
private void createPicContainer() {
l.setPreferredSize(new Dimension(700, 500));
scrollPane = new JScrollPane(l,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBackground(Color.white);
scrollPane.getViewport().setBackground(Color.white);
d.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
d.add(scrollPane);
d.pack();
d.setVisible(false);
d.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
f.setVisible(true);
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
});
}
private void startTimer() {
timer1 = new Timer(1000, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
capture.doClick();
f.setVisible(false);
}
});
}
});
timer1.setDelay(500);
timer1.setRepeats(false);
timer1.start();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("CaptureScreen")) {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // gets the screen size
Robot r;
BufferedImage bI;
try {
r = new Robot(); // creates robot not sure exactly how it works
Thread.sleep(1000); // waits 1 second before capture
bI = r.createScreenCapture(new Rectangle(dim)); // tells robot to capture the screen
showPic(bI);
saveImage(bI);
} catch (AWTException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
e2.printStackTrace();
}
}
}
private void saveImage(BufferedImage bI) {
try {
ImageIO.write(bI, "JPG", new File("screenShot.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
private void showPic(BufferedImage bI) {
ImageIcon pic = new ImageIcon(bI);
l.setIcon(pic);
l.revalidate();
l.repaint();
d.setVisible(false);
//location = f.getLocationOnScreen();
//int x = location.x;
//int y = location.y;
//d.setLocation(x, y + f.getHeight());
d.setLocation(150, 150);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
d.setVisible(true);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CaptureScreen cs = new CaptureScreen();
}
});
}
}