How can I paint something in a frame in an event handler in java? Because I want to write the game Breakout and there I would need to repaint the entire screen in the event handler.
public void mouseMoved(MouseEvent e, Graphics g)
{
// if mouse was moved then rearrange paddle
double x = e.getX() - paddle_width;
double y = e.getY() - paddle_height;
this.repaint();
g.setColor(Color.BLACK);
g.fillRect(x, y, paddle_width, paddle_height);
}
You can create your drawing panel extending JPanel and override the paintComponent.
Then you can have a model (By model i mean the data about what you want to paint)
Then you can add MouseMotionListener which would manipulate your model.
Notify the model changes to the drawing panel so that it will update the painting based on the model changes.
The below code should help you progress.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Demo extends JFrame {
public static void main(String[] args) {
Demo frame = new Demo();
frame.setVisible(true);
}
public Demo() throws HeadlessException {
super();
init();
}
private void init() {
Point start = new Point(0, 0);
Paddle paddle = new Paddle(start, 20, 20);
DrawingPanel drawingPanel = new DrawingPanel(paddle);
setContentPane(drawingPanel);
pack();
}
class DrawingPanel extends JPanel implements MouseMotionListener {
private Paddle paddle;
public DrawingPanel(Paddle paddle) {
super();
this.paddle = paddle;
this.addMouseMotionListener(this);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(paddle.point.x, paddle.point.y, paddle.width, paddle.height);
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
paddle.point = new Point(e.getX(), e.getY());
repaint();
}
}
class Paddle {
Point point;
Integer height, width;
public Paddle(Point point, Integer height, Integer width) {
super();
this.point = point;
this.height = height;
this.width = width;
}
}
}
Related
I have a project where I need to create a GUI in Java that creates a circle on mouse-click and and continues to make trailing circles as the mouse is dragged through the frame. I've been given reference to multiple threads on here but none have seemed to help me do what I need to do. So far I've got a static circle added to my JFrame, but I want to make the multiple circles show on a JPanel in that frame. I'm stuck after trying many different angles. As of now I just need to be able to click once and create a circle.
public class Theremin extends JFrame implements ActionListener, MouseListener{
private JPanel windowArea;
private int x, y;
private static final long serialVersionUID = 1L;
public Theremin() {
}
public static void main(String[] args) {
Theremin Frame = new Theremin();
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
panel.setLayout(null);
Frame.add(panel);
Frame.pack();
Frame.setLocationRelativeTo(null);
Frame.setVisible(true);
}
private static class MyPanel extends JPanel {
public void paint(Graphics g) {
Graphics2D gObj = (Graphics2D)g;
Shape disk = new Ellipse2D.Double(10, 10, 100, 100);
gObj.setColor(new Color(255, 0, 0, 120));
gObj.fill(disk);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(700, 600);
}
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Here's a GUI that I put together.
Each mouse click creates a circle.
When I create a Swing GUI, or any Java application, I use the model / view / controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one part of the application at a time.
For a Swing GUI, the MVC pattern means:
The view reads from the model.
The view does not update the model.
The controller updates the model and repaints / revalidates the view.
The model consists of two classes, Circles and Circle. The Circle class defines a circle with a Point center, int radius, and a Color color. Because Circle is a class, I can define as many instances (circles) as I want.
The Circles class holds a List of Circle instances.
The view consists of a JFrame and a drawing JPanel. The paintComponent method of the drawing JPanel paints circles. Period. We create the circles in the controller class.
The controller class CirclesListener creates the circles and repaints the drawing JPanel. All of the circles are redrawn each and every time the drawing JPanel is repainted.
An instance of the JFrame class and the application model class is passed to the controller CirclesListener class. This allows the class to create a new circle and repaint the drawing JPanel.
Here's the complete runnable code.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseClickCircleGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MouseClickCircleGUI());
}
private Circles circles;
private DrawingPanel drawingPanel;
public MouseClickCircleGUI() {
this.circles = new Circles();
}
#Override
public void run() {
JFrame frame = new JFrame("Circles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel(this, circles);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void repaint() {
drawingPanel.repaint();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final Circles circles;
public DrawingPanel(MouseClickCircleGUI frame, Circles circles) {
this.circles = circles;
setBackground(Color.WHITE);
setPreferredSize(new Dimension(500, 500));
addMouseListener(new CirclesListener(frame, circles));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(3f));
for (Circle circle : circles.getCircles()) {
Point p = circle.getCenter();
int radius = circle.getRadius();
g2.setColor(circle.getColor());
g2.drawOval(p.x - radius, p.y - radius,
2 * radius, 2 * radius);
}
}
}
public class CirclesListener extends MouseAdapter {
private final Circles circles;
private final MouseClickCircleGUI frame;
public CirclesListener(MouseClickCircleGUI frame, Circles circles) {
this.frame = frame;
this.circles = circles;
}
#Override
public void mouseReleased(MouseEvent event) {
circles.addCircle(new Circle(event.getPoint(), 30, Color.BLACK));
frame.repaint();
}
}
public class Circles {
private final List<Circle> circles;
public Circles() {
this.circles = new ArrayList<>();
}
public void addCircle(Circle circle) {
this.circles.add(circle);
}
public List<Circle> getCircles() {
return circles;
}
}
public class Circle {
private final int radius;
private final Color color;
private final Point center;
public Circle(Point center, int radius, Color color) {
this.center = center;
this.radius = radius;
this.color = color;
}
public int getRadius() {
return radius;
}
public Point getCenter() {
return center;
}
public Color getColor() {
return color;
}
}
}
The idea here is to:
capture point
add it to list
repaint component
Here is how I have done it, this is a sample code.
package com.company;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Theremin frame = new Theremin();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
panel.initListeners();
panel.setLayout(null);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.addWindowListener(new WindowListener() {
#Override
public void windowOpened(WindowEvent e) {
}
#Override
public void windowClosing(WindowEvent e) {
panel.releaseListener();
}
#Override
public void windowClosed(WindowEvent e) {
}
#Override
public void windowIconified(WindowEvent e) {
}
#Override
public void windowDeiconified(WindowEvent e) {
}
#Override
public void windowActivated(WindowEvent e) {
}
#Override
public void windowDeactivated(WindowEvent e) {
}
});
}
}
class MyPanel extends JPanel implements MouseListener, MouseMotionListener {
private Graphics graphics;
private List<CircleData> shapeList = new ArrayList<>();
private Graphics2D gObj;
public MyPanel() {
}
#Override
public void paint(Graphics g) {
this.graphics = g;
gObj = (Graphics2D) g;
System.out.println("called paint with times: " + times++);
for (CircleData circleData : shapeList) {
Rectangle rectangle = circleData.rectangle;
Color color = circleData.color;
Shape disk = new Ellipse2D.Double(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
gObj.setColor(color);
gObj.fill(disk);
}
}
Color randomColor() {
int red = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
return new Color(red, green, blue);
}
static int times = 0;
#Override
public Dimension getPreferredSize() {
return new Dimension(700, 600);
}
public void initListeners() {
System.out.println("added default listeners");
addMouseListener(this);
addMouseMotionListener(this);
}
public void releaseListener() {
System.out.println("removed default listeners");
removeMouseListener(this);
removeMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
float x = e.getX();
float y = e.getY();
String cordinates = String.format("(%f, %f)", x, y);
System.out.println("Mouse Clicked # " + cordinates);
shapeList.add(new CircleData(new Rectangle((int) x, (int) y, 50, 50), randomColor()));
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
float x = e.getX();
float y = e.getY();
String cordinates = String.format("(%f, %f)", x, y);
System.out.println("Mouse Dragged # " + cordinates);
System.out.println("Mouse Dragged # " + shapeList.size());
shapeList.add(new CircleData(new Rectangle((int) x, (int) y, 50, 50), randomColor()));
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
class CircleData {
Rectangle rectangle;
Color color;
public CircleData(Rectangle rectangle, Color color) {
this.rectangle = rectangle;
this.color = color;
}
}
class Theremin extends JFrame {
private static final long serialVersionUID = 1L;
public Theremin() {
}
}
I'm a beginner in Java and this time I'm trying to learn more by finding code examples and editing them, for example from this website. I have a JFrame and each time it (or more precise the JPanel in it) is clicked on, a circle is drawn which will grow/expand outwards like a water ripple. Each circle starts with a certain radius and will be removed or redrawn when reaching a bigger radius (I chose radius "r" from 10 to 200). I have two programs for this which almost work but are missing something. If I'm correct, I might also know what their problems are but I can't figure out how to solve them:
One generates growing circles but all of them have the same size, no matter when they're generated, since I can't find out how to assign the radius to a single circle. The code is adapted from here:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Ripples extends JPanel implements ActionListener{
public int r = 10;
private ArrayList<Point> p;
public Ripples() {
p = new ArrayList<>();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
p.add(new Point(e.getX(), e.getY()));
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.CYAN);
for (Point pt : p) {
g2.drawOval(pt.x-r, pt.y-r, 2*r, 2*r);
}
}
#Override
public void actionPerformed(ActionEvent evt) {
if(r<200){
r++;
} else {
r = 10;
}
repaint();
}
public static void Gui() {
JFrame f = new JFrame();
Ripples p = new Ripples();
p.setBackground(Color.WHITE);
f.setContentPane(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(500,300);
f.setVisible(true);
Timer t = new Timer(20,p);
t.start();
}
public static void main(String[] args) {
Gui();
}
}
The other program(I've forgotten where I got it from) has circles with different radii depending on when they were generated, however the circles "flicker", because -as far as I understand- they are all processed at the same time, because the code doesn't include an Array to store and update each circle individually like the one above does:
import java.awt.Color;
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.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Ripples extends JPanel {
int x,y;
int r = 10;
public Ripples(int x, int y) {
this.x = x;
this.y = y;
Timer t = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (r<200) {
r++;
} else {
r=10;
}
revalidate();
repaint();
}
});
t.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.CYAN);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawOval(x-r,y-r,2*r,2*r);
}
public static void Gui() {
JFrame f = new JFrame("Water Ripples");
JPanel p0 = new JPanel();
p0.setBackground(Color.WHITE);
f.add(p0);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBounds(100,100,600,500);
f.setVisible(true);
f.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
Ripples rG = new Ripples(e.getX(), e.getY());
rG.setBackground(Color.WHITE);
f.add(rG);
}
});
}
public static void main(String[] args) {
Gui();
}
}
So how can I solve this so that I get the circles growing independent from each other? I'd prefer a solution/improvement/hint for the upper code because I think its structured better than the second one. Also, I apologize for not splitting the code into more classes and for possibly not sticking to naming conventions. I appreciate your help, thank you very much!
I added a Circle class to your Ripples code. This allows the ActionListener to treat each circle independently.
I started the GUI with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
Here's the code.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Ripples extends JPanel implements ActionListener {
private List<Circle> circles;
public Ripples() {
circles = new ArrayList<>();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent event) {
circles.add(new Circle(event.getPoint()));
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.CYAN);
g2.setStroke(new BasicStroke(3f));
for (Circle circle : circles) {
Point p = circle.getCenter();
int radius = circle.getRadius();
g2.drawOval(p.x - radius, p.y - radius,
2 * radius, 2 * radius);
}
}
#Override
public void actionPerformed(ActionEvent evt) {
for (Circle circle : circles) {
circle.incrementRadius();
}
repaint();
}
public static void createGUI() {
JFrame f = new JFrame("Ripples");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Ripples p = new Ripples();
p.setBackground(Color.WHITE);
p.setPreferredSize(new Dimension(500, 500));
f.setContentPane(p);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
Timer t = new Timer(20, p);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createGUI();
}
});
}
public class Circle {
private int radius;
private final Point center;
public Circle(Point center) {
this.center = center;
this.radius = 10;
}
public void incrementRadius() {
radius += 1;
radius = (radius > 200) ? 10 : radius;
}
public int getRadius() {
return radius;
}
public Point getCenter() {
return center;
}
}
}
Edited to add:
I reworked the Ripples class code to separate the concerns. I created a DrawingPanel class to hold the drawing panel, a RipplesListener class to hold the MouseAdapter code, an Animation class to hold the Runnable that runs the animation of the circles, a RipplesModel class to hold the List of Circle instances, and finally, the Circle class.
I could have used a Swing Timer for the animation, but I'm more familiar with creating and running my own animation thread.
Yes, this code is more complicated than the original example. The coding style used here can be carried into larger, more complex Swing GUI development.
Here's the revised code. I hope it's a better example.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Ripples implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Ripples());
}
private Animation animation;
private DrawingPanel drawingPanel;
private RipplesModel model;
public Ripples() {
model = new RipplesModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Ripples");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent event) {
stopAnimation();
frame.dispose();
System.exit(0);
}
});
drawingPanel = new DrawingPanel(model);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
animation = new Animation(this, model);
new Thread(animation).start();
}
public void repaint() {
drawingPanel.repaint();
}
private void stopAnimation() {
if (animation != null) {
animation.setRunning(false);
}
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private RipplesModel model;
public DrawingPanel(RipplesModel model) {
this.model = model;
setBackground(Color.WHITE);
setPreferredSize(new Dimension(500, 500));
addMouseListener(new RipplesListener(model));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(3f));
List<Circle> circles = model.getCircles();
for (Circle circle : circles) {
Point p = circle.getCenter();
int radius = circle.getRadius();
g2.setColor(circle.getColor());
g2.drawOval(p.x - radius, p.y - radius,
2 * radius, 2 * radius);
}
}
}
public class RipplesListener extends MouseAdapter {
private RipplesModel model;
public RipplesListener(RipplesModel model) {
this.model = model;
}
#Override
public void mousePressed(MouseEvent event) {
model.addCircle(new Circle(event.getPoint(),
createColor()));
}
private Color createColor() {
Random random = new Random();
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
return new Color(r, g, b);
}
}
public class Animation implements Runnable {
private volatile boolean running;
private Ripples frame;
private RipplesModel model;
public Animation(Ripples frame, RipplesModel model) {
this.frame = frame;
this.model = model;
this.running = true;
}
#Override
public void run() {
while (running) {
sleep(20L);
incrementRadius();
}
}
private void incrementRadius() {
List<Circle> circles = model.getCircles();
for (Circle circle : circles) {
circle.incrementRadius();
}
repaint();
}
private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.repaint();
}
});
}
public synchronized void setRunning(boolean running) {
this.running = running;
}
}
public class RipplesModel {
private List<Circle> circles;
public RipplesModel() {
this.circles = new ArrayList<>();
}
public void addCircle(Circle circle) {
this.circles.add(circle);
}
public List<Circle> getCircles() {
return circles;
}
}
public class Circle {
private int radius;
private final Color color;
private final Point center;
public Circle(Point center, Color color) {
this.center = center;
this.color = color;
this.radius = 10;
}
public void incrementRadius() {
radius = (++radius > 200) ? 10 : radius;
}
public Color getColor() {
return color;
}
public int getRadius() {
return radius;
}
public Point getCenter() {
return center;
}
}
}
I'd prefer a solution/improvement/hint for the upper code
The second code is better because it uses:
a custom class to contain information about the object to be painted
an ArrayList to contain the objects to be painted
a Timer for the animation.
because I think its structured better than the second one.
Not a good reason. Use the code that provides the functionality that you require.
Restructure the code yourself. That is part of the learning experience.
Issues with the second code:
It doesn't compile. Why post code that doesn't compile? This implies you haven't even tested it.
the initial radius is assigned when the Position object is created.
When the Timer fires you need to iterate through the ArrayList to update the radius of each Position object.
The radius of the Position object is used in the painting code.
As an added change, maybe call the Position class Ripple. Then you can add another custom property for the Color of the ripple. Then when you add the Ripple to the ArrayList you randomly generate a Color. Then in the painting method you use the Color property of the Ripple class. This is how you make objects and painting more flexible and dynamic.
I'm trying to draw multiple rectangles on a panel. I created an ArrayList<Shape> and initialized in my constructor. In my paintComponent method, I draw a rectangle and then add it to the ArrayList. But when I do that, the drawing outcome on my panel turns out weird. As I drag to draw my first rectangle, I get this:
Here's part of my code:
public class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(final MouseEvent theEvent) {
myStartPoint = theEvent.getPoint();
repaint();
}
#Override
public void mouseReleased(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
public class MyMouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
/**
* Paints some rectangles.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
// for better graphics display
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(51, 0, 111));
g2d.setStroke(new BasicStroke(3));
final double x = myStartPoint.getX();
final double y = myStartPoint.getY();
final double xEnd = myEndPoint.getX();
final double yEnd = myEndPoint.getY();
if (xEnd> x && yEnd > y) {
final Shape rectangle = new Rectangle2D.
Double(x, y, xEnd - x, yEnd - y);
g2d.draw(rectangle);
myDrawings.add(rectangle);
}
for (Shape s : myDrawings) {
g2d.draw(s);
}
}
Don't do any code logic within paintComponent -- that method is for drawing and drawing only, and that is the source of your bug. Add the rectangle to the ArrayList in the mouse listener, on mouse release.
When I have done a similar project, I usually have one Rectangle field that I use to draw with the mouse listener on mouse drag, and which is draw within paintComponent. Then on mouse release I place that rectangle into the ArrayList, and set the class field as null.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class RectangleDraw extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color TEMP_RECT_COLOR = Color.LIGHT_GRAY;
private static final Color SHAPE_COLOR = Color.RED;
private Rectangle tempRect = null;
private List<Shape> shapes = new ArrayList<>();
public RectangleDraw() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw the temporary rectangle if not null
if (tempRect != null) {
g2.setColor(TEMP_RECT_COLOR);
g2.draw(tempRect);
}
// draw all the rectangles in the list
g2.setColor(SHAPE_COLOR);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
// size the GUI to my specification
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
// My mouse listener and mouse motion listener
private class MyMouse extends MouseAdapter {
private Point p1; // start point
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
// create temporary rectangle
tempRect = createRectangle(e);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempRect = null; // null temp rectangle and
// add rectangle to List
shapes.add(createRectangle(e));
repaint();
}
// create a rectangle from start point and current point
private Rectangle createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
Rectangle rect = new Rectangle(x, y, w, h);
return rect;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Rectangle Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RectangleDraw());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
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 been trying to do this assignment and for it to work I need the event mousePressed to work but for some reason it's not responding to the mouse. Its purpose is to paint another yellow circle when the mouse is pressed.
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.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CatchMonster extends JPanel
{
private int height = 300;
private int width = 600;
private final int delay = 4001;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY, xPoint, yPoint;
public CatchMonster() {
DotListener dot = new DotListener();
addMouseListener(dot);
timer = new Timer(delay, new timerListener());
x = 40;
y = 40;
moveX = moveY = 3;
setPreferredSize(new Dimension(width, height));
setBackground(Color.black);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
}
private class timerListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
Random gn = new Random();
x = gn.nextInt(width);
y = gn.nextInt(height);
repaint();
}
}
private class DotListener implements MouseListener
{
public void mousePressed(MouseEvent event)
{
repaint();
}
#Override
public void mouseClicked(MouseEvent event) {
}
#Override
public void mouseEntered(MouseEvent event) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent event) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent event) {
// TODO Auto-generated method stub
}
}
}
I need the event mousePressed to work but for some reason it's not responding to the mouse. Its purpose is to paint another yellow circle when the mouse is pressed.
But it won't paint another circle as all it does is call repaint(), and how is that going to paint anything new? If you want it to create another circle, you'll have to give it logic to do so. For instance, if you want to paint more than one yellow oval, you'll want to create an ArrayList of Point objects and add a Point into that array list in the mousePressed method. Then in the paintComponent method, you can iterate through the array list, painting ovals for each Point it contains.
In addition, you want to change this:
public void paintComponent(Graphics g) {
super.paintComponents(g); // this is not the "super" method of paintComponent
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
}
to this:
public void paintComponent(Graphics g) {
super.paintComponent(g); // See the difference?
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
}
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CatchMonster extends JPanel {
private int height = 300;
private int width = 600;
private final int delay = 4001;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY, xPoint, yPoint;
private List<Point> points = new ArrayList<Point>();
public CatchMonster() {
DotListener dot = new DotListener();
addMouseListener(dot);
timer = new Timer(delay, new timerListener());
x = 40;
y = 40;
moveX = moveY = 3;
setPreferredSize(new Dimension(width, height));
setBackground(Color.black);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
int radius = 30;
g.setColor(Color.green);
for (Point p : points) {
int x = p.x - radius;
int y = p.y - radius;
g.fillOval(x, y, 2 * radius, 2 * radius);
}
}
private class timerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Random gn = new Random();
x = gn.nextInt(width);
y = gn.nextInt(height);
repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CatchMonster());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class DotListener extends MouseAdapter {
public void mousePressed(MouseEvent event) {
points.add(event.getPoint());
repaint();
}
}
}