Adding shapes to JPanel on a button click - java

I have a Class Circle with a button and a Class with a jPanel what i want to do is when that button is clicked a circle will be drawn on the panel and each time i click that button and change x and y "some how not implemented here" i got a circle on the JPanel over and over .
How to do that, or is there a way to do what i descriped regardless of my code but i want the class circle to extends Shape.
public class Window{
private JFrame frame;
private JPanel panel = new JPanel();
Circle c = new Circle(frame, panel);
// some other buttons
.
.
// some code to set the panel grid bag constaraints and background then
frame.getContentPane().add(panel, gbc_panel);
}
then the Circle Class
public class Circle extends Shape implements ActionListener{
private JPanel Panel;
private GridBagConstraints gbc_btnCircle;
private JButton btnCircle;
public void setPanel(JPanel panel) {
Panel = panel;
}
public Circle(JFrame frame, JPanel panel){
btnCircle = new JButton("Circle");
// some code to set grid bag constraint then
frame.getContentPane().add(btnCircle, gbc_btnCircle);
setPanel(panel);
btnCircle.addActionListener(this);
}
public void paint(Graphics g) {
super.paintComponents(g);
g.setColor(Color.red);
g.fillOval(100, 100, 100, 100);
Panel.add(this);
}
public void actionPerformed(ActionEvent arg0) {
repaint();
}
}

You kinda have the wrong idea. In your drawing panel, you should have a List<Circle>. And in the paintComponent method of the drawing panel, you should iterate through the list to draw each circle
class Circle {
int x, int y, int width, int height;
public Circle (int x, int y, int width, int height) {
... set em
}
public void draw(Graphics g) {
g.fillOval(x, y, width, height);
}
}
class DrawingPanel extends JPanel {
List<Circle> circles = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Circle circle : circles) {
circle.draw(g);
}
}
// Dont forget to override public Dimension getPreferredSize()
}
To add more Circles to the list, just have a addCircle method in the DrawingPanel class
public void addCircle(Circle circle) {
circles.add(circle);
repaint();
}
As far as the button, you should be creating it in the Window class. In the ActionListener, just create a new Circle and add it the DrawingPanel by calling the addCircle method
An aside, Circle doesn't need the extend Shape. The Shape API already has an Ellipse2D class, which you can create circles from
class DrawingPanel extends JPanel {
List<Ellipse2D> circles = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
for (Ellipse2D circle : circles) {
g2.fill(circle);
}
g2.dispose();
}
// Dont forget to override public Dimension getPreferredSize()
}
See 2D Graphics
UPDATE: full example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CirclesDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new CirclesDemo();
}
});
}
public CirclesDemo() {
JFrame frame = new JFrame();
frame.add(panel);
frame.add(createButton(), BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private final DrawingPanel panel = new DrawingPanel();
private JButton createButton() {
JButton button = new JButton("Add Circle");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
int[] circleValues = generateRandomValues(300, 300, 50, 150);
int x = circleValues[0];
int y = circleValues[1];
int width = circleValues[2];
int height = width;
Circle circle = new Circle(x, y, width, height);
panel.addCircle(circle);
}
});
return button;
}
private int[] generateRandomValues(int maxX, int maxY,
int minSize, int maxSize) {
Random random = new Random();
int[] values = new int[3];
values[0] = random.nextInt(maxX);
values[1] = random.nextInt(maxY);
values[2] = Math.min(random.nextInt(maxSize) + minSize, maxSize);
return values;
}
class Circle {
int x, y, width, height;
public Circle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void draw(Graphics g) {
g.drawOval(x, y, width, height);
}
}
class DrawingPanel extends JPanel {
List<Circle> circles = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Circle circle : circles) {
circle.draw(g);
}
}
public void addCircle(Circle circle) {
circles.add(circle);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}

You are overriding the paint method of Circle. You need to be overriding the paint method of the panel.

Related

How to rotate something with Graphics2D

