So I have this JPanel Graphics code:
public void paint(Graphics g){
super.paint(g);
for(int y=0 ;y < 50; y++){
for(int x = 0; x < 50; x++){
if(m.getMaze(x, y).equals("g")){
g.drawImage(m.getGround(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("w")){
g.drawImage(m.getWall(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("S")){
g.drawImage(m.getStart(), x * 16, y * 16,null);
}
if(m.getMaze(x, y).equals("E")){
g.drawImage(m.getEnd(), x * 16, y * 16,null);
}
}
}
}
And inside the for loop (the second one) I would like to pause it for half a second, so you can see it drawing each tile. The thing is, is when I use
Thread.sleep(500);
After the second for loop, it just stops the whole thing forever. If I use
g.wait(500);
it keeps spamming
java.lang.IllegalMonitorStateException
in the console. And yes, it is surrounded with try/catch. How can I pause this?
On a swing Timer call repaint(50L, x*16, y*16, 16, 16);. Use fields for the current state (x, y),
and on every paintComponent draw only that state/tile.
1) use paintComponent() method for custom paintings intead of paint(). Read about custom paintings in java
2) Don't block EDT with Thread.sleep(500); or g.wait(500);.
Seems you need to use swing Timer for loading. Here is simple example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class TestFrame extends JFrame {
private Timer timer;
public TestFrame() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void init() {
final DrawPanel p = new DrawPanel();
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(p.drawingTiles < 16){
p.addDrawingTile();
p.repaint();
} else {
timer.stop();
System.out.println("done");
}
}
});
timer.start();
add(p);
}
public static void main(String args[]) {
new TestFrame();
}
private class DrawPanel extends JPanel{
protected int drawingTiles = 0;
private int tiles[][] = new int[4][4];
public DrawPanel(){
Random r = new Random();
for(int i=0;i<tiles.length;i++){
for(int j=0;j<tiles.length;j++){
tiles[i][j] = r.nextInt(5);
}
}
}
public void addDrawingTile() {
drawingTiles++;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int curTiles = 0;
for(int i=0;i<tiles.length;i++){
for(int j=0;j<tiles.length;j++){
if(curTiles <drawingTiles){
curTiles++;
g.drawString(tiles[i][j]+"", (j+1)*10, (i+1)*10);
}
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50,50);
}
}
}
Related
Vertical bars should be filling to the height of the applet. When the top is reached, a new bar should start filling next to the previous. Problem: When the new bar starts filling the previous paint() /bar is cleared
img how it is: http://bayimg.com/DAEoeaagm
img how it should be: http://bayimg.com/dAeOgAaGm
the code:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
public class fillingbar extends JApplet implements Runnable{
int shifting=0,filling=0;
public void init()
{
Thread t= new Thread(this);
t.start();
setSize(400,250);
}
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.GREEN);
g.fillRect(shifting,getHeight()-filling,20,filling);
g.setColor(Color.BLACK);
g.drawRect(shifting, getHeight()-filling, 20, filling);
}
public void run()
{
while(true)
{
repaint();
try{
if(shifting<getWidth())
{
if(filling<getHeight())
filling+=10;
else {
shifting+=20;
filling=0;
}
}
Thread.sleep(50);
}catch(Exception E){
System.out.println("Exception caught");
}
}
}
}
You only draw one rectangle in your paint method, and so it makes sense that only one will show.
If you need to draw more, do so, using a for loop that loops through perhaps a Rectangle ArrayList<Rectangle>.
Another way is to make shifting local and do a bit of simple math inside paintComponent to see what to draw and where. For instance, draw your completed bars inside of a for loop, for (int i = 0; i < filling / getHeight(); i++) {, and your yet to be completed bar up to filling % getHeight().
You should not draw directly within a JApplet but rather in the paintComponent method of a JPanel.
A Swing Timer is easier to use than a thread (for me at least), and can be safer.
For example, this can be created by the code below:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
#SuppressWarnings("serial")
public class FillingBar2 extends JApplet {
#Override
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
FillingBarPanel fillingBarPanel = new FillingBarPanel();
add(fillingBarPanel);
add(new JButton(new StartAction(fillingBarPanel)), BorderLayout.PAGE_END);
setSize(getPreferredSize());
}
});
} catch (InvocationTargetException | InterruptedException e) {
System.err.println("Big Problems");
e.printStackTrace();
}
}
}
#SuppressWarnings("serial")
class StartAction extends AbstractAction {
private FillingBarPanel fillingBarPanel;
public StartAction(FillingBarPanel fillingBarPanel) {
super("Start");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
this.fillingBarPanel = fillingBarPanel;
}
#Override
public void actionPerformed(ActionEvent evt) {
fillingBarPanel.start();
}
}
#SuppressWarnings("serial")
class FillingBarPanel extends JPanel {
private static final int BAR_WIDTH = 20;
private static final int TIMER_DELAY = 100;
private static final int PREF_W = 400;
private static final int PREF_H = 250;
private int filling = 0;
private Timer timer;
public FillingBarPanel() {
timer = new Timer(TIMER_DELAY, new TimerListener());
}
public void start() {
if (timer != null && !timer.isRunning()) {
timer.start();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int shifting = 0;
for (int i = 0; i < filling / getHeight(); i++) {
shifting = i * BAR_WIDTH;
g.setColor(Color.GREEN);
g.fillRect(shifting, 0, BAR_WIDTH, getHeight());
g.setColor(Color.BLACK);
g.drawRect(shifting, 0, BAR_WIDTH, getHeight());
}
shifting = BAR_WIDTH * (filling / getHeight());
g.setColor(Color.GREEN);
g.fillRect(shifting, getHeight() - (filling % getHeight()), BAR_WIDTH, getHeight());
g.setColor(Color.BLACK);
g.drawRect(shifting, getHeight() - (filling % getHeight()), BAR_WIDTH, getHeight());
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent evt) {
filling += 10;
repaint();
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
So I have to move my (multiple) images across a GUI, but for whatever reason my paint method is only being called twice, even though my x variable and my timer, which I am using to try and move the image, are incrementing correctly. Any help would be appriciated! Thanks
import javax.swing.*;
import java.awt.*;
import java.lang.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class Races extends JFrame
{
public int threadCount = 5;
public int x = 0;
public ImageIcon picture = new ImageIcon("races.jpeg");
public int height = picture.getIconHeight();
public int width = picture.getIconHeight();
public Races(int _threadCount)
{
threadCount = _threadCount;
int counter = 0;
while(counter<threadCount)
{
(new Thread(new RacesInner(threadCount))).start();
counter++;
}
initialize();
}
public static void main(String[] args)
{
if(args.length == 0)
{
JFrame f = new Races(5);
}
else
{
JFrame f = new Races(Integer.parseInt(args[0]));
}
}
public void initialize()
{
this.setVisible(true);
this.setTitle("Off to the Races - By ");
RacesInner inner = new RacesInner(threadCount);
this.add(inner);
this.setSize((width*20),(height*3)*threadCount);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.repaint();
}
protected class RacesInner extends JPanel implements Runnable
{
public int j = (int)(Math.random() * 50) + 20;
public void timer()
{
Timer timer1 = new Timer(j, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
x += 2;
repaint();
}
});
timer1.start();
}
public void run()
{
timer();
}
#Override
public void paint(Graphics g)
{
super.paintComponent(g);
//drawing the correct amount of icons based on input(or lack of input, default 5)
//Get the current size of this component
Dimension d = this.getSize();
//draw in black
g.setColor(Color.BLACK);
//calculating where finish line should be and drawing the line
int finishLine;
finishLine = (width*20)-(width*2);
g.drawLine(finishLine,0,finishLine,2000);
for(int i =0; i<threadCount; i++)
{
picture.paintIcon(this,g,1+x,(50*i));
}
}
public RacesInner(int _threadCount)
{
threadCount = _threadCount;
System.out.println(threadCount);
//JPanel
this.setVisible(true);
this.setLayout(new GridLayout(threadCount,1));
}
}//closes RacesInner class
}//closes races class
I've just moved over from Pygame so Java 2D in an applet is a little new to me, especially when it comes to repainting the screen. In pygame you can simply do display.fill([1,1,1]) but how do I do this in an applet in Java? I understand the use of repaint() but that doesn't clear the screen - any moving object is not 'removed' from the screen so you just get a long line of painted circles.
Here's my code that I've been testing with:
package circles;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
public class circles extends Applet implements Runnable {
private static final long serialVersionUID = -6945236773451552299L;
static Random r = new Random();
String msg = "Click to play!";
static int w = 800, h = 800;
int[] txtPos = { (w/2)-50,(h/2)-50 };
int[] radiusRange = { 5,25 };
int[] circles;
static int[] posRange;
int x = 0, y = 0;
int radius = 0;
int cursorRadius = 10;
boolean game = false;
public static int[] pos() {
int side = r.nextInt(5-1)+1;
switch(side) {
case 1:
posRange = new int[]{ 1,r.nextInt(w),r.nextInt((h+40)-h)+h,r.nextInt(270-90)+90 };
break;
case 2:
posRange = new int[]{ 2,r.nextInt((w+40)-w)+w,r.nextInt(h),r.nextInt(270-90)+90 };
break;
case 3:
posRange = new int[]{ 3,r.nextInt(w),r.nextInt(40)-40,r.nextInt(180) };
break;
case 4:
posRange = new int[]{ 4,r.nextInt(40)-40,r.nextInt(h),r.nextInt(180) };
break;
}
System.out.println(side);
return posRange;
}
public void start() {
setSize(500,500);
setBackground(Color.BLACK);
new Thread(this).start();
}
public void run() {
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics e) {
Graphics2D g = (Graphics2D) e;
if(System.currentTimeMillis()%113==0) {
x+=1;
y+=1;
}
g.setColor(Color.BLUE);
g.fillOval(x,y,20,20);
repaint();
}
}
You need to call super.paint(g); in your paint method, as to not leave paint artifacts.
Never call repaint() from inside the paint method
Don't explicitly call paint, as you do in update(), when you mean to call reapaint()
just update the x and y values from inside the update() method, then call repaint()
You don't need to take a Graphics argument in update()
You need to call update() somewhere repeatedly in a loop, as it updates the x and y and reapint()s
If your class is going to be a Runnable, then you should put some code in the run() method. That's probably where you should have your loop
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class circles extends Applet implements Runnable {
int x = 0, y = 0;
public void start() {
setSize(500, 500);
setBackground(Color.BLACK);
new Thread(this).start();
}
public void run() {
while (true) {
try {
update();
Thread.sleep(50);
} catch (InterruptedException ex) {
}
}
}
public void update() {
x += 5;
y += 6;
repaint();
}
public void paint(Graphics e) {
super.paint(e);
Graphics2D g = (Graphics2D) e;
g.setColor(Color.BLUE);
g.fillOval(x, y, 20, 20);
}
}
Side Notes
Why use Applets in the first place. If you must, why use AWT Applet and not Swing JApplet? Time for an upgrade.
Here's how I'd redo the whole thing in Swing, using a Swing Timer instead of a loop and Thread.sleep, as you should be doing.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Circle extends JPanel{
private static final int D_W = 500;
private static final int D_H = 500;
int x = 0;
int y = 0;
public Circle() {
setBackground(Color.BLACK);
Timer timer = new Timer(50, new ActionListener(){
public void actionPerformed(ActionEvent e) {
x += 5;
y += 5;
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(x, y, 20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new Circle());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
See How to use Swing Timers
See Create GUIs with Swing
Here's more advanced example for you to look at and ponder.
UPDATE
"Problem is, that's a JPANEL application. I specifically want to make an applet easily usable on a web page. "
You can still use it. Just use the JPanel. Take out the main method, and instead of Applet, use a JApplet and just add the JPanel to your applet. Easy as that.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CircleApplet extends JApplet {
#Override
public void init() {
add(new Circle());
}
public class Circle extends JPanel {
private static final int D_W = 500;
private static final int D_H = 500;
int x = 0;
int y = 0;
public Circle() {
setBackground(Color.BLACK);
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
x += 5;
y += 5;
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(x, y, 20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
}
}
I am trying to make a program that work like this:
In Window class every time I click on the button, the method panel2 of Panel is called: first it is drawing a first circle, then a second one (after the time defined in the timer). Then, I click again on the button, and it is drawing a fist circle, then a second one then a third one. etc.
The problem is that it when I click to obtain 3 circles appearing one after the other, the two first circles drawn at the previous step (before I pressed a second time the button) stay on the screen and only the third circle is drawn when i press the button (instead of having : first circle drawn, second circle drawn, third circle drawn). I hope I am clear.
Here is a simple code:
Window
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Window extends JFrame implements ActionListener{
int h = 2;
Panel b = new Panel();
JPanel container = new JPanel();
JButton btn = new JButton("Start");
JButton bouton = new JButton();
Panel boutonPane = new Panel();
public Window(){
this.setTitle("Animation");
this.setSize(300, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
JPanel top = new JPanel();
btn.addActionListener(this);
top.add(btn);
container.add(top);
this.setContentPane(container);
this.setVisible(true);
}
public void window2(){
this.setTitle("ADHD");
this.setSize(1000,700);
this.setLocationRelativeTo(null);
if (h < 11){
boutonPane.panel2(h);
bouton.addActionListener(this);
boutonPane.add(bouton);
this.add(boutonPane);
this.setContentPane(boutonPane);
updateWindow2();
}
this.setVisible(true);
}
public void updateWindow2(){
boutonPane.panel2(h);
this.revalidate();
this.repaint();
}
public void actionPerformed(ActionEvent e){
if ((JButton) e.getSource() == btn){
System.out.println("pressed0");
window2();
}
if ((JButton) e.getSource() == bouton){
h++;
System.out.println("pressed" + h);
updateWindow2();
}
}
public static void main(String[] args){
Window w = new Window();
}
}
Panel
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Panel extends JPanel implements ActionListener{
int m;
int u=0;
int lgi, lrgi;
int [] ta;
Timer timer1 = new Timer(300, this);
Panel(){
}
public void panel2(int n){
m=n;
ta = new int [n];
for(int it=0; it<m;it++){
ta[it]=100*it;
}
timer1.start();
}
public void paintComponent(Graphics gr){
super.paintComponent(gr);
gr.setColor(Color.red);
for(int i=0;i<m;i++){
gr.fillOval(ta[i],ta[i], 150, 150);
}
}
#Override
public void actionPerformed(ActionEvent arg0) {
if(u<m){
u++;
revalidate();
repaint();
}
}
}
Your code needs use two int values to decide how many circles to draw and when:
The first int should be the count of current circles to draw, say called, currentCirclesToDraw.
The second int will be the number of circles to draw total.
If you use a List<Ellipse2D> like I suggest, then this number will be the size of the list. So if the List is called ellipseList, then the 2nd number will be ellipseList.size().
The first variable will be incremented in the timer up to the size of the list, but no larger, and will be used by paintComponent method to decide how many circles to draw.
Key point here: the first number, the currentCirclesToDraw, must be re-set to 0 when the button is pressed. This way your paintComponent method will start out drawing 0 circles, then 1, then 2, ...
For example, the paintComponent method could look like so:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(CIRCLE_COLOR);
for (int i = 0; i < currentCirclesToDraw && i < ellipseList.size(); i++) {
g2.fill(ellipseList.get(i));
}
}
I use the second term in the for loop conditional statement, i < currentCirclesToDraw && i < ellipseList.size() as an additional fail-safe to be sure that we don't try to draw more circles then we have in our list.
My Timer's ActionListener would increment the currentCirclesToDraw variable and call repaint. It would stop the Timer once currentCirclesToDraw reaches the size of the ellipseList:
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (currentCirclesToDraw < ellipseList.size()) {
currentCirclesToDraw++;
repaint();
} else {
// stop the Timer
((Timer)e.getSource()).stop();
}
}
}
And my button's actionPerformed method would reset currentCirclesToDraw to 0, would add a new Ellipse2D to my ellipseList (if we've not yet reached the MAX_CIRCLE_INDEX), would call repaint() to clear the JPanel, and would construct and start the Timer:
public void actionPerformed(java.awt.event.ActionEvent arg0) {
currentCirclesToDraw = 0; // this is key -- reset the index used to control how many circles to draw
if (ellipseList.size() < MAX_CIRCLE_INDEX) {
double x = (ellipseList.size()) * CIRCLE_WIDTH / Math.pow(2, 0.5);
double y = x;
double w = CIRCLE_WIDTH;
double h = CIRCLE_WIDTH;
ellipseList.add(new Ellipse2D.Double(x, y, w, h));
}
repaint(); // clear image
new Timer(TIMER_DELAY, new TimerListener()).start();
};
Edit 3/30/14
Note it all can be put together like this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
/**
* http://stackoverflow.com/a/22714405/522444
* http://stackoverflow.com/questions/22712655/repaint-in-panel-method-not-updated
* #author Pete
*
*/
#SuppressWarnings("serial")
public class TimerCircles extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 700;
private static final Color CIRCLE_COLOR = Color.RED;
public static final int MAX_CIRCLE_INDEX = 11;
public static final int TIMER_DELAY = 300;
public static final int CIRCLE_WIDTH = 100;
private final List<Ellipse2D> ellipseList = new ArrayList<>();
private int currentCirclesToDraw = 0;
public TimerCircles() {
add(new JButton(new ButtonAction("New Circle", KeyEvent.VK_C)));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(CIRCLE_COLOR);
for (int i = 0; i < currentCirclesToDraw && i < ellipseList.size(); i++) {
g2.fill(ellipseList.get(i));
}
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
public void actionPerformed(java.awt.event.ActionEvent arg0) {
currentCirclesToDraw = 0; // this is key -- reset the index used to control how many circles to draw
if (ellipseList.size() < MAX_CIRCLE_INDEX) {
double x = (ellipseList.size()) * CIRCLE_WIDTH / Math.pow(2, 0.5);
double y = x;
double w = CIRCLE_WIDTH;
double h = CIRCLE_WIDTH;
ellipseList.add(new Ellipse2D.Double(x, y, w, h));
}
repaint(); // clear image
new Timer(TIMER_DELAY, new TimerListener()).start();
};
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (currentCirclesToDraw < ellipseList.size()) {
currentCirclesToDraw++;
repaint();
} else {
// stop the Timer
((Timer)e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
TimerCircles mainPanel = new TimerCircles();
JFrame frame = new JFrame("TimerCircles");
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();
}
});
}
}
I was wondering if anybody here knows how to make a seamlessly endless loop with shapes using a timer. Basically I'm trying to make a new set of moving shapes while the current set of shapes is moving so that it looks like it's just infinitely moving along the top of the screen. I have tried the if statements alongside the public int getX(){return x;)}, but I have not succeeded in doing so. Maybe it's possible to have a second timer linked with a second set of shapes and set a delay time? (However, I do not know how to go about writing a second timer and I do not know how to set a delay, help me??)
Any solutions or suggestions?
Here is an example, notice how the set of shapes is redrawn after all of the shapes pass the screen. This is not what I want. I want it to appear as if it were infinitely running along the top of the screen in smooth succession.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ExampleLoop extends JPanel implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ExampleLoop());
frame.setVisible(true);
}
Timer timer = new Timer(50, this);
int x = 0, velX = 7;
// CHRISTMAS THEME :D
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.GREEN);
for (int z = 0; z <= 500; z += 100)
g.fillRect(x + z, 0, 20, 20);
timer.start();
}
public void actionPerformed(ActionEvent e) {
if (x < 500) {
velX = velX;
x = x + velX;
}
else {
x = 0;
}
repaint();
}
}
I can't really figure out what going on in your code, but I reproduce the effect you're looking for. You can examine it. It runs.
What i did was make 5 different xPoints. You could have done this by using an array of int but I thouhgt it would be easier to read this way.
For each xPoint, I incremented each timer iteration. If the xPoint reached the screen width, I made it equal 0. Then repaint. I did that for all the points.
Code Edited: to use arrays and loops
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class GreenRects extends JPanel {
private static final int SCREEN_WIDTH = 500;
private static final int SCREEN_HEIGHT = 500;
private static final int OFFSET = 100;
private static final int SIZE = 20;
private static final int INC = 5;
int[] xPoints = new int[5];
public GreenRects() {
int x = 0;
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] = x;
x += OFFSET;
}
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < xPoints.length; i++) {
if (xPoints[i] + INC < SCREEN_WIDTH) {
xPoints[i] += INC;
} else {
xPoints[i] = 0;
}
}
repaint();
}
});
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
g.setColor(Color.green);
for (int i = 0; i < xPoints.length; i++) {
g.fillRect(xPoints[i], 0, SIZE, SIZE);
}
}
public Dimension getPreferredSize() {
return new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT);
}
public static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new GreenRects());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can try this code in if clause
if (x < 80)
{
velX = velX;
x = x + velX;
}