How to put two different tasks in Threads - java

I have following code. in this code i have an image which moves from left to right and a button which has an event. but i want to put these both tasks in Threads. so that it can work properly. the problem with this code is that button event does not work until it reaches to the right most point.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyImage extends JFrame implements ActionListener
{
static int xPixel = 20;
Image myImage, offScreenImage;
Graphics offScreenGraphics;
JPanel p = new JPanel();
Button btn = new Button("bun");
JFrame f = new JFrame();
public MyImage()
{
myImage = Toolkit.getDefaultToolkit().getImage("mywineshoplogo.jpg");
setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
add(p);
p.add(btn);
moveImage();
btn.addActionListener(this);
}
public void update(Graphics g)
{
paint(g);
}
public void paint(Graphics g)
{
int width = getWidth();
int height = getHeight();
if (offScreenImage == null)
{
offScreenImage = createImage(width, height);
offScreenGraphics = offScreenImage.getGraphics();
}
// clear the off screen image
offScreenGraphics.clearRect(0, 0, width + 1, height + 1);
// draw your image off screen
offScreenGraphics.drawImage(myImage, xPixel, 10, this);
// draw your image off screen
// show the off screen image
g.drawImage(offScreenImage, 0, 0, this);
// show the off screen image
}
void moveImage() //left to right move
{
Thread hilo = new Thread() {
public void run() {
try {
for (int i = 0; i < 530; i++)
{
xPixel += 1;
repaint();
// then sleep for a bit for your animation
try
{
Thread.sleep(4);
} /* this will pause for 50 milliseconds */
catch (InterruptedException e)
{
System.err.println("sleep exception");
}
}
} //try
catch (Exception ex) {
// do something...
}
}
};
hilo.start();
}
/* void moveimg() // right to left move
{
for (int i = 529; i > 0; i--)
{
if (i == 1)
{
moveImage();
}
xPixel -= 1;
repaint();
// then sleep for a bit for your animation
try
{
Thread.sleep(40);
} // this will pause for 50 milliseconds
catch (InterruptedException e)
{
System.err.println("sleep exception");
}
}
} */
public void actionPerformed(ActionEvent ae)
{
try
{
if (ae.getSource() == btn)
{
p.setBackground(Color.RED);
}
}
catch (Exception e)
{
System.out.println("error");
}
}
public static void main(String args[])
{
MyImage me = new MyImage();
}
}

Whenever you are about to write Thread.sleep in your GUI code, stop yourself and introduce a task scheduled on Swing's Timer. This is exactly what you need with your code: schedule each update as a separate scheduled task on Timer. Timer is quite simple and straightforward to use, see for example this official Oracle tutorial.

Related

Java - Create a button from a shape