So I want to rotate this Rectangle I made
public void paint (Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillRect(10, 10, 30, 30);
g2.rotate(Math.toRadians(45)); //I tried this but doesn't seem to work...
}
How do I do that? Rotate as in rotate in 45* angle or 200* angle.
It really isn't that hard to rotate objects. Most of the code below is simply boiler plate to create the frames and panels. Here is a demo that shows two methods that were mentioned in the comments.
the left panel simply rotates the graphics context. This is, imo, the easiest method but it does not alter the object.
the right panel uses the AffineTransform to rotate the object. This actually changes the contents of the shape.
If the desire is to rotate an object in place it is necessary to ensure one is rotating about the middle of the image that is under rotation. In both cases below that would be (125,125) or the center of both the panels and the rectangle.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.LineBorder;
public class RotateRectangle extends JPanel {
JFrame frame = new JFrame();
double angle = 0;
MyPanel mypanel = new MyPanel();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new RotateRectangle().start());
}
public void start() {
Timer t = new Timer(0, (ae) -> {mypanel.rotateit(); frame.repaint();});
t.setDelay(30);
t.start();
}
public RotateRectangle() {
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.add(mypanel);
setBorder(new LineBorder(Color.red,2));
mypanel.setBorder(new LineBorder(Color.red, 2));
frame.pack();
// center on screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// visually smooth the lines
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.BLACK);
g2d.rotate(angle, 125,125);
g2d.drawRect(75, 75, 100, 100);
// adjust the amount of rotation per timer interval
angle += Math.PI / 200;
g2d.dispose();
}
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
class MyPanel extends JPanel {
Polygon polygon = new Polygon();
// amount to rotate
double angle = Math.PI / 200;
Shape shape = polygon;
AffineTransform af = new AffineTransform();
public MyPanel() {
af.rotate(angle, 125,125);
polygon.addPoint(75,175);
polygon.addPoint(175,175);
polygon.addPoint(175,75);
polygon.addPoint(75,75);
}
public void rotateit() {
shape = af.createTransformedShape(shape);
}
public void paintComponent(Graphics g) {
if (shape == null) {
return;
}
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// visually smooth the lines
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.BLACK);
g2d.draw(shape);
}
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
Following up on my comment, I created the following GUI.
I used math to calculate the four endpoints of a rotated rectangle and used the Graphics2D fillPolygon method to draw the rectangle.
The buttons at the bottom of the GUI allow you to rotate the rectangle on the center point or the upper left endpoint.
I created a drawing JPanel to draw the rectangle. All the paintComponent method of the drawing JPanel does is draw the Polygon returned by the application model.
The application model is a key part of this application. I create a plain Java getter / setter class. I start with a java.awt.Rectangle and use polar coordinates to rotate the rectangle. I convert the polar coordinates back to cartesian coordinates to get the four endpoints of the Polygon.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class RotatingRectangle implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new RotatingRectangle());
}
private DrawingPanel drawingPanel;
private JButton centerButton;
private JButton endPointButton;
private RotatedRectangle rotatedRectangle;
public RotatingRectangle() {
this.rotatedRectangle = new RotatedRectangle(Color.BLUE,
new Rectangle(200, 200, 100, 50));
}
#Override
public void run() {
JFrame frame = new JFrame("Rotating Rectangle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.drawingPanel = new DrawingPanel(rotatedRectangle);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
ButtonListener listener = new ButtonListener(this, rotatedRectangle);
centerButton = new JButton("Rotate on center point");
centerButton.addActionListener(listener);
panel.add(centerButton);
endPointButton = new JButton("Rotate on end point");
endPointButton.addActionListener(listener);
endPointButton.setPreferredSize(centerButton.getPreferredSize());
panel.add(endPointButton);
return panel;
}
public void repaint() {
drawingPanel.repaint();
}
public JButton getCenterButton() {
return centerButton;
}
public JButton getEndPointButton() {
return endPointButton;
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private RotatedRectangle rotatedRectangle;
public DrawingPanel(RotatedRectangle rotatedRectangle) {
this.rotatedRectangle = rotatedRectangle;
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(400, 400));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Polygon polygon = rotatedRectangle.getRectangle();
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(rotatedRectangle.getColor());
g2d.fillPolygon(polygon);
}
}
public class ButtonListener implements ActionListener {
private final RotatingRectangle frame;
private final RotatedRectangle model;
private Timer timer;
public ButtonListener(RotatingRectangle frame, RotatedRectangle model) {
this.frame = frame;
this.model = model;
}
#Override
public void actionPerformed(ActionEvent event) {
if (timer != null) {
timer.stop();
}
JButton button = (JButton) event.getSource();
if (button.equals(frame.getEndPointButton())) {
model.setCenterPoint(false);
model.setAngle(180);
} else {
model.setCenterPoint(true);
model.setAngle(0);
}
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
model.incrementAngle(1);
frame.repaint();
}
});
timer.start();
}
}
public class RotatedRectangle {
private boolean centerPoint;
private int angle;
private final Color color;
private final Rectangle rectangle;
public RotatedRectangle(Color color, Rectangle rectangle) {
this.color = color;
this.rectangle = rectangle;
this.angle = 0;
this.centerPoint = true;
}
public int getAngle() {
return angle;
}
public void setAngle(int angle) {
this.angle = angle;
}
public void incrementAngle(int increment) {
this.angle += increment;
this.angle %= 360;
}
public Polygon getRectangle() {
Point rotatePoint = new Point(rectangle.x, rectangle.y);
if (isCenterPoint()) {
int x = rectangle.x + rectangle.width / 2;
int y = rectangle.y + rectangle.height / 2;
rotatePoint = new Point(x, y);
}
Point[] point = new Point[4];
int width = rectangle.x + rectangle.width;
int height = rectangle.y + rectangle.height;
point[0] = new Point(rectangle.x, rectangle.y);
point[1] = new Point(width, rectangle.y);
point[2] = new Point(width, height);
point[3] = new Point(rectangle.x, height);
Polygon polygon = new Polygon();
for (int i = 0; i < point.length; i++) {
point[i] = calculatePoint(rotatePoint, point[i], angle);
polygon.addPoint(point[i].x, point[i].y);
}
return polygon;
}
private Point calculatePoint(Point rotatePoint, Point point, int angle) {
double theta = Math.toRadians(angle);
int xDistance = rotatePoint.x - point.x;
int yDistance = rotatePoint.y - point.y;
double distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
double alpha = Math.atan2(yDistance, xDistance);
theta += alpha;
int x = (int) Math.round(Math.cos(theta) * distance) + rotatePoint.x;
int y = (int) Math.round(Math.sin(theta) * distance) + rotatePoint.y;
return new Point(x, y);
}
public Color getColor() {
return color;
}
public boolean isCenterPoint() {
return centerPoint;
}
public void setCenterPoint(boolean centerPoint) {
this.centerPoint = centerPoint;
}
}
}

