Currently this is my code
package com.raggaer.frame;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Frame {
private JFrame frame;
public Frame() {
this.frame = new JFrame("Java Snake");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.add(new Panel());
Paint game = new Paint();
this.frame.setResizable(false);
this.frame.pack();
this.frame.setVisible(true);
}
}
And this is my paint class
package com.raggaer.frame;
public class Paint implements Runnable {
private Thread thread;
public Paint() {
thread = new Thread(this);
thread.start();
}
public void run() {
System.out.println("aaa");
}
}
But the System.out.println("aaa"); is just executing one time instead of forever.. what Im doing wrong?
You'll have to loop in the run() method if you want it to run forever. Otherwise the thread finishes execution and exits.
Try This :
public void run()
{
while(true)
System.out.println("aaa");
}
When the run() method returns/ends the thread will be terminated. If you want the thread to continue 'forever' you can use while(true) or recall the run() method inside the run() method.
Related
[Technically not a [Duplicate]] I know this has happened before (There is a bug where my JFrame will not open when I compile my game, how do I fix this [duplicate]) and MadProgrammer answered:"Game.main isn't doing anything. Since its the main entry point for the program, it will need to do something before something can happen" but now that Game.main does something I don't see the answer.
I tried recompiling and checking for errors, none, someone else even got it to work. How can I fix this
Game.java:
package com.hypopixel;
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Game extends Canvas implements Runnable {
public static final long serialVersionUID = 1L;
private Thread thread;
private Boolean running = false;
public Game() {
new Window(800, 600, this);
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
} catch(Exception e) {
e.printStackTrace();
}
}
public void run() {
}
public static void main(String[] args) {
new Game();
}
}
Window.java:
package com.hypopixel;
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Window extends Canvas {
public static int BlockSizing = 4;
public static final long serialVersionUID = 1L;
public Window(int Wwidth, int Wheight, Game game) {
JFrame Window = new JFrame();
setPreferredSize(new Dimension(Wwidth, Wheight));
setMinimumSize(new Dimension(800, 600));
Window.add(game);
Window.pack();
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Window.setTitle("HypoPixel");
Window.setLocationRelativeTo(null);
Window.setVisible(true);
game.start();
}
}
/*
Credits:
Just another Java Programmer
MadProgrammer
*/
manifest.txt is the same
I expected the JFrame to open (Cuase someone else was able to got it) and it would not open.
So, there's a number of things which are "off"
Starting with...
public Window(int Wwidth, int Wheight, Game game) {
JFrame Window = new JFrame();
setPreferredSize(new Dimension(Wwidth, Wheight));
setMinimumSize(new Dimension(800, 600));
Window.add(game);
Window.pack();
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Window.setTitle("HypoPixel");
Window.setLocationRelativeTo(null);
Window.setVisible(true);
game.start();
}
Apart from the fact that there is already a class called Window in java.awt, which is confusing, you use the variable name Window, which is more confusing.
Window extends from Canvas, but you never actually use it. Calling setPreferredSize and setMinimumSize because Window is never actually added to anything and it's commonly recommend against doing so, favouring instead to override these methods, so as to prevent accidentally changing their values.
From Game, you call Window ... it's kind of weird way to be doing things, as it's not really Games responsibility to be making the window, rather, it's the other way around.
Personally, I'd start with a dedicated entry point, whose responsibility is to load and prepare the environment and show the first screen, for example...
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Make sure that the manufest.mf so that it's Main-Class property points to this class.
I'd also update Game, so it overrides getPreferredSize. I'd also take a look at your start and stop methods.
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
What happens if this is called twice? You should be checking the state of the Thread before creating a new one
public synchronized void stop() {
try {
thread.join();
running = false;
} catch(Exception e) {
e.printStackTrace();
}
}
This isn't going to do anything, as join is blocking, so the state of running will never change.
Also, because of Java's memory model, you may find that even setting running to false before calling join doesn't work. Instead, you should be using an atomic variable (and using Boolean is probably going to cause a bunch of other issues, as you're referencing the memory location and not the actual value)
I would recommend having a read through Concurrency
import java.awt.Canvas;
import java.awt.Dimension;
import java.util.concurrent.atomic.AtomicBoolean;
public class Game extends Canvas implements Runnable {
public static final long serialVersionUID = 1L;
private Thread thread;
private AtomicBoolean running = new AtomicBoolean(false);
public Game() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
public synchronized void start() {
running.set(true);
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public synchronized void stop() {
running.set(false);
if (thread == null) {
return;
}
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
}
}
the IDE I use (NetBeans) will not let me run the java file
From the "Projects" tab, select the Main class/Java File, right click and select "Run File"
Alternatively, with Main open in the editor (and selected), press Shift+F6
Next, make sure com.hypopixel.Main is set as the projects "main class"
Right click the project node in the "Projects" tab and select "Properties"
Select "Run" from the options down the right side, verify that "Main Class" is set as com.hypopixel.Main, if not, click Browse... and select it from the available options
I am trying to control a while loop in my program to stop and start based on a user input. I have attempted this with a button and the "start" part of it works but then the code goes into an infinite loop which I cant stop without manually terminating it. The following is all my code:
Header Class
package test;
import javax.swing.JFrame;
public class headerClass {
public static void main (String[] args){
frameClass frame = new frameClass();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(150,75);
frame.setVisible(true);
}
}
Frame Class
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class frameClass extends JFrame {
private JButton click;
public frameClass(){
setLayout(new FlowLayout());
click = new JButton("Stop Loop");
add(click);
thehandler handler = new thehandler();
click.addActionListener(handler);
}
private class thehandler implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource()==click){
looper loop = new looper();
looper.buttonSet = !looper.buttonSet;
}
}
}
}
Looping class
package test;
public class looper {
public static boolean buttonSet;
public looper(){
while (buttonSet==false){
System.out.println("aaa");
}
}
}
How do I fix this and stop if from going into the infinite loop please?
Swing is a single threaded framework, this means that while the loop is running, the Event Dispatching Thread is been blocked and can't process new events, including repaint requests...
You need to start your Looper class inside it's own thread context. This would also mean that your loop flag would need to be declared volatile or you should use an AtomicBoolean so that state can be inspected and modified across thread boundaries
For example...
public class Looper implements Runnable {
private AtomicBoolean keepRunning;
public Looper() {
keepRunning = new AtomicBoolean(true);
}
public void stop() {
keepRunning.set(false);
}
#Override
public void run() {
while (keepRunning.get()) {
System.out.println("aaa");
}
}
}
Then you might be able to use something like...
private class thehandler implements ActionListener {
private Looper looper;
public void actionPerformed(ActionEvent e) {
if (e.getSource() == click) {
if (looper == null) {
looper = new Looper();
Thread t = new Thread(looper);
t.start();
} else {
looper.stop();
looper = null;
}
}
}
}
to run it...
Take a look at Concurrency in Swing and Concurrency in Java for some more details
Also beware, Swing is not thread safe, you should never create or modify the UI from out side the context of the EDT
The problem is you start an infinite loop and try to terminate it in the same thread. That doesn't work because the VM executes one task in a thread after another. It would execute the command to stop the looper directly after the loop is finished but an infinite loop never finishes. So it cannot be stopped like this.
You need to create a second Thread for the looper. This way you can stop it from your main thread.
I have problems with Java's Multi-Threading feature, so hopefully somebody can help me....
Here is my problem:
In the JPanel ExamplePanel which is located in the JFrame ExampleFrame I've added a ComponentListener which invokes the startPaint()-Method. This method should work in a new Thread. My Problem is that by resizing the window "former" Threads aren't closed, meanwhile new Threads are added....
So is there a way to resize the JPanel and to close at the same time the "old" threads, so that the number of threads is not growing, when I resize the JPanel?
I have tried something with a boolean exiter-variable, but it do not seemed to work...
here is the code:
package example;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Example2 {
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new ExampleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class ExampleFrame extends JFrame {
private static final long serialVersionUID = 1L;
ExamplePanel examplePanel = new ExamplePanel();
private Thread t=null;
private class ExamplePanel extends JPanel implements ComponentListener {
private static final long serialVersionUID = 1L;
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentResized(ComponentEvent e) {
startPaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
private void startPaint() {
t=new Thread(new Runnable() {
#Override
public void run() {
//System.out.println(Thread.currentThread().getName());
while (true) {
//System.out.println(Thread.activeCount());
}
}
});
t.start();
}
}
public ExampleFrame() {
examplePanel.addComponentListener((ComponentListener) examplePanel);
getContentPane().add(examplePanel);
}
}
if the calculations don't take long don't use an extra Thread.
if you need this extra Thread make sure that it doesn't run forever (no while (true) without returning at some point)
you can always interrupt your running Thread bfore creating the new one
if (t != null && t.isAlive()) {
t.interrupt();
}
and check in the while(true) loop if the Thread is interrupted
if (t.isInterrupted()) {
System.out.println("Thread ended");
return;
}
hope this helps
I want to make a simple space shooter game but it is not working well at the start. How it will be its end? Something is going wrong with my code. The overridden run() method of the Runnable interface is not working. Why the run method is not working as it should? Moreover any information about how to shoot more independent bullets. Here is my code. Thanks in advance.
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
public class GameWindow extends JFrame implements Runnable {
static final int WIDTH = 500;
static final int HEIGHT = 500;
static final String title = "East Game Development";
private boolean running = false;
private Thread thread;
GameWindow() {
setSize(new Dimension(WIDTH, HEIGHT));
getContentPane().setBackground(Color.BLACK);
setMaximumSize(new Dimension(WIDTH, HEIGHT));
setMinimumSize(new Dimension(WIDTH, HEIGHT));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle(title);
setResizable(false);
setVisible(true);
}
private synchronized void start() {
System.out.println("Debugging start method");
if (running) {
return;
}
running = true;
thread = new Thread();
thread.start();
}
private synchronized void stop() {
if (!running) {
return;
}
running = false;
try {
thread.join();
} catch (Exception ex) {
}
System.exit(1);
}
#Override
public void run() {
System.out.println("Debugging");
while (running) {
System.out.println("Working well...");
}
stop();
}
public static void main(String[] args) {
GameWindow gw = new GameWindow();
gw.start();
}
}
thread = new Thread();
thread.start();
You're creating a thread without passing it anything to run. The Thread constructor expects a Runnable as argument, and this runnable is what will be executed in the thread. You thus want
thread = new Thread(this);
thread.start();
Note, though, that your code is not thread-safe: the run() method reads the value of the running variable without synchonization. And it might thus see it as true aven if the stop() method has been called in another thread. You should use the stanard interruption mechanism to ask your thread to stop, and to check if the thread must continue to run:
public void stop() {
thread.interrupt();
}
public void run() {
while (!Thread.currentThread.isInterrupted()) {
...
}
}
When you create a thread, you should specify which runnable instance it will call run. In your case:
thread = new Thread(this);
thread.start();
thread = new Thread();
You are creating normal Thread and starting it. Why do you expect your run() method to run?
private synchronized void start() {
System.out.println("Debugging start method");
if (running) {
return;
}
running = true;
thread = new Thread(this);
thread.start();
}
if u have only JFrame no really need to make it a runnable. just use these in main method:
gw.setVisible(true);
gw.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I want to cause the "main thread" (the thread started which runs main()) to do some work from the actionPerformed() method of a button's ActionListener, but I do not know how to achieve this.
A little more context:
I am currently programming a 2D game using Swing (a flavour of Tetris).
When the application starts, a window opens which displays the main menu of the game.
The user is presented several possibilities, one of them is to start the game by pushing a "Start" button, which causes the game panel to be displayed and triggers the main loop of the game.
To be able to switch between the two panels (that of the main menu and that of the game), I am using a CardLayout manager, then I can display one panel by calling show().
The idea is that I would like my start button to have a listener that looks like this:
public class StartListener implements ActionListener {
StartListener() {}
public void actionPerformed(ActionEvent e) {
displayGamePanel();
startGame();
}
}
but this does not work because actionPerformed() is called from the event-dispatch thread, so the call to startGame() (which triggers the main loop: game logic update + repaint() call at each frame) blocks the whole thread.
The way I am handling this right now is that actionPerformed() just changes a boolean flag value: public void actionPerformed(ActionEvent e) {
startPushed = true;
}
which is then eventually checked by the main thread:
while (true) {
while (!g.startPushed) {
try {
Thread.sleep(100);
} catch (Exception e) {}
}
g.startPushed = false;
g.startGame();
}
But I find this solution to be very inelegant.
I have read the Concurrency in Swing lesson but I am still confused (should I implement a Worker Thread – isn't that a little overkill?). I haven't done any actual multithreading work yet so I am a little lost.
Isn't there a way to tell the main thread (which would be sleeping indefinitely, waiting for a user action) "ok, wake up now and do this (display the game panel and start the game)"?.
Thanks for your help.
EDIT:
Just to be clear, this is what my game loop looks like:
long lastLoopTime = System.currentTimeMillis();
long dTime;
int delay = 10;
while (running) {
// compute the time that has gone since the last frame
dTime = System.currentTimeMillis() - lastLoopTime;
lastLoopTime = System.currentTimeMillis();
// UPDATE STATE
updateState(dTime);
//...
// UPDATE GRAPHICS
// thread-safe: repaint() will run on the EDT
frame.repaint()
// Pause for a bit
try {
Thread.sleep(delay);
} catch (Exception e) {}
}
This doesn't make sense:
but this does not work because actionPerformed() is called from the event-dispatch thread, so the call to startGame() (which triggers the main loop: game logic update + repaint() call at each frame) blocks the whole thread.
Since your game loop should not block the EDT. Are you using a Swing Timer or a background thread for your game loop? If not, do so.
Regarding:
while (true) {
while (!g.startPushed) {
try {
Thread.sleep(100);
} catch (Exception e) {}
}
g.startPushed = false;
g.startGame();
}
Don't do this either, but instead use listeners for this sort of thing.
e.g.,
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class GameState extends JPanel {
private CardLayout cardlayout = new CardLayout();
private GamePanel gamePanel = new GamePanel();
private StartPanel startpanel = new StartPanel(this, gamePanel);
public GameState() {
setLayout(cardlayout);
add(startpanel, StartPanel.DISPLAY_STRING);
add(gamePanel, GamePanel.DISPLAY_STRING);
}
public void showComponent(String displayString) {
cardlayout.show(this, displayString);
}
private static void createAndShowGui() {
GameState mainPanel = new GameState();
JFrame frame = new JFrame("GameState");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class StartPanel extends JPanel {
public static final String DISPLAY_STRING = "Start Panel";
public StartPanel(final GameState gameState, final GamePanel gamePanel) {
add(new JButton(new AbstractAction("Start") {
#Override
public void actionPerformed(ActionEvent e) {
gameState.showComponent(GamePanel.DISPLAY_STRING);
gamePanel.startAnimation();
}
}));
}
}
class GamePanel extends JPanel {
public static final String DISPLAY_STRING = "Game Panel";
private static final int PREF_W = 500;
private static final int PREF_H = 400;
private static final int RECT_WIDTH = 10;
private int x;
private int y;
public void startAnimation() {
x = 0;
y = 0;
int timerDelay = 10;
new Timer(timerDelay , new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
repaint();
}
}).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(x, y, RECT_WIDTH, RECT_WIDTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
you should be using a SwingWorker this will execute the code in doInBackground() in a background thread and the code in done() in the EDT after doInBackground() stops
The easiest way: use a CountDownLatch. You set it to 1, make it available in the Swing code by any means appropriate, and in the main thread you await it.
You can consider showing a modal dialog with the game panel using SwingUtilities.invokeAndWait() so that when the dialog is closed the control returns back to main thread.
You can make all code except the EDT run on single thread execution service and then just post runnables whenever you need some code executed.