Howcome this code below wont work? I want to add new Ovals to the ArrayList every 200 ms and display them and run them one by one. It works fine when Im running one particle s.runner(); but it doesnt seem to run all my particles.
MAIN:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.Timer;
public class ExempelGraphics extends JFrame implements ActionListener {
Timer t;
private int inc = 0;
ArrayList<Surface> particle = new ArrayList<>();
Surface s;
public ExempelGraphics() {
t = new Timer(10, this);
t.start();
s = new Surface(10, 10);
initUI();
}
private void initUI() {
add(s);
setSize(350, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
// s.runner();
// add
if (inc++ % 20 == 0) {
particle.add(new Surface(10, 10));
}
// display
for (int i = 0; i < particle.size(); i++) {
Surface p = particle.get(i);
p.runner();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ExempelGraphics ex = new ExempelGraphics();
ex.setVisible(true);
}
});
}
}
GRAPHICS:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Surface extends JPanel {
private int locX = 0;
private int locY = 0;
public Surface(int locX, int locY) {
this.locX = locX;
this.locY = locY;
}
public void runner() {
locX = locX + 1;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval(locX, locY, 10, 10);
}
}
I think that you're program structure is broken. You should have only one JPanel here that does the drawing, that has its paintComponent overridden, and your Surface class should be a logical class and not a component class -- in other words, don't have it extend JPanel, and give it a public void draw(Graphics g) method where you draw the oval. Then have the drawing JPanel hold an ArrayList of these surfaces, and in the main JPanel's paintComponent method, iterate through the surfaces, calling each one's draw method.
Also your Timer's delay is not realistic and is too small. 15 would be much more realistic.
Also, don't call repaint() from within surface, since that will generate too many repaint calls unnecessarily. Instead call it from within the Timer's ActionListener after calling the runner methods on all the Surface objects.
Also note that every time you add a component to a JFrame's contentPane in a default fashion, you cover up the previously added components. If you go by my recommendations above, this isn't an issue since you'd only be adding that single JPanel to it.
For example:
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.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class ExampleGraphics2 extends JPanel {
private static final int PREF_W = 650;
private static final int PREF_H = 500;
private static final int TIMER_DELAY = 20;
private List<Surface> surfaces = new ArrayList<>();
public ExampleGraphics2() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Surface surface : surfaces) {
surface.draw(g);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
index++;
index %= 20;
if (index == 0) {
surfaces.add(new Surface(10, 10));
}
for (Surface surface : surfaces) {
surface.runner();
}
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Example Graphics 2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ExampleGraphics2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
package foo1;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class Surface {
private int locX = 0;
private int locY = 0;
public Surface(int locX, int locY) {
this.locX = locX;
this.locY = locY;
}
public void runner() {
locX = locX + 1;
}
public void draw(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval(locX, locY, 10, 10);
}
}
Related
I have an image I am rotating when the user clicks on a button. But it is not working.
I would like to see the image rotating gradually to 90 degrees till it stops but it doesn't. The image must rotate 90 degrees gradually when the button is clicked.
I have created an SSCCE to demonstrate the problem. Please replace the image in the CrossingPanelSSCE class with any image of your choice. Just put the image in your images folder and name it images/railCrossing.JPG.
RotateButtonSSCE
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
public class RotateButtonSSCE extends JPanel implements ActionListener{
private JButton rotate = new JButton("Rotate");
private VisualizationPanelSSCE vis = new VisualizationPanelSSCE();
public RotateButtonSSCE() {
this.setBorder(BorderFactory.createTitledBorder("Rotate Button "));
this.rotate.addActionListener(this);
this.add(rotate);
}
public void actionPerformed(ActionEvent ev) {
vis.rotatetheCrossing();
}
}
CrossingPanelSSCE
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
public class CrossingPanelSSCE extends JPanel{
private static final long serialVersionUID = 1L;
// private data members
private Image crossingImage;
private int currentRotationAngle;
private int imageWidth;
private int imageHeight;
private AffineTransform affineTransform;
private boolean clockwise;
private static int ROTATE_ANGLE_OFFSET = 2;
private int xCoordinate;
private int yCoordinate;
private static javax.swing.Timer timer;
private void initialize(){
this.crossingImage = Toolkit.getDefaultToolkit().getImage("images/railCrossing.JPG");
this.imageWidth = this.getCrossingImage().getWidth(this);
this.imageHeight = this.getCrossingImage().getHeight(this);
this.affineTransform = new AffineTransform();
currentRotationAngle = 90;
timer = new javax.swing.Timer(20, new MoveListener());
}
public CrossingPanelSSCE(int x, int y) {
this.setxCoordinate(x);
this.setyCoordinate(y);
this.setPreferredSize(new Dimension(50, 50));
this.setBackground(Color.red);
TitledBorder border = BorderFactory.createTitledBorder("image");
this.setLayout(new FlowLayout());
this.initialize();
}
public void paintComponent(Graphics grp){
Rectangle rect = this.getBounds();
Graphics2D g2d = (Graphics2D)grp;
g2d.setColor(Color.BLACK);
this.getAffineTransform().setToTranslation(this.getxCoordinate(), this.getyCoordinate());
//rotate with the rotation point as the mid of the image
this.getAffineTransform().rotate(Math.toRadians(this.getCurrentRotationAngle()), this.getCrossingImage().getWidth(this) /2,
this.getCrossingImage().getHeight(this)/2);
//draw the image using the AffineTransform
g2d.drawImage(this.getCrossingImage(), this.getAffineTransform(), this);
}
public void rotateCrossing(){
System.out.println("CurrentRotationAngle: " + currentRotationAngle);
this.currentRotationAngle += ROTATE_ANGLE_OFFSET;
//int test = currentRotationAngle % 90;
if(currentRotationAngle % 90 == 0){
setCurrentRotationAngle(currentRotationAngle);
timer.stop();
}
//repaint the image panel
repaint();
}
void start() {
if (timer != null) {
timer.start();
}
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
rotateCrossing();
}
}
public Image getCrossingImage() {
return crossingImage;
}
public void setCrossingImage(Image crossingImage) {
this.crossingImage = crossingImage;
}
public int getCurrentRotationAngle() {
return currentRotationAngle;
}
public void setCurrentRotationAngle(int currentRotationAngle) {
this.currentRotationAngle = currentRotationAngle;
}
public int getImageWidth() {
return imageWidth;
}
public void setImageWidth(int imageWidth) {
this.imageWidth = imageWidth;
}
public int getImageHeight() {
return imageHeight;
}
public void setImageHeight(int imageHeight) {
this.imageHeight = imageHeight;
}
public AffineTransform getAffineTransform() {
return affineTransform;
}
public void setAffineTransform(AffineTransform affineTransform) {
this.affineTransform = affineTransform;
}
public boolean isClockwise() {
return clockwise;
}
public void setClockwise(boolean clockwise) {
this.clockwise = clockwise;
}
public int getxCoordinate() {
return xCoordinate;
}
public void setxCoordinate(int xCoordinate) {
this.xCoordinate = xCoordinate;
}
public int getyCoordinate() {
return yCoordinate;
}
public void setyCoordinate(int yCoordinate) {
this.yCoordinate = yCoordinate;
}
public javax.swing.Timer getTimer() {
return timer;
}
public void setTimer(javax.swing.Timer timer) {
this.timer = timer;
}
}
VisualizationPanelSSCE
import gui.CrossingPanel;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import application.Robot2;
public class VisualizationPanelSSCE extends JPanel{
//private data members
private GeneralPath path;
private Shape horizontalRail;
private Shape verticalRail;
private static int LENGTH = 350;
private CrossingPanelSSCE crossingP;
private void initializeComponents(){
this.path = new GeneralPath();
this.horizontalRail = this.createHorizontalRail();
this.verticalRail = this.createVerticalRail();
this.crossingP = new CrossingPanelSSCE(328,334);
}
public VisualizationPanelSSCE(){
this.initializeComponents();
this.setPreferredSize(new Dimension(400,400));
TitledBorder border = BorderFactory.createTitledBorder("Rotation");
this.setBorder(border);
}
public GeneralPath getPath() {
return path;
}
public void setPath(GeneralPath path) {
this.path = path;
}
private Shape createHorizontalRail(){
this.getPath().moveTo(5, LENGTH);
this.getPath().lineTo(330, 350);
this.getPath().closePath();
return this.getPath();
}
private Shape createVerticalRail(){
this.getPath().moveTo(350, 330);
this.getPath().lineTo(350,10);
this.getPath().closePath();
return this.getPath();
}
public void paintComponent(Graphics comp){
super.paintComponent(comp);
Graphics2D comp2D = (Graphics2D)comp;
BasicStroke pen = new BasicStroke(15.0F, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND);
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.setPaint(Color.black);
comp2D.setBackground(Color.WHITE);
comp2D.draw(this.horizontalRail);
this.crossingP.paintComponent(comp2D);
}
public CrossingPanelSSCE getCrossingP() {
return crossingP;
}
public void setCrossingP(CrossingPanelSSCE crossingP) {
this.crossingP = crossingP;
}
public void rotatetheCrossing(){
Runnable rotateCrossing1 = new Runnable(){
public void run() {
crossingP.start();
}
};
SwingUtilities.invokeLater(rotateCrossing1);
}
}
TestGUISSCE it contains the main method.
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.*;
public class TestGUISSCE{
private RotateButtonSSCE rotate = new RotateButtonSSCE();
private VisualizationPanelSSCE vision = new VisualizationPanelSSCE();
public void createGui(){
JFrame frame = new JFrame("Example");
frame.setSize(new Dimension(500, 500));
JPanel pane = new JPanel();
pane.add(this.vision);
pane.add(rotate);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.setVisible(true);
}
public static void main(String[] args) {
new TestGUISSCE().createGui();
}
}
In addition to #tulskiy's helpful observations, I would add two points:
Always construct your GUI on the event dispatch thread, as shown below.
An sscce should be a Short, Self Contained, Correct (Compilable), Example. As a convenience, don't require others to recreate multiple public classes; use top-level (package-private) or nested classes. As this is a graphics problem, use a public or synthetic image that reflects your problem.
In the example below, paintComponent() alters the graphics context's transform to effect the rotation. Note that the operations are performed in the (apparent) reverse of the declaration order: First, the image's center is translated to the origin; second, the image is rotated; third, the image's center is translated to the center of the panel. You can see the effect by resizing the panel.
Addendum: See also this alternative approach using AffineTransform.
package overflow;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
/**
* #see https://stackoverflow.com/questions/3371227
* #see https://stackoverflow.com/questions/3405799
*/
public class RotateApp {
private static final int N = 3;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(N, N, N, N));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 0; i < N * N; i++) {
frame.add(new RotatePanel());
}
frame.pack();
frame.setVisible(true);
}
});
}
}
class RotatePanel extends JPanel implements ActionListener {
private static final int SIZE = 256;
private static double DELTA_THETA = Math.PI / 90;
private final Timer timer = new Timer(25, this);
private Image image = RotatableImage.getImage(SIZE);
private double dt = DELTA_THETA;
private double theta;
public RotatePanel() {
this.setBackground(Color.lightGray);
this.setPreferredSize(new Dimension(
image.getWidth(null), image.getHeight(null)));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
image = RotatableImage.getImage(SIZE);
dt = -dt;
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.translate(this.getWidth() / 2, this.getHeight() / 2);
g2d.rotate(theta);
g2d.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2d.drawImage(image, 0, 0, null);
}
#Override
public void actionPerformed(ActionEvent e) {
theta += dt;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
}
class RotatableImage {
private static final Random r = new Random();
static public Image getImage(int size) {
BufferedImage bi = new BufferedImage(
size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.getHSBColor(r.nextFloat(), 1, 1));
g2d.setStroke(new BasicStroke(size / 8));
g2d.drawLine(0, size / 2, size, size / 2);
g2d.drawLine(size / 2, 0, size / 2, size);
g2d.dispose();
return bi;
}
}
The code for Rotated Icon uses the AffineTransform to rotate about its center.
this.crossingP.paintComponent(comp2D);
Never do this! Your CrossingPane is not added to any component, so repaint() doesn't have any effect. You can check it by adding prints in the paintComponent() method. SO you need to add CrossingPane to the VisualizationPane:
setLayout(new BorderLayout());
add(crossingP, BorderLayout.CENTER);
There are some issues with centering the image, but this shouldn't be hard to fix.
PS. Read again about layouts and painting.
I was programming a game similar to asteroid, but I do not understand how to spawn the asteroids in the background.
now i spawn an asteroid in the main class but i want create a class for the asteroid ho i do it?
MAIN CLASS
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if(flag_img)
{
background(g2d);
logo(g2d);
menu(g2d);
spaceship(g2d);
crediti(g2d);
}
}
background function(now)
private void background(Graphics2D g2d)
{
asteroidi_g_x+=r.nextInt(4);
asteroidi_g_y+=r.nextInt(1);
g2d.drawImage(asteroidi_g[0], asteroidi_g_x,asteroidi_g_y,this);
}
background function(what i want)
private void background(Graphics2D g2d)
{
asteroid asteroid = new asteroid[10];
}
and class asteroid
public class asteroid extends JPanel implements ActionListener
{
private BufferedImage images_asteroid;
private boolean flag_img;
private JPanel jp;
private int x,y;
public asteroide_grande(JPanel jp)
{
flag_img = true;
x = (jp.getWidth()/2);
y = (jp.getHeight()/2);
this.jp = jp;
try {
images_asterod = ImageIO.read(this.getClass().getResource("images/asteroid/a1.png"));
} catch(IOException e){flag = false;}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(flag_img)
{
g.drawImage(images_asteroid, 100, 100,this);
}
}
#Override
public void actionPerformed(ActionEvent e)
{
x=x-1;
y=y+1;
repaint();
}
method paintcomponent in class doesn't work
Don't have your Asteroid class extends JPanel. Instead have it as a class that model's asteroid data and has data manipulation methods. You'll also want to have a draw method that take a Graphic context. Something like
public class Asteroid {
Image asteroidImage;
JPanel panel;
int x, y;
public Asteroid(JPanel panel, Image image, int x, int y) {
this.panel = panel;
this.asteroidImage = image;
this.x = x;
this.y = y;
}
public void drawAsteroid(Graphics g) {
g.drawImage(asteroidImage, x, y, panel);
}
public void move() {
x += 5;
}
}
Now you have a model of an asteroid, you can create a List of Asteriod objects and iterate through them and use it's drawAsteroid method to paint them. Something like
public class GamePanel extends JPanel {
List<Asteroid> asteroids;
Image asteroidImage;
public GamePanel(){
asteroidImage = ...
asteroids = new ArrayList<>();
asteroids.add(new Asteroid(GamePanel.this, asteroidImage, 100, 100));
// add more asteriods
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Asteriod asteroid: asteriods) {
asteriod.drawAsteroid(g);
}
}
}
To animate them, you'll want to use a javax.swing.Timer. See more at How to Use Swing Timers. You'll want to manipulate the Asteriod data in the Timer. With the code provided above, you can just call it's move method, then call repaint(). Something like
public GamePanel(){
...
Timer timer = new Timer(30, new ActionListener(){
public void actionPerformed(ActionEvent e) {
Iterator it = asteroids.iterator();
while (it.hasNaext()) {
Asteroid asteriod = (Asteroid)it.next();
asteroid.move();
}
}
});
}
You can see a bunch more complete example of animating multiple objects here and here and here and here and here
Here's a full example. You'll see I included a Rectangle2D object in the Astreroid class. That's just if you want to check for collision detection. You should move the Rectangle2D x and/or y with every Asreroid movement of x and y. Then you can check if asteroid.rectangle.intersects(someOtherObject)
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class AsteroidBackground extends JPanel {
private static final int D_W = 400;
private static final int D_H = 600;
BufferedImage asteroidImage;
BufferedImage background;
List<Asteroid> asteroids;
Random random = new Random();
int countToAddAsteroid = 0;
int y;
public AsteroidBackground() {
try {
asteroidImage = ImageIO.read(getClass().getResource("/resources/small-asteroid.png"));
background = ImageIO.read(getClass().getResource("/resources/space.png"));
} catch (IOException ex) {
Logger.getLogger(AsteroidBackground.class.getName()).log(Level.SEVERE, null, ex);
}
asteroids = new ArrayList<>();
y = 0 - asteroidImage.getHeight();
Timer timer = new Timer(40, new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (countToAddAsteroid >= 25) {
int randX = random.nextInt(D_W);
asteroids.add(new Asteroid(AsteroidBackground.this, asteroidImage, randX, y));
countToAddAsteroid = 0;
}
countToAddAsteroid++;
Iterator it = asteroids.iterator();
while (it.hasNext()) {
Asteroid asteroid = (Asteroid)it.next();
if (asteroid.y >= D_H) {
it.remove();
} else {
asteroid.move();
}
}
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, this);
for (Asteroid asteroid : asteroids) {
asteroid.drawAsteroid(g);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
public class Asteroid {
Rectangle2D rectangle;
Image asteroidImage;
JPanel panel;
int x, y;
public Asteroid(JPanel panel, Image image, int x, int y) {
this.panel = panel;
this.asteroidImage = image;
this.x = x;
this.y = y;
rectangle = new Rectangle2D.Double(
x, y, image.getWidth(panel), image.getHeight(panel));
}
public void drawAsteroid(Graphics g) {
g.drawImage(asteroidImage, x, y, panel);
}
public void move() {
y += 5;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new AsteroidBackground());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
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've tried to create Graphic object that this object was working timer/timerTask.I could work for a single object but if I create new object it could not work as I want. I want to work it like tetris.
Here's my code
That's my first class prosek
import javax.swing.*;
import java.awt.*;
import java.util.Timer;
import java.util.*;
public class prosek extends JPanel{
public static int boyut; // size
public static int koordinatx; //coordx
public static int koordinaty; //coordy
public static boolean tekrar; //repeat
public static int yukseklik; //height
private Timer timer;
private LinkedList<TimerTask> taskList=new LinkedList<TimerTask>();
public prosek(){
yukseklik=140;
tekrar=false;
koordinatx=0;
koordinaty=-20;
boyut=20;
startSampling();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
g2d.setColor(Color.RED);
g2d.fillRect(koordinatx, koordinaty, boyut+1, boyut+1);
g2d.dispose();
}
public void moveRectangle()
{
if(yukseklik<=140)
{
if(koordinaty<140) koordinaty=koordinaty+boyut;
else
{
yukseklik-=20;
stopSampling();
}
}
}
void startSampling(){
TimerTask task=new TimerTask(){
public void run() {
moveRectangle();
repaint();
}
};
Timer timer=new Timer();
timer.scheduleAtFixedRate(task,0, 500);
taskList.add(task);
}
void stopSampling(){
if(taskList.isEmpty()){
return;
}
taskList.removeFirst().cancel();
}
}
------------
That's my second class prosekt
import javax.swing.*;
import java.awt.*;
public class prosekt extends JFrame {
public prosekt(){
Container container=getContentPane();
container.setLayout(new GridLayout(0,1));
container.add(new prosek());
setSize(100,200);
setVisible(true);
add(container);
}
public static void main(String args[])
{
prosekt p=new prosekt();
}
}
I've made some changes to your code.
The first thing I did was to define a DropObject class. This makes it easier to have more than one drop object.
Here's the code for the DropObject class. It's a basic getter / setter model class. I used a Rectangle to hold the coordinates and size of the drop object.
DropObject class
import java.awt.Rectangle;
public class DropObject {
private int yukseklik; // height
private Rectangle object;
public DropObject(int yukseklik, int x, int y, int size) {
this.yukseklik = yukseklik;
this.object = new Rectangle(x, y, size, size);
}
public int getYukseklik() {
return yukseklik;
}
public void setYukseklik(int yukseklik) {
this.yukseklik = yukseklik;
}
public Rectangle getObject() {
return object;
}
public void setObject(Rectangle object) {
this.object = object;
}
}
I modified your JPanel class to use the DropObject class. I also capitalized Prosek, since Java class names are supposed to start with a capital letter.
I added the new objects in the moveRectangle method, just so you would see more than one object falling. The adding of new objects needs to take place somewhere else.
Prosek class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
public class Prosek extends JPanel {
private static final int yukseklik = 140;
private DropObject koordinat;
private List<DropObject> objects = new LinkedList<DropObject>();
private LinkedList<TimerTask> taskList = new LinkedList<TimerTask>();
public Prosek() {
koordinat = new DropObject(yukseklik, 0, -20, 20);
objects.add(koordinat);
startSampling();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
for (DropObject o : objects) {
Rectangle r = o.getObject();
g2d.fillRect(r.x, r.y, r.width, r.height);
}
}
public void moveRectangle() {
for (int i = (objects.size() - 1); i >= 0; i--) {
DropObject o = objects.get(i);
Rectangle r = o.getObject();
if (o.getYukseklik() <= 140) {
if (r.y < 140) {
r.y += r.height;
o.setObject(r);
} else {
o.setYukseklik(o.getYukseklik() - r.height);
// stopSampling();
}
}
if ((r.y >= 70) && (r.y <= 80)) {
objects.add(new DropObject(yukseklik, 0, -20, 20));
}
}
}
void startSampling() {
TimerTask task = new TimerTask() {
public void run() {
moveRectangle();
repaint();
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 500);
taskList.add(task);
}
void stopSampling() {
if (taskList.isEmpty()) {
return;
}
taskList.removeFirst().cancel();
}
}
I made some changes to your main class. I called the SwingUtilities invokeLater method to ensure that your Swing components were created and used on the Event Dispatch thread. I used a JFrame instead of extending JFrame. You should only extend a Swing component when you're overriding one of the component methods.
Composition over inheritance
Prosekt class
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Prosekt implements Runnable {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = frame.getContentPane();
container.setLayout(new GridLayout(0, 1));
container.add(new Prosek());
frame.setSize(100, 200);
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Prosekt());
}
}
I have an image I am rotating when the user clicks on a button. But it is not working.
I would like to see the image rotating gradually to 90 degrees till it stops but it doesn't. The image must rotate 90 degrees gradually when the button is clicked.
I have created an SSCCE to demonstrate the problem. Please replace the image in the CrossingPanelSSCE class with any image of your choice. Just put the image in your images folder and name it images/railCrossing.JPG.
RotateButtonSSCE
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
public class RotateButtonSSCE extends JPanel implements ActionListener{
private JButton rotate = new JButton("Rotate");
private VisualizationPanelSSCE vis = new VisualizationPanelSSCE();
public RotateButtonSSCE() {
this.setBorder(BorderFactory.createTitledBorder("Rotate Button "));
this.rotate.addActionListener(this);
this.add(rotate);
}
public void actionPerformed(ActionEvent ev) {
vis.rotatetheCrossing();
}
}
CrossingPanelSSCE
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
public class CrossingPanelSSCE extends JPanel{
private static final long serialVersionUID = 1L;
// private data members
private Image crossingImage;
private int currentRotationAngle;
private int imageWidth;
private int imageHeight;
private AffineTransform affineTransform;
private boolean clockwise;
private static int ROTATE_ANGLE_OFFSET = 2;
private int xCoordinate;
private int yCoordinate;
private static javax.swing.Timer timer;
private void initialize(){
this.crossingImage = Toolkit.getDefaultToolkit().getImage("images/railCrossing.JPG");
this.imageWidth = this.getCrossingImage().getWidth(this);
this.imageHeight = this.getCrossingImage().getHeight(this);
this.affineTransform = new AffineTransform();
currentRotationAngle = 90;
timer = new javax.swing.Timer(20, new MoveListener());
}
public CrossingPanelSSCE(int x, int y) {
this.setxCoordinate(x);
this.setyCoordinate(y);
this.setPreferredSize(new Dimension(50, 50));
this.setBackground(Color.red);
TitledBorder border = BorderFactory.createTitledBorder("image");
this.setLayout(new FlowLayout());
this.initialize();
}
public void paintComponent(Graphics grp){
Rectangle rect = this.getBounds();
Graphics2D g2d = (Graphics2D)grp;
g2d.setColor(Color.BLACK);
this.getAffineTransform().setToTranslation(this.getxCoordinate(), this.getyCoordinate());
//rotate with the rotation point as the mid of the image
this.getAffineTransform().rotate(Math.toRadians(this.getCurrentRotationAngle()), this.getCrossingImage().getWidth(this) /2,
this.getCrossingImage().getHeight(this)/2);
//draw the image using the AffineTransform
g2d.drawImage(this.getCrossingImage(), this.getAffineTransform(), this);
}
public void rotateCrossing(){
System.out.println("CurrentRotationAngle: " + currentRotationAngle);
this.currentRotationAngle += ROTATE_ANGLE_OFFSET;
//int test = currentRotationAngle % 90;
if(currentRotationAngle % 90 == 0){
setCurrentRotationAngle(currentRotationAngle);
timer.stop();
}
//repaint the image panel
repaint();
}
void start() {
if (timer != null) {
timer.start();
}
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
rotateCrossing();
}
}
public Image getCrossingImage() {
return crossingImage;
}
public void setCrossingImage(Image crossingImage) {
this.crossingImage = crossingImage;
}
public int getCurrentRotationAngle() {
return currentRotationAngle;
}
public void setCurrentRotationAngle(int currentRotationAngle) {
this.currentRotationAngle = currentRotationAngle;
}
public int getImageWidth() {
return imageWidth;
}
public void setImageWidth(int imageWidth) {
this.imageWidth = imageWidth;
}
public int getImageHeight() {
return imageHeight;
}
public void setImageHeight(int imageHeight) {
this.imageHeight = imageHeight;
}
public AffineTransform getAffineTransform() {
return affineTransform;
}
public void setAffineTransform(AffineTransform affineTransform) {
this.affineTransform = affineTransform;
}
public boolean isClockwise() {
return clockwise;
}
public void setClockwise(boolean clockwise) {
this.clockwise = clockwise;
}
public int getxCoordinate() {
return xCoordinate;
}
public void setxCoordinate(int xCoordinate) {
this.xCoordinate = xCoordinate;
}
public int getyCoordinate() {
return yCoordinate;
}
public void setyCoordinate(int yCoordinate) {
this.yCoordinate = yCoordinate;
}
public javax.swing.Timer getTimer() {
return timer;
}
public void setTimer(javax.swing.Timer timer) {
this.timer = timer;
}
}
VisualizationPanelSSCE
import gui.CrossingPanel;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
import application.Robot2;
public class VisualizationPanelSSCE extends JPanel{
//private data members
private GeneralPath path;
private Shape horizontalRail;
private Shape verticalRail;
private static int LENGTH = 350;
private CrossingPanelSSCE crossingP;
private void initializeComponents(){
this.path = new GeneralPath();
this.horizontalRail = this.createHorizontalRail();
this.verticalRail = this.createVerticalRail();
this.crossingP = new CrossingPanelSSCE(328,334);
}
public VisualizationPanelSSCE(){
this.initializeComponents();
this.setPreferredSize(new Dimension(400,400));
TitledBorder border = BorderFactory.createTitledBorder("Rotation");
this.setBorder(border);
}
public GeneralPath getPath() {
return path;
}
public void setPath(GeneralPath path) {
this.path = path;
}
private Shape createHorizontalRail(){
this.getPath().moveTo(5, LENGTH);
this.getPath().lineTo(330, 350);
this.getPath().closePath();
return this.getPath();
}
private Shape createVerticalRail(){
this.getPath().moveTo(350, 330);
this.getPath().lineTo(350,10);
this.getPath().closePath();
return this.getPath();
}
public void paintComponent(Graphics comp){
super.paintComponent(comp);
Graphics2D comp2D = (Graphics2D)comp;
BasicStroke pen = new BasicStroke(15.0F, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND);
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.setPaint(Color.black);
comp2D.setBackground(Color.WHITE);
comp2D.draw(this.horizontalRail);
this.crossingP.paintComponent(comp2D);
}
public CrossingPanelSSCE getCrossingP() {
return crossingP;
}
public void setCrossingP(CrossingPanelSSCE crossingP) {
this.crossingP = crossingP;
}
public void rotatetheCrossing(){
Runnable rotateCrossing1 = new Runnable(){
public void run() {
crossingP.start();
}
};
SwingUtilities.invokeLater(rotateCrossing1);
}
}
TestGUISSCE it contains the main method.
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.*;
public class TestGUISSCE{
private RotateButtonSSCE rotate = new RotateButtonSSCE();
private VisualizationPanelSSCE vision = new VisualizationPanelSSCE();
public void createGui(){
JFrame frame = new JFrame("Example");
frame.setSize(new Dimension(500, 500));
JPanel pane = new JPanel();
pane.add(this.vision);
pane.add(rotate);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.setVisible(true);
}
public static void main(String[] args) {
new TestGUISSCE().createGui();
}
}
In addition to #tulskiy's helpful observations, I would add two points:
Always construct your GUI on the event dispatch thread, as shown below.
An sscce should be a Short, Self Contained, Correct (Compilable), Example. As a convenience, don't require others to recreate multiple public classes; use top-level (package-private) or nested classes. As this is a graphics problem, use a public or synthetic image that reflects your problem.
In the example below, paintComponent() alters the graphics context's transform to effect the rotation. Note that the operations are performed in the (apparent) reverse of the declaration order: First, the image's center is translated to the origin; second, the image is rotated; third, the image's center is translated to the center of the panel. You can see the effect by resizing the panel.
Addendum: See also this alternative approach using AffineTransform.
package overflow;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
/**
* #see https://stackoverflow.com/questions/3371227
* #see https://stackoverflow.com/questions/3405799
*/
public class RotateApp {
private static final int N = 3;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(N, N, N, N));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 0; i < N * N; i++) {
frame.add(new RotatePanel());
}
frame.pack();
frame.setVisible(true);
}
});
}
}
class RotatePanel extends JPanel implements ActionListener {
private static final int SIZE = 256;
private static double DELTA_THETA = Math.PI / 90;
private final Timer timer = new Timer(25, this);
private Image image = RotatableImage.getImage(SIZE);
private double dt = DELTA_THETA;
private double theta;
public RotatePanel() {
this.setBackground(Color.lightGray);
this.setPreferredSize(new Dimension(
image.getWidth(null), image.getHeight(null)));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
image = RotatableImage.getImage(SIZE);
dt = -dt;
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.translate(this.getWidth() / 2, this.getHeight() / 2);
g2d.rotate(theta);
g2d.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2d.drawImage(image, 0, 0, null);
}
#Override
public void actionPerformed(ActionEvent e) {
theta += dt;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
}
class RotatableImage {
private static final Random r = new Random();
static public Image getImage(int size) {
BufferedImage bi = new BufferedImage(
size, size, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.getHSBColor(r.nextFloat(), 1, 1));
g2d.setStroke(new BasicStroke(size / 8));
g2d.drawLine(0, size / 2, size, size / 2);
g2d.drawLine(size / 2, 0, size / 2, size);
g2d.dispose();
return bi;
}
}
The code for Rotated Icon uses the AffineTransform to rotate about its center.
this.crossingP.paintComponent(comp2D);
Never do this! Your CrossingPane is not added to any component, so repaint() doesn't have any effect. You can check it by adding prints in the paintComponent() method. SO you need to add CrossingPane to the VisualizationPane:
setLayout(new BorderLayout());
add(crossingP, BorderLayout.CENTER);
There are some issues with centering the image, but this shouldn't be hard to fix.
PS. Read again about layouts and painting.