Swing draws only after resizing

Program should draw the line twice longer after clicking the button, but it only does that after clicking AND THEN resizing the window. I don't know what is happening, i thought this is gonna be easy.
Could you tell me how can I fix it?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Random;
import java.util.Stack;
class MyButtonPanel extends JPanel {
public static final int HEIGHT = 800;
public static final int WIDTH = 800;
private JButton greenButton;
private JPanel buttonPanel;
Stack<Point> points;
int X = 25;
int Y = 25;
public MyButtonPanel() {
greenButton = new GreenButton();
points = new Stack<Point>();
buttonPanel = this;
setLayout(new FlowLayout());
setPreferredSize(new Dimension(WIDTH, HEIGHT));
add(greenButton);
}
class GreenButton extends JButton implements ActionListener
{
GreenButton() {
super("LongerLine");
addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
//points.push(new Point(0,0));
X = 2 * X;
Y = 2 * Y;
validate();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//g2d.setColor(Color.WHITE);
//g2d.fillRect(0, 0, WIDTH, HEIGHT);
g2d.setColor(Color.BLACK);
//drawLines(g2d);
Line2D lin = new Line2D.Double(0,0, X, Y);
g2d.draw(lin);
}
private void drawLines(Graphics2D g2d) {
//Line2D lin = new Line2D.Float(100, 100, 250, 260);
//g2d.draw(lin);
double x1, y1, x2, y2;
/*
for(Point point: points) {
x1 = (double) point.getX();
y1 = (double) point.getY();
Line2D line = new Line2D.Double(x1,y1,200,200);
g2d.draw(line);
}
*/
}
}
public class MyActionFrame extends JFrame {
public MyActionFrame() {
super("Test akcji");
JPanel buttonPanel = new MyButtonPanel();
add(buttonPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
//setResizable(false);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MyActionFrame();
}
});
}
}
This validate();, or better revalidate(); is called when a container's layout needs to be re-done, often when components are added or removed, and is not what you're doing or desiring. Instead you want to call repaint() which suggests that the component be painted.