I am learning Java currently and have been given the assignmnet of finidhing off a program to create the game Conways's life (we started with some code provided to us and must add features etc to this).
I am currently stuck on a menu option for the game. I want it to start off at the menu screen, wherein buttons appear at the top for "Start", "Random", "Load", Save". I have written code so that the program displays these buttons, through a fillRect option in my paint method.
My question is, how do I use the mousePressed method to recognise the cells selected so that I can get an action to occur when they are selected. I been looking at this for a while but can't seem to get this working.
Any suggestion would be a massive help. I have shared my code below. It's a work in progress but I would really like to get this working before continuing on with the other functionality.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
public class ConwaysLife extends JFrame implements Runnable, MouseListener {
// member data
private BufferStrategy strategy;
private Graphics offscreenBuffer;
private boolean gameState[][] = new boolean[40][40];
private boolean isGameInProgress = false;
// constructor
public ConwaysLife () {
//Display the window, centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - 400;
int y = screensize.height/2 - 400;
setBounds(x, y, 800, 800);
setVisible(true);
this.setTitle("Conway's game of life");
// initialise double-buffering
createBufferStrategy(2);
strategy = getBufferStrategy();
offscreenBuffer = strategy.getDrawGraphics();
// register the Jframe itself to receive mouse events
addMouseListener(this);
// initialise the game state
for (x=0;x<40;x++) {
for (y=0;y<40;y++) {
gameState[x][y]=false;
}
}
// create and start our animation thread
Thread t = new Thread(this);
t.start();
}
// thread's entry point
public void run() {
while ( 1==1 ) {
// 1: sleep for 1/5 sec
try {
Thread.sleep(200);
} catch (InterruptedException e) { }
// 2: animate game objects [nothing yet!]
/*if (isGameInProgress == false) {
this.repaint();
}*/
// 3: force an application repaint
this.repaint();
}
}
// mouse events which must be implemented for MouseListener
public void mousePressed(MouseEvent e) {
while (!isGameInProgress) {
int x = e.getX()/20;
int y = e.getY()/20;
if(x >= 10 && x <= 80 && y >= 40 && y <= 65) {
isGameInProgress = !isGameInProgress;
this.repaint();
}
}
// determine which cell of the gameState array was clicked on
int x = e.getX()/20;
int y = e.getY()/20;
// toggle the state of the cell
gameState[x][y] = !gameState[x][y];
// request an extra repaint, to get immediate visual feedback
this.repaint();
}
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) { }
//
// application's paint method
public void paint(Graphics g) {
Font font = new Font("Veranda", Font.BOLD, 20);
g = offscreenBuffer; // draw to off screen buffer
// clear the canvas with a big black rectangle
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
/*look to add a while game in progress loop here!!!*/
// draw menu options
if(!isGameInProgress) {
g.setColor(Color.green);
g.fillRect(10, 40, 70, 25);
g.fillRect(100, 40, 100, 25);
g.fillRect(300, 40, 170, 25);
g.setColor(Color.BLACK);
g.setFont(font);
g.drawString("Start", 15, 60);
g.drawString("Random", 105, 60);
g.drawString("Load", 305, 60);
g.drawString("Save", 395, 60);
}
// redraw all game objects
g.setColor(Color.WHITE);
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
if (gameState[x][y]) {
g.fillRect(x*20, y*20, 20, 20);
}
}
}
// flip the buffers
strategy.show();
}
// application entry point
public static void main(String[] args) {
ConwaysLife w = new ConwaysLife();
}
}
You're not going to like the answer, but it's the "correct" way to approach the problem.
What you need to understand is, Swing/AWT is using a "passive" rendering workflow and BufferStrategy is using a "active" rendering workflow, these are incompatible with each other.
As a general rule, you should not be overriding paint of top level containers like JFrame, this is going to end in no end of issues. Instead, you should be starting with something like JPanel and overriding it's paintComponent method instead.
Having said that, there's a "simpler" solution available to you. CardLayout. This will allow you to seperate the workflows of the menu from the game and resolve the issue between Swing/AWT and BufferStrategy
For example...
import java.awt.Canvas;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferStrategy;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
enum View {
MENU, GAME;
}
private CardLayout cardLayout = new CardLayout();
private GamePane gamePane;
public MainPane() {
setLayout(cardLayout);
gamePane = new GamePane();
add(new MenuPane(new MenuPane.Observer() {
#Override
public void startNewGame() {
showGame();
}
#Override
public void randomGame() {
}
#Override
public void loadGame() {
}
#Override
public void saveGame() {
}
}), View.MENU);
add(gamePane, View.GAME);
}
protected void add(Component compent, View view) {
add(compent, view.name());
}
protected void showGame() {
show(View.GAME);
gamePane.start();
}
protected void showMenu() {
gamePane.stop();
show(View.MENU);
}
protected void show(View view) {
cardLayout.show(this, view.name());
}
}
public class MenuPane extends JPanel {
public interface Observer {
public void startNewGame();
public void randomGame();
public void loadGame();
public void saveGame();
}
private Observer observer;
public MenuPane(Observer observer) {
this.observer = observer;
JButton startButton = new JButton("Start");
JButton randomButton = new JButton("Random");
JButton loadButton = new JButton("Load");
JButton saveButton = new JButton("Save");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.insets = new Insets(8, 8, 8, 8);
gbc.weightx = GridBagConstraints.REMAINDER;
add(startButton, gbc);
add(randomButton, gbc);
add(loadButton, gbc);
add(saveButton, gbc);
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.startNewGame();
}
});
randomButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.randomGame();
}
});
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.loadGame();
}
});
saveButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
observer.saveGame();
}
});
}
}
public class GamePane extends Canvas {
private Thread thread;
private volatile boolean isRunning = false;
public GamePane() {
setBackground(Color.BLACK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
protected void start() {
if (isRunning) {
return;
}
createBufferStrategy(3);
isRunning = true;
thread = new Thread(new Runnable() {
#Override
public void run() {
mainLoop();
}
});
thread.start();
}
protected void stop() {
if (!isRunning || thread == null) {
return;
}
isRunning = false;
try {
thread.join();
} catch (InterruptedException ex) {
}
thread = null;
}
protected void mainLoop() {
try {
while (isRunning) {
render();
Thread.sleep(16);
}
} catch (InterruptedException ex) {
}
}
protected void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy == null) {
return;
}
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
Graphics graphics = strategy.getDrawGraphics();
FontMetrics fm = graphics.getFontMetrics();
String text = "All your game are belong to us";
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = (getHeight() - fm.getHeight()) / 2;
graphics.setColor(Color.WHITE);
graphics.drawString(text, x, y + fm.getAscent());
// Render to graphics
// ...
// Dispose the graphics
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
}
}
I would strongly recommend that you take the time to read through:
Creating a GUI With Swing
A Visual Guide to Layout Managers
Performing Custom Painting
Painting in AWT and Swing
BufferStrategy and BufferCapabilities
JavaDocs for BufferStrategy which demonstrate how the API should be used.
A "fully" BufferStrategy based approach...
Now, if you can't use Swing, "for reasons", you can still achieve a simular concept using "delegation".
Basically this means "delegating" responsibility for performing some workflow to another. In this case, we want to delegate the rendering and the handling of the mouse events.
This allows you to have a dedicated workflow for the menu and a dedicated workflow for the game, without having to try and mix a lot of state.
Why do I keep on insisting on separating these two workflows? Simply, because it makes it MUCH easier to manage and reason about, but also because it supports the Single Responsibility Principle.
The follow example makes use of Renderable interface to define the core functionality that end "render" delegate will need to implement, in this case, it's pretty simple, we want to tell the renderer to "render" it's content on each paint pass and we want to (optionally) delegate mouse clicked events (this could be done via a second interface or even just the MouseListener interface directly, but I've made it a requirement of the Renderable interface for demonstration purposes.
The "basic" solution to your actual question is found through the use of Rectangle#contains(Point).
This basically inspects each "button" Rectangle to determine if the supplied MouseEvent occurs within it's bounds, if it does, we take action.
It is, however, a little more complicated then that, as we need to have the Rectangles built ahead of time, not difficult, but it's state which is actually reliant on the parent, as we need to know the area in which the renderer is been displayed, run the example, you'll see what I mean 😉
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MainPane mainPane = new MainPane();
JFrame frame = new JFrame();
frame.add(mainPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
mainPane.start();
}
});
}
public interface Renderable {
public void render(Graphics2D g2d, Dimension size);
// We could just extend from MouseListener
// but I don't need all those event handlers
public void mouseClicked(MouseEvent e);
}
public class MainPane extends Canvas {
private Thread thread;
private volatile boolean isRunning = false;
private Renderable currentRenderer;
private MenuRenderer menuRenderer;
private GameRenderer gameRenderer;
public MainPane() {
setBackground(Color.BLACK);
gameRenderer = new GameRenderer();
menuRenderer = new MenuRenderer(new MenuRenderer.Observer() {
#Override
public void startNewGame() {
showGame();
}
#Override
public void randomGame() {
}
#Override
public void loadGame() {
}
#Override
public void saveGame() {
}
});
showMenu();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (currentRenderer == null) {
return;
}
currentRenderer.mouseClicked(e);
}
});
}
protected void showMenu() {
// This may need to tell the game renderer to stop
// or pause
currentRenderer = menuRenderer;
}
protected void showGame() {
currentRenderer = gameRenderer;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
protected void start() {
if (isRunning) {
return;
}
createBufferStrategy(3);
isRunning = true;
thread = new Thread(new Runnable() {
#Override
public void run() {
mainLoop();
}
});
thread.start();
}
protected void stop() {
if (!isRunning || thread == null) {
return;
}
isRunning = false;
try {
thread.join();
} catch (InterruptedException ex) {
}
thread = null;
}
protected void mainLoop() {
try {
while (isRunning) {
render();
Thread.sleep(16);
}
} catch (InterruptedException ex) {
}
}
protected void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy == null && currentRenderer != null) {
return;
}
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
g2d.setBackground(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON
);
g2d.setRenderingHints(hints);
// Render to graphics
currentRenderer.render(g2d, getSize());
// Dispose the graphics
g2d.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
}
public class GameRenderer implements Renderable {
#Override
public void render(Graphics2D g2d, Dimension size) {
FontMetrics fm = g2d.getFontMetrics();
String text = "All your game are belong to us";
int x = (size.width - fm.stringWidth(text)) / 2;
int y = (size.height - fm.getHeight()) / 2;
g2d.setColor(Color.WHITE);
g2d.drawString(text, x, y + fm.getAscent());
}
#Override
public void mouseClicked(MouseEvent e) {
}
}
public class MenuRenderer implements Renderable {
public interface Observer {
public void startNewGame();
public void randomGame();
public void loadGame();
public void saveGame();
}
private Observer observer;
private String[] menuOptions = new String[]{
"New Game",
"Random",
"Load Game",
"Save Game"
};
private Rectangle[] menuBounds;
private int internalPadding = 20;
private int horizontalGap = 16;
public MenuRenderer(Observer observer) {
this.observer = observer;
}
#Override
public void render(Graphics2D g2d, Dimension size) {
if (menuBounds == null) {
createMenus(g2d, size);
}
renderMenus(g2d);
}
protected void createMenus(Graphics2D g2d, Dimension size) {
FontMetrics fm = g2d.getFontMetrics();
int totalHeight = (((fm.getHeight() + internalPadding) + horizontalGap) * menuOptions.length) - horizontalGap;
int buttonHeight = fm.getHeight() + internalPadding;
menuBounds = new Rectangle[menuOptions.length];
int buttonWidth = 0;
for (int index = 0; index < menuOptions.length; index++) {
int width = fm.stringWidth(menuOptions[index]) + internalPadding;
buttonWidth = Math.max(width, buttonWidth);
}
int yPos = (size.height - totalHeight) / 2;
for (int index = 0; index < menuOptions.length; index++) {
int xPos = (size.width - buttonWidth) / 2;
Rectangle menuRectangle = new Rectangle(xPos, yPos, buttonWidth, buttonHeight);
menuBounds[index] = menuRectangle;
yPos += buttonHeight + (horizontalGap / 2);
}
}
protected void renderMenus(Graphics2D g2d) {
for (int index = 0; index < menuOptions.length; index++) {
String text = menuOptions[index];
Rectangle bounds = menuBounds[index];
renderMenu(g2d, text, bounds);
}
}
protected void renderMenu(Graphics2D g2d, String text, Rectangle bounds) {
FontMetrics fm = g2d.getFontMetrics();
int textWidth = fm.stringWidth(text);
int textXPos = (bounds.x + (internalPadding / 2)) + ((bounds.width - internalPadding - textWidth) / 2);
int textYPos = bounds.y + (internalPadding / 2);
RoundRectangle2D buttonBackground = new RoundRectangle2D.Double(bounds.x, bounds.y, bounds.width, bounds.height, 20, 20);
g2d.setColor(Color.BLUE.darker());
g2d.fill(buttonBackground);
g2d.setColor(Color.WHITE);
g2d.drawString(text, textXPos, textYPos + fm.getAscent());
}
#Override
public void mouseClicked(MouseEvent e) {
if (menuBounds == null) {
return;
}
for (int index = 0; index < menuOptions.length; index++) {
if (menuBounds[index].contains(e.getPoint())) {
switch (index) {
case 0:
observer.startNewGame();
break;
case 2:
observer.randomGame();
break;
case 3:
observer.loadGame();
break;
case 4:
observer.saveGame();
break;
}
}
}
}
}
}