java gui paintComponent refresh

I am learning java gui interface and wrote a program that has a button. Each time the button is clicked, a random sized rectangle will be added to the screen. But instead of adding it to the screen, the program keeps erasing the old one, which I want to keep on the screen. Here is my code. I tried to do paint() and it did not work. Thanks in advance.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class SimpleGui implements ActionListener {
JFrame frame = new JFrame();
public static void main(String[] args){
SimpleGui gui = new SimpleGui();
gui.go();
}
public void go(){
JButton button = new JButton("Add a rectangle");
MyDrawPanel panel = new MyDrawPanel();
button.addActionListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event){
frame.repaint();
}
class MyDrawPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(Color.blue);
int height = (int) (Math.random()*120 + 10);
int width = (int) (Math.random()*120 + 10);
int x = (int) (Math.random()*40 + 10);
int y = (int) (Math.random()*40 + 10);
g.fillRect(x, y, height, width);
}
}
}
Your paintComponent method is written to draw only one rectangle, so its behavior should come as no shock to you. If you want it to draw multiple, you have one of two options:
Create an ArrayList<Rectangle>, and in the actionPerformed method, add a new random Rectangle to this List and then call repaint(). In the paintComponent method, iterate through this List with a for-loop, painting each Rectangle.
Or you could draw the new random rectangle onto a BufferedImage that is displayed by the paintComponent method.
The first method is the easier of the two, the 2nd is better if you're worried about program responsiveness, say in an animation program.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class TwoDrawRectMethods extends JPanel {
// Array to hold our two drawing JPanels
private AddRandomRect[] addRandomRects = {
new DrawList("Using List"),
new DrawBufferedImage("Using BufferedImage")};
// constructor
public TwoDrawRectMethods() {
// add drawing rectangles onto GUI
for (AddRandomRect addRandomRect : addRandomRects) {
add(addRandomRect);
}
// button to tell rectangles to add a new Rectangle
add(new JButton(new DrawAction("Add New Rectangle")));
}
// The button's Action -- an ActionListener on "steroids"
private class DrawAction extends AbstractAction {
public DrawAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// tell both drawing JPanels to add a new rectangle
for (AddRandomRect addRandomRect : addRandomRects) {
addRandomRect.addRectangle();
}
}
}
private static void createAndShowGui() {
TwoDrawRectMethods mainPanel = new TwoDrawRectMethods();
JFrame frame = new JFrame("TwoDrawRectMethods");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class DrawList extends AddRandomRect {
private static final Color RECT_COLOR = Color.RED;
private List<Rectangle> rectList = new ArrayList<>();
public DrawList(String title) {
super(title);
}
#Override
public void addRectangle() {
rectList.add(createRandomRect());
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(RECT_COLOR);
for (Rectangle rectangle : rectList) {
g2.draw(rectangle);
}
}
}
#SuppressWarnings("serial")
class DrawBufferedImage extends AddRandomRect {
private static final Color RECT_COLOR = Color.BLUE;
private BufferedImage img = null;
public DrawBufferedImage(String title) {
super(title);
}
#Override
public void addRectangle() {
if (img == null) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Rectangle rect = createRandomRect();
Graphics2D g2 = img.createGraphics();
g2.setColor(RECT_COLOR);
g2.draw(rect);
g2.dispose();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
}
}
#SuppressWarnings("serial")
abstract class AddRandomRect extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private Random random = new Random();
public AddRandomRect(String title) {
setBorder(BorderFactory.createTitledBorder(title));
}
abstract void addRectangle();
protected Rectangle createRandomRect() {
int x1 = random.nextInt(PREF_W);
int x2 = random.nextInt(PREF_W);
int y1 = random.nextInt(PREF_H);
int y2 = random.nextInt(PREF_H);
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Rectangle(x, y, width, height);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}

How to paint permanently on JComponent

I'm trying to create a paint application in Java.
I have a "canvas" class which extends JComponent.
I have an ArrayList of type Shape which holds all the shapes of the entire drawing.
Inside the paintComponent() method:
Each loop everything gets cleared
Every Shape inside the ArrayList gets painted with either g.draw() or g.fill()
If I want to add a shape or draw a Shape, I add it to the ArrayList.
The problem is that after a considerably high amount of shapes inside the ArrayList, the execution of the paintComponent() method slows.
For example a custom brush.
When dragging the brush over the canvas I have to add a new Shape of type "CustomBrush extends Shape" to the ArrayList
So with just a single stroke I end up with hundreds of shapes in the ArrayList
The question is:
How do I "pack" say 100 Shape objects into one, so that a single brush stroke becomes one single object in my ArrayList ?
The ultimate goal is however to speed up the paintComponent() method so that it paints all the drawn Shapes faster.
Thank You!
Here's a sample code:
public class GraphicPanel extends JComponent{
private ArrayList<Shape> shapeBuffer;
public void paintComponent( Graphics gPlain ){
Graphics2D g = (Graphics2D)gPlain;
for( Shape s : shapeBuffer ){
if( filled.next() ){
g.fill( s );
}
else{
g.draw( s );
}
}
}
Paint the background to a BufferedImage, and then draw the BufferedImage to your GrahpicPanel within the paintComponent(...) method using g.drawImage(...). You get the BufferedImage's Graphics context by calling getGraphics() or createGraphics() (for a Graphics2D object). Don't forget to dispose of the Graphics object obtained in this way (but never dispose of a Graphics object given to you by the JVM).
Also, don't forget to call the super.paintComponent(g) in your override!
For example:
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.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
public class MyPaint extends JComponent {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Stroke STROKE = new BasicStroke(4f);
private static final Color[] COLORS = { Color.RED, Color.GREEN,
Color.yellow, Color.orange, Color.blue, Color.cyan };
private BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
private Rectangle rect = null;
public MyPaint() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
if (rect != null) {
g.setColor(Color.LIGHT_GRAY);
((Graphics2D) g).draw(rect);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
private Random random = new Random();
private Point p;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
p = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (p != null) {
Rectangle rect2 = createRect(e.getPoint());
Graphics2D g2 = img.createGraphics();
g2.setStroke(STROKE);
Color c = COLORS[random.nextInt(COLORS.length)];
g2.setColor(c);
g2.fill(rect2);
g2.setColor(c.darker());
g2.draw(rect2);
g2.dispose();
}
p = null;
rect = null;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
rect = createRect(e.getPoint());
repaint();
}
private Rectangle createRect(Point p2) {
int x = Math.min(p.x, p2.x);
int y = Math.min(p.y, p2.y);
int width = Math.abs(p.x - p2.x);
int height = Math.abs(p.y - p2.y);
Rectangle rect2 = new Rectangle(x, y, width, height);
return rect2;
}
}
private static void createAndShowGui() {
MyPaint mainPanel = new MyPaint();
JFrame frame = new JFrame("MyPaint");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Brushstroke and color are attributes of a shape. You could define your own shape class like this. That way, you're maintaining shapes in your List.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Shape;
public class MyShape {
private int brushSize;
private Color interiorColor;
private Shape shape;
public MyShape() {
this.brushSize = 1;
this.interiorColor = Color.blue;
}
public MyShape(int brushSize, Color interiorColor, Shape shape) {
this.brushSize = brushSize;
this.interiorColor = interiorColor;
this.shape = shape;
}
public int getBrushSize() {
return brushSize;
}
public void setBrushSize(int brushSize) {
this.brushSize = brushSize;
}
public Color getInteriorColor() {
return interiorColor;
}
public void setInteriorColor(Color interiorColor) {
this.interiorColor = interiorColor;
}
public Shape getShape() {
return shape;
}
public void setShape(Shape shape) {
this.shape = shape;
}
}
If I missed any attributes, feel free to add them to your shape class.

Make a object when pressed follow mouse pointer, java [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I want to make a program that has objects on the screen and then when you press down on them it will follow the mouse pointer until you then release the mouse and then it will no longer follow the mouse.
Here is the code i have to add balls to the screen so if it would be possible to just adapt the code it would be great. It is split into 3 classes
import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class DrawBalls {
JFrame frame = new JFrame();
final DrawPanel drawPanel = new DrawPanel();
JPanel controlPanel = new JPanel();
JButton createBallButton = new JButton("Add ball");
DrawBalls(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
controlPanel.add(createBallButton);
frame.add(drawPanel);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
{
drawPanel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
for (Ball b : drawPanel.getBalls()) {
if (b.getBounds().contains(me.getPoint())) {
//this has it being the same coordinates as the mouse i don't know
//how to have it run constantly so when i move it, it doesn't work
b.setx(me.getX()-(b.radius/2));
b.sety( me.getY()-(b.radius/2));
drawPanel.repaint();
}
}
}
});
createBallButton.addActionListener(new ActionListener() {
Random rand = new Random();
private int counter = 1;
int noOfClicks = 1;
public void actionPerformed(ActionEvent e) {
if(noOfClicks<=10){
int ballRadius = 10;
int x = rand.nextInt(drawPanel.getWidth());
int y = rand.nextInt(drawPanel.getHeight());
//check that we dont go offscreen by subtarcting its radius unless its x and y are not bigger than radius
if (y > ballRadius) {
y -= ballRadius;
}
if (x > ballRadius) {
x -= ballRadius;
}
drawPanel.addBall(new Ball(x, y, ballRadius, counter));//add ball to panel to be drawn
counter++;//increase the ball number
noOfClicks++;
}
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DrawBalls();
}
});
}
Ball class
import java.awt.*;
import java.awt.geom.*;
public class Ball {
private Color color;
private int x, y;
private int radius;
private final int number;
Ball(int x, int y, int radius, int counter) {
this.x = x;
this.y = y;
this.radius = radius;
this.number = counter;
this.color = Color.RED;
}
public void draw(Graphics2D g2d) {
Color prevColor = g2d.getColor();
g2d.drawString(number + "", x + radius, y + radius);
g2d.setColor(color);
g2d.fillOval(x, y, radius, radius);
g2d.setColor(prevColor);
}
public Rectangle2D getBounds() {
return new Rectangle2D.Double(x, y, radius, radius);
}
int getNumber() {
return number;
}
}
DrawPanel
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class DrawPanel extends JPanel {
ArrayList<Ball> balls = new ArrayList<Ball>();
public void addBall(Ball b) {
balls.add(b);
repaint();
}
public ArrayList<Ball> getBalls() {
return balls;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Ball ball : balls) {
ball.draw(g2d);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
One way is to make your Ball class an actual Swing component. Then you can use the ComponentMover class.
Edit:
how do you make a class into a swing component
Basically, you move your draw(...) code into the paintComponent() method of JComponent. Here is a simple example that does all the custom painting for you because the painting is based on a Shape object. You would still need to modify the code to paint the "number".
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class ShapeComponent extends JComponent
{
Shape shape;
public ShapeComponent(Shape shape)
{
this.shape = shape;
setOpaque( false );
}
public Dimension getPreferredSize()
{
Rectangle bounds = shape.getBounds();
return new Dimension(bounds.width, bounds.height);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor( getForeground() );
g2d.fill( shape );
}
#Override
public boolean contains(int x, int y)
{
return shape.contains(x, y);
}
private static void createAndShowUI()
{
ShapeComponent ball = new ShapeComponent( new Ellipse2D.Double(0, 0, 50, 50) );
ball.setForeground(Color.GREEN);
ball.setSize( ball.getPreferredSize() );
ball.setLocation(10, 10);
ShapeComponent square = new ShapeComponent( new Rectangle(30, 30) );
square.setForeground(Color.ORANGE);
square.setSize( square.getPreferredSize() );
square.setLocation(50, 50);
JFrame frame = new JFrame();
frame.setLayout(null);
frame.add(ball);
frame.add(square);
frame.setSize(200, 200);
frame.setVisible(true);
MouseListener ml = new MouseAdapter()
{
public void mouseClicked( MouseEvent e )
{
System.out.println( "clicked " );
}
};
ball.addMouseListener( ml );
square.addMouseListener( ml );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
The main difference between this approach and trashgod's suggestion to use an Icon is that mouse events will only be generated when the mouse in over the ball, not the rectangular corners of the ball since the contains(...) method respects the shape of what you are drawing.

Categories