Repaint() working only half times

i've got a problem with what should be a simple excercise.
I've been asked to make an applet that prints a green oval (filled) that becomes larger until it hits the borders, than start becoming smaller.
This should go on until you close the applet.
Well, i came out with this code
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
public class Disco extends JApplet{
private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;
public void init() {}
public void start() {
x = getWidth()/2;
y = getHeight()/2;
r = 50;
enlarge = true;
makeLarger = new MakeLarger();
makeLarger.start();
}
public void paint(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x - r, y- r, r*2, r*2);
}
public void update() {
if(enlarge) {
makeLarger = new MakeLarger();
makeLarger.start();
} else {
makeSmaller = new MakeSmaller();
makeSmaller.start();
}
}
private class MakeLarger extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(getWidth() > getHeight()) {
if(r < getHeight()/2) {
r++;
repaint();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
} else {
if(r < getWidth()/2) {
r++;
repaint();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
private class MakeSmaller extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(r > 50) {
r--;
repaint();
revalidate();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = true;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
When I start my applet the oval start growing correctly until it hits the border and then suddently stop.
The first thing i thought was that it wasn't getting smaller correctly. But a little System.out.println work showed me that all computation was going on correctly, the problem is that the applet repaint only while the makeLarger thread is active, when the makeSmaller thread is at work the call to repaint() doesn't work!
If i resize the applet window while the makeSmaller Thread is at work it repaints correctly showing me the oval getting smaller.
Can, please, someone enlight me on this odd behavior?
What am I missing?
thank you everyone for your most appreciated help and sorry if my english is so poor!
I can't say that I've looked at all the code, but a couple of suggestions:
Paint in a JPanel's paintComponent override.
This is key: call the super.paintComponent method in the override, first line. This gets rid of prior images so that the image can get smaller.
Display the JPanel within your JApplet by adding it to the applet.
Myself, I'd use a single Swing Timer for the animation loop, and would use a boolean to decide which direction the sizing should go.
But regardless of whether I were using a Swing Timer or a Runnable placed in a Thread, I'd try to keep things a simple as possible, and that would mean using a single Timer that changes direction of resizing or a single Runnable/Thread that changes size of resizing based on a boolean. This swapping of threads that you're doing just serves to overly and unnecessarily complicate things, and could quite possibly be the source of your error.
As a side recommendation, you almost never want to extend Thread. Much better is to create classes that implement Runnable, and then when you need to run them in a background thread, create a Thread, passing in your Runnable into the Thread's constructor, and then calling start() on the Thread.
First things first, thank you all for helping me!
The problem I was trying to solve was this:
Make an applet which shows a green oval getting larger until it hits the borders, then it should start getting smaller up to a fixed radius (50), then it should start over (and over) again. Solve the problem by making two threads (by extending Thread).
Just to explain why the algorithm was so odd!
Well, reading your suggestions I fixed my code, now it's running properly. Here is the code if anyone will need this.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JApplet;
import javax.swing.Timer;
public class Disco extends JApplet{
private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;
public void init() {}
public void start() {
x = getWidth()/2;
y = getHeight()/2;
r = 50;
enlarge = true;
makeLarger = new MakeLarger();
makeLarger.start();
Timer timer = new Timer(1000/60, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
public void paint(Graphics g) {
BufferedImage offScreenImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D g2D = (Graphics2D) offScreenImage.getGraphics();
g2D.clearRect(0, 0, getWidth(), getHeight());
g2D.setColor(Color.GREEN);
g2D.fillOval(x - r, y- r, r*2, r*2);
g.drawImage(offScreenImage, 0, 0, this);
}
public void update() {
if(enlarge) {
makeLarger = new MakeLarger();
makeLarger.start();
} else {
makeSmaller = new MakeSmaller();
makeSmaller.start();
}
}
private class MakeLarger extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(getWidth() > getHeight()) {
if(r < getHeight()/2) {
r++;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
} else {
if(r < getWidth()/2) {
r++;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
private class MakeSmaller extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(r > 50) {
r--;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = true;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}

java repaint does not works inside while lop works in end of loop

After execution, the loop completes its circles and then the repaint method is being called,
Is there an alternative way of drawing the image?
public class GameCanvas extends JPanel implements KeyListener {
private Tank tank1;
private Tank tank2;
private Rocket rocket;
public Graphics2D g2;
private Image img;
public boolean fire;
public GameCanvas() {
tank1 = new Tank(0, 0);
tank2 = new Tank(500, 500);
rocket = new Rocket(50, tank1);
init();
fire = false;
}
public void init() {
JFrame frame = new JFrame("Topak Tank");
frame.setLayout(new FlowLayout());
frame.setSize(1300, 740);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
this.setPreferredSize(new Dimension(1300, 740));
frame.add(this);
frame.addKeyListener(tank1);
frame.addKeyListener(this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
tank1.draw(g);
// rocket.draw(g);
g2 = (Graphics2D) g;
if (fire == true) {
try {
img = ImageIO.read(getClass().getResource("rocket.png"));
System.out.println(rocket.getYPos());
g2.drawImage(img, rocket.getXPos(), rocket.getYPos(), null);
} catch (Exception e) {
}
}
repaint();
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_F: {
try {
int xPos = tank1.getXAxis();
int yPos = tank1.getYAxis();
fire = true;
int delay = 10000;
// img = ImageIO.read(getClass().getResource("rocket.png"));
int count = 0;
while (true) {
System.out.println(xPos);
System.out.println(yPos);
if (count == 5) {
break;
}
count++;
// g2.drawImage(img,xPos,yPos,null);
rocket.setYPos(yPos);
System.out.println("loop");
Timer t = new Timer(delay, null);
t.start();
yPos++;
this.repaint();// here i want to excute and draw image after every lop cycle
Thread.sleep(100);
}
System.out.println("Fired");
fire = false;
} catch (Exception io) {
JOptionPane.showMessageDialog(null, "Could not found Rocket image");
}
}
break;
}
}
public void keyReleased(KeyEvent ke) {
}
public void keyTyped(KeyEvent ke) {
}
public static void main(String[] arg) {
GameCanvas gc = new GameCanvas();
}
}
Calling repaint() just tells the component to repaint itself whenever the EDT is available again. Since that entire loop is on the EDT, the component can't repaint itself until it's done.
You should probably be using a Timer or a Thread instead of tying up the EDT with that loop. You should NOT be calling sleep() on the EDT.
More info here: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/

How to update jlabel while running animation?

I have a little animation where a rectangle, which is a jlabel with blue background, is constantly moving down the screen. I am running a thread to do this.
Now, i want to have another jlabel where it shows the current position of the rectangle.
public void run()
{
Pnl.requestFocus();
x = (int) p.getX(); //find location of rectangle
y = (int) p.getY();
while (y < 450)
{
RectangleLabel.setLocation(x, y); //reset location of the rectangle
y += 10;
try {
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
}
}
Now i want to insert this code inside the while statement.
locationLabel.setText(String.valueOf(450-y));
But every time i do, the jlable updates but the rectangle doesnt move anymore.
How would i go about?
Try This :
Run This example
import javax.swing.*;
import java.lang.*;
class TestThread extends JFrame implements Runnable{
JLabel RectangleLabel,locationLabel;
int x,y=0;
TestThread()
{
setVisible(true);
setLayout(null);
RectangleLabel=new JLabel("Rectangle");
RectangleLabel.setBounds(10,10,100,100);
locationLabel=new JLabel();
locationLabel.setBounds(200,200,100,100);
add(RectangleLabel);
add(locationLabel);
setSize(1000,1000);
Thread t=new Thread(this);
t.run();
}
public void run()
{
while (y < 450)
{
RectangleLabel.setLocation(x, y); //reset location of the rectangle
y += 10;
locationLabel.setText(""+y);
try {
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
if(y==440)
{
y=0;
}
}
}
public static void main(String args[]) {
TestThread t=new TestThread();
}
}

Problem with having Canvas and Panel rendering on Frame for animation

i have problem with canvas Jpanel and need optimized solution
i got this design from one of the post on this forum.
i have three classes :
one is for animation which is canvas(BallPanel), one is frame(Main) and one is panel for swing controls(ControlPanel)
Main is rending both Controlpanel and BallPanel, but in the end, i can't see the drawworld() rendering from BallPanel but i can only ControlPanel.
I can't see animation and black background,seems like controlpanel is all on frame and canvas (black background) is behind/underneath that or somewhere but invisible
BallPanel:
public BallPanel()
{
try {
this.aBall = (BallServer) Naming
.lookup("rmi://localhost/BouncingBalls");
} catch (Exception e) {
System.out.println("Exception: " + e);
}
box = new Box(0, 0, BOX_WIDTH, BOX_HEIGHT);
setPreferredSize(new Dimension(800, 600));
setIgnoreRepaint(true);
// Wire up Events
// MouseHandler mouseHandler = new MouseHandler();
// addMouseMotionListener(mouseHandler);
// addMouseListener(mouseHandler);
}
public void drawworld() throws RemoteException {
if (strategy == null || strategy.contentsLost())
{
// Create BufferStrategy for rendering/drawing
this.createBufferStrategy(2);
strategy = getBufferStrategy();
Graphics g = strategy.getDrawGraphics();
this.g2 = (Graphics2D) g;
}
// Turn on anti-aliasing
this.g2.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// box.draw(this.g2); // this can be another but it's also not working
// Render Background
this.g2.setColor(Color.BLACK);
this.g2.fillRect(0, 0, getWidth(), getHeight());
serball = aBall.getState();// other version UNcomment this line
for (int i = 0; i < currentNumBalls; i++) {
this.g2.setColor(serball[i].getBallColor(velocity.getLength()));
this.g2
.fillOval((int) (serball[i].position.getX() - serball[i]
.getRadius()),
(int) (serball[i].position.getY() - serball[i]
.getRadius()), (int) (2 * serball[i]
.getRadius()), (int) (2 * serball[i]
.getRadius()));
}
public void mainLoop() {
long previousTime = System.currentTimeMillis();
long currentTime = previousTime;
long elapsedTime;
long totalElapsedTime = 0;
int frameCount = 0;
while (true) {
currentTime = System.currentTimeMillis();
elapsedTime = (currentTime - previousTime); // elapsed time in
// seconds
totalElapsedTime += elapsedTime;
if (totalElapsedTime > 1000) {
currentFrameRate = frameCount;
frameCount = 0;
totalElapsedTime = 0;
}
try {
drawworld();
} catch (RemoteException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(5);
} catch (Exception e) {
e.printStackTrace();
}
previousTime = currentTime;
frameCount++;
}
}
public void start()
{
mainLoop();
}
the Main class above start() is calling from here :
public static void main(String[] args)
{
JFrame frame = new JFrame("BallBounce");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));
BallPanel ballCanvas = new BallPanel();
ControlPanel controlPanel = new ControlPanel(ballCanvas);
frame.getContentPane().add(ballCanvas);
frame.getContentPane().add(controlPanel);
frame.pack();
frame.setVisible(true);
ballCanvas.start();
}
this is controlpanel whichis working as controller:
public class ControlPanel extends JPanel {
private BallPanel mainPanel;
private JButton resetButton;
public ControlPanel(BallPanel mainPanel)
{
this.setPreferredSize(new Dimension(200, 60));
this.setMaximumSize(new Dimension(5000, 100));
this.mainPanel = mainPanel;
....
..
..
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JButton source = (JButton)e.getSource();
if (source == resetButton)
{
mainPanel.clearBalls();
}
Many thanks for any help and how we could handle such GUI with RMI animation and swing control for interacting/controlling that
can somebody tell optimized way.
jibby lala
P.S: i thought there is some thread problem while i m calling the remote method and rendering the drawworld, either of thread is going on suspension or blocked
cross post: http://www.coderanch.com/forums/jforum?module=posts&action=edit&post_id=2406332&start=0
i made this with timer but the problems persist please help:
public CopyOfCleanBallPanel2() throws IOException, InterruptedException {
frame = new JFrame("simple gaming loop in java");
frame.setSize(BOX_WIDTH, BOX_WIDTH);
frame.setResizable(false);
displayCanvas = new CustomCanvas();
displayCanvas.setLocation(0, 0);
displayCanvas.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
displayCanvas.setBackground(Color.BLACK);
displayCanvas.setFont(new Font("Arial", Font.BOLD, 14));
displayCanvas.setPreferredSize(new Dimension(CANVAS_WIDTH,CANVAS_HEIGHT));
frame.add(displayCanvas);
displayCanvas.requestFocus();
frame.setLocationRelativeTo(null);
try {
this.aBall = (BallServer) Naming
.lookup("rmi://localhost/BouncingBalls");
} catch (Exception e) {
System.out.println("Exception: " + e);
}
frame.pack();
frame.setVisible(true);
aBall.start();
startFrameTimer();
}
/*
* Initializes the frame (also game update) timer.
*/
private void startFrameTimer() {
frameTimer.schedule(new FrameTimerTask(), 1, GAME_TIMER_COOLDOWN);
}
public void updateSimulation() throws RemoteException {
repaintCanvas();
}
/*
* This method gets called by the timer. It updates the game simulation and
* redraws it.
*/
private void onFrameTimer() throws RemoteException {
updateSimulation();
}
/*
* Causes the whole canvas to get repainted.
*/
private final void repaintCanvas() throws RemoteException {
Graphics g = displayCanvas.getGraphics();
drawworld(g);
}
private class FrameTimerTask extends TimerTask {
public void run() {
try {
onFrameTimer();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
/*
* This custom canvas overrides the paint method thus allowing for a custom
* painting on the component.
*/
private class CustomCanvas extends Canvas {
#Override
public void paint(Graphics g) {
// Currently the game message gets drawn over the inner border
// of the canvas so we have to repaint the whole thing.
try {
repaintCanvas();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public void drawworld(Graphics g) throws RemoteException {
g.setColor(Color.BLACK);
g.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
System.out.println("i m in drawworld ");
serBall = aBall.getState1();// other version UNcomment this line
System.out.println("i m in drawworld "+serBall.length);
for (int i = 0; i < currentNumBalls; i++) {
g.setColor(serBall[i].getBallColor(velocity.getLength()));
g
.fillOval((int) (serBall[i].position.getX() - serBall[i]
.getRadius()),
(int) (serBall[i].position.getY() - serBall[i]
.getRadius()), (int) (2 * serBall[i]
.getRadius()), (int) (2 * serBall[i]
.getRadius()));
// Draw our framerate and ball count
g.setColor(Color.WHITE);
g.drawString("FPS: " + currentFrameRate + " Balls: "
+ currentNumBalls, 15, 15);
}
}
Please Help.
It looks like a thread issue as it appears to me you're calling while (true) and Thread.sleep(...) on the EDT, the main Swing thread. Have you read up on Concurrency in Swing? If not, check out the article linked to within. Also strongly consider using a Swing Timer to drive your animation instead of while (true) and Thread.sleep(...).

Categories

Resources