Hi I'm trying to create heart shape for my application and
I could do the hollow one and it's working good, now I need to draw it with filled method but it's created by two Arc2D.Double and two Line2D.Double so because of this just the Arc's filling and two lines not.I've tried to add these two lines in two different 'Area' and add these two areas in one but also not worked.
There is a any way to do this (filling between two lines)?Thanks advance.
My codes : Class Heart
`public class HeartShape {
private ArrayList<Shape> shapes;
public HeartShape() {
}
public ArrayList<Shape> Heart(double x, double y, double HEART_RADIUS) {
shapes = new ArrayList<>();
double r = HEART_RADIUS;
double root2 = Math.sqrt(2);
double cx = x;
double cy = y;
double dx = r / root2;
double heights = 3 * dx + r;
double top = cy - heights / 2;
double bottom = cy + heights / 2;
Shape s = new Arc2D.Double(cx - dx - r, top, 2 * r, 2 * r, 45, 180, Arc2D.OPEN);
shapes.add(s);
s = new Arc2D.Double(cx + dx - r, top, 2 * r, 2 * r, -45, 180, Arc2D.OPEN);
shapes.add(s);
s = new Line2D.Double(cx, bottom, cx - 2 * dx, bottom - 2 * dx);
shapes.add(s);
s = new Line2D.Double(cx, bottom, cx + 2 * dx, bottom - 2 * dx);
shapes.add(s);
if (shapes != null) {
return shapes;
} else {
return null;
}
}
public void drawHeart(Graphics2D g2d, boolean isFilled) {
if (isFilled == true) {
shapes.forEach((ss) -> {
g2d.fill(ss);
});
} else {
shapes.forEach((ss) -> {
g2d.draw(ss);
});
}
}`
And DrawinTest :
public class DrawinTest extends JPanel{
private int HEART_RADIUS;
private Point startpoint;
private int x, y, width, height;
private HeartShape heartShape = new HeartShape();
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new DrawinTest();
}
public DrawinTest() {
JFrame f = new JFrame("Test Area");
f.setPreferredSize(new Dimension(600, 500));
f.setLocationRelativeTo(null);
f.setLayout(new BorderLayout(0, 1));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(new MyMouseListener());
this.addMouseMotionListener(new MyMouseListener());
this.setBackground(Color.WHITE);
f.setContentPane(this);
f.setVisible(true);
f.pack();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
if(heartShape != null) {
heartShape.Heart(x, y, HEART_RADIUS);
heartShape.drawHeart(g2d, false);
}
g2d.dispose();
}
class MyMouseListener implements MouseListener,MouseMotionListener {
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
startpoint = new Point(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseDragged(MouseEvent e) {
x = Math.min(startpoint.x, e.getX());
y = Math.min(startpoint.y, e.getY());
width = Math.abs(startpoint.x - e.getX());
height = Math.abs(startpoint.y - e.getY());
HEART_RADIUS = Math.min(width, height);
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {}
}
}
So far its looking like this :
The Shapes API has a number of really interesting APIs, one of my favorites is Path2D
Basically, what it allows you to do is append other Shapes, making it very useful in this situation.
public class HeartShape {
private Shape shape;
public HeartShape() {
}
public Shape Heart(double x, double y, double HEART_RADIUS) {
double r = HEART_RADIUS;
double root2 = Math.sqrt(2);
double cx = x;
double cy = y;
double dx = r / root2;
double heights = 3 * dx + r;
double top = cy - heights / 2;
double bottom = cy + heights / 2;
Path2D base = new Path2D.Double();
Shape s = new Arc2D.Double(cx - dx - r, top, 2 * r, 2 * r, 45, 180, Arc2D.OPEN);
base.append(s, false);
s = new Line2D.Double(cx, bottom, cx - 2 * dx, bottom - 2 * dx);
base.append(s, true);
s = new Line2D.Double(cx, bottom, cx + 2 * dx, bottom - 2 * dx);
base.append(s, true);
s = new Arc2D.Double(cx + dx - r, top, 2 * r, 2 * r, -45, 180, Arc2D.OPEN);
base.append(s, true);
base.closePath();
shape = base;
return base;
}
public void drawHeart(Graphics2D g2d, boolean isFilled) {
System.out.println("...");
if (isFilled) {
g2d.fill(shape);
} else {
g2d.draw(shape);
}
}
}
As shown in this example, you don't need to re-create the shape when you want to change it's size, you can simply create an instance of it at a "default" size and use a AffineTransform to resize it, much easier ;)
I think that instead of using an arrayList of shapes you should use a GenericPath and append each individual shape to it with GenericPath.append(). One you're done add the pieces of the heart use GenericPath.closePath() to make it a close it up so that it can be filled. Then you should be able to use the new GenericPath object as the path to be drawn with g2d.draw
Related
I made a this test program for a project im working on. It draws a car, and moves it across the JFrame from left to right. What I am trying to do is make it so once the car object has completely passed the other side of the frame it will loop back on the other side. I think I have to use an outside loop for the timer in the main class called animationTester but Im not entirely sure what I want to put in the loop. Also Ive been told that I cannot hard code the size of the window into the program. anyway here are my classes.
ShapeIcon class
import java.awt.*;
import java.util.*;
import javax.swing.*;
/**
An icon that contains a moveable shape.
*/
public class ShapeIcon implements Icon
{
private int width;
private int height;
private MoveableShape shape;
public ShapeIcon(MoveableShape shape,
int width, int height)
{
this.shape = shape;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
Graphics2D g2 = (Graphics2D) g;
shape.draw(g2); // has draw method since it implements MoveableShape
}
}
CarShape Class
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
/**
A car that can be moved around.
*/
public class CarShape implements MoveableShape
{
private int x;
private int y;
private int width;
/**
Constructs a car item.
#param x the left of the bounding rectangle
#param y the top of the bounding rectangle
#param width the width of the bounding rectangle
*/
public CarShape(int x, int y, int width)
{
this.x = x;
this.y = y;
this.width = width;
}
public void translate(int dx, int dy)
{
x += dx;
y += dy;
}
public void draw(Graphics2D g2)
{
Rectangle2D.Double body
= new Rectangle2D.Double(x, y + width / 6,
width - 1, width / 6);
Ellipse2D.Double frontTire
= new Ellipse2D.Double(x + width / 6, y + width / 3,
width / 6, width / 6);
Ellipse2D.Double rearTire
= new Ellipse2D.Double(x + width * 2 / 3, y + width / 3,
width / 6, width / 6);
// The bottom of the front windshield
Point2D.Double r1
= new Point2D.Double(x + width / 6, y + width / 6);
// The front of the roof
Point2D.Double r2
= new Point2D.Double(x + width / 3, y);
// The rear of the roof
Point2D.Double r3
= new Point2D.Double(x + width * 2 / 3, y);
// The bottom of the rear windshield
Point2D.Double r4
= new Point2D.Double(x + width * 5 / 6, y + width / 6);
Line2D.Double frontWindshield
= new Line2D.Double(r1, r2);
Line2D.Double roofTop
= new Line2D.Double(r2, r3);
Line2D.Double rearWindshield
= new Line2D.Double(r3, r4);
g2.draw(body);
g2.draw(frontTire);
g2.draw(rearTire);
g2.draw(frontWindshield);
g2.draw(roofTop);
g2.draw(rearWindshield);
}
}
MoveableShape class
import java.awt.*;
/**
A shape that can be moved around.
*/
public interface MoveableShape
{
/**
Draws the shape.
#param g2 the graphics context
*/
void draw(Graphics2D g2);
/**
Moves the shape by a given amount.
#param dx the amount to translate in x-direction
#param dy the amount to translate in y-direction
*/
void translate(int dx, int dy);
}
Main class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
This program implements an animation that moves
a car shape.
*/
public class AnimationTester
{
private static final int ICON_WIDTH = 400;
private static final int ICON_HEIGHT = 100;
private static final int CAR_WIDTH = 100;
public static void main(String[] args)
{
JFrame frame = new JFrame();
final MoveableShape shape
= new CarShape(0, 0, CAR_WIDTH);
ShapeIcon icon = new ShapeIcon(shape,
ICON_WIDTH, ICON_HEIGHT);
final JLabel label = new JLabel(icon);
frame.setLayout(new FlowLayout());
frame.add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
final int DELAY = 100;
// Milliseconds between timer ticks
Timer t = new Timer(DELAY, new
ActionListener()
{
public void actionPerformed(ActionEvent event)
{
shape.translate(1, 0);
label.repaint();
}
});
t.start();
}
}
You may modify translate method to allow an end parameter, so the car start again when it gets to the end of the frame:
public void translate(int dx, int dy, int end) {
x += dx;
y += dy;
if (end == x) {
x = -100;
}
}
Then pass the frame.getWidth() to the translate call on AnimationTester.class:
Timer t = new Timer(DELAY, new ActionListener() {
public void actionPerformed(ActionEvent event) {
car.translate(1, 0, frame.getWidth());
label.repaint();
}
});
I hope it helps :)
As part of my assignment, I'm supposed to make a shape that moves when the keyboard is pressed, and also changes color as it moves. I'm trying to add duplicate shapes that move when selected by clicking on them. However, for some reason, I can't add more than one shape. Here's my code. WARNING: MySimplePanel is very long, but the comments explain what my code does.
import java.awt.Graphics2D;
public interface ActionShape {
/**
* Calls the draw method inherited from the shape
* #param g
*/
public void draw(Graphics2D g);
public boolean contains(double x, double y);
public double getWidth();
public double getHeight();
public void setFrame(double x, double y, double w, double h);
}
Driver.java
public class Driver {
public static void main(String args[]) {
MySimplePanel panel = new MySimplePanel(800, 800, Color.gray);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static float random(float lower, float upper) {
float rand = (float) Math.random();
float range = upper - lower;
rand = range * rand;
System.out.println((lower + rand));
return (lower + rand);
}
}
myShape.java
public class myShape extends Rectangle2D.Double implements ActionShape{
static final int size = 50;
Ellipse2D oval;
Ellipse2D oval2;
Ellipse2D oval3;
public int red=127;
public int green=127;
public int blue = 0;
public myShape(int x, int y) {
//sets position of square to center
super(x-size/2, y-size/2, size, size);
oval = new Ellipse2D.Double(x-size/2, y - size, size, size);
oval2 = new Ellipse2D.Double(x-size/2, y + size/25, size, size);
oval3 = new Ellipse2D.Double(x - size, y-size/2, size, size);
}
/**
* Move all the shapes comprising this one
* #return
*/
#Override
public void draw(Graphics2D g) {
// TODO Auto-generated method stub
g.setColor(Color.black);
g.draw(this); //draw outline
g.draw(oval);
g.draw(oval2);
g.draw(oval3);
g.setColor(new Color(red,green,blue));//set color of all shapes
g.fill(this); //draw inside
g.fill(oval);
g.fill(oval2);
g.fill(oval3);
}
public void setFrame(double x, double y, double w, double h) {
super.setFrame(x, y, w, h);
oval.setFrame(x, y-size/2, w, h);
oval2.setFrame(x, y+size/2, w, h);
oval3.setFrame(x-size/2, y, w, h);
}
public boolean contains(double x, double y) {
if(super.contains(x, y) || oval.contains(x, y)|| oval2.contains(x, y)|| oval3.contains(x, y)) {
return true;
}else {
return false;
}
}
}
MySimplepanel
public class MySimplePanel extends JPanel implements MouseInputListener, KeyListener{
public static final int MOVE_PER_ARROW_KEY = 5; //variable that determines how many spaces the shape will move.
private int width;
private int height;
private boolean isPressed = false;
private boolean rightPressed = false;
private boolean otherPressed = false;
public myShape shape;
public int maxRed = 255;
public int maxGreen = 255;
public int maxBlue = 255;
public myShape selShape=null;
public int nextShape=0;
//An array of different shapes that all share an interface. This will be used when the right mouse button is pressed
public myShape[] shapes;
/**
* Construct a panel with specified width, height, and background color
* #param width
* #param height
* #param bgColor
*/
public MySimplePanel(int width, int height, Color bgColor) {
this.setPreferredSize(new Dimension(width, height));
this.setBackground(bgColor);
//Start to listen to mouse and keyboard input on this panel
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.addKeyListener(this); //detect keyboard input
this.setFocusable(true); //allows you to select this window (required to be able to type in it, just like Processing)
this.setFocusTraversalKeysEnabled(false); //disables shift and tab
setup();
}
private void setup() {
//sets up the starting coordinates for each shape the shape is going to be on the panel.
//I still need to align the center of the panel with the shape's center.
shape = new myShape(400,400);
shapes = new myShape[100];
//array of shapes
shapes[nextShape] = new myShape(200,200);
repaint();
}
/**
* This method is called whenever you call repaint();
*/
protected void paintComponent(Graphics graphicHelper) {
super.paintComponent(graphicHelper); //basically background() in Processing, erases everything
Graphics2D g = (Graphics2D) graphicHelper; //used for drawing in 2D mode
//width and height of the panel
width= getWidth();
height = getHeight();
//draws the shape.
shape.draw(g);
for(int i=0;i<nextShape;i++) {
shapes[i].draw(g);
g.setColor(Color.red);
g.draw(shapes[i]);
}
//for the very first shape that is drawn
if(isPressed==true) {
shape.draw(g);
g.setColor(Color.red);
g.draw(shape);
System.out.println("Shape pressed");
}
//for the very other shape that is drawn by right-clicking
if(otherPressed==true) {
for(int i=0;i<nextShape;i++) {
selShape.draw(g);
g.setColor(Color.red);
g.draw(selShape);
System.out.println("Other Shape pressed");
}
}
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
if(arg0.getButton() == MouseEvent.BUTTON1) {
if(shape.contains(arg0.getX(), arg0.getY())) {
selShape=shape;
isPressed=true;
repaint();
}
}
if(arg0.getButton() == MouseEvent.BUTTON1) {
for(int i=0; i<nextShape; i++) {
if(shapes[i]!=null) {
if(shapes[i].contains(arg0.getX(), arg0.getY())) {
selShape=shapes[i];
otherPressed=true;
repaint();
}
}
}
}
if(arg0.getButton() == MouseEvent.BUTTON3) {
rightPressed=true;
if(rightPressed==true) {
selShape=shapes[nextShape];
nextShape++;
repaint();
}
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent arg0) {
}
#Override
public void keyPressed(KeyEvent arg0) {
/**
* Scales the values of red and green based on the width and height respectively.
* red = 0 when the shape is all the way on the left, red = 255 when the shape is all the way on the right
* green = 0 when the shape is all the way up, green = 255 when the shape is all the way down
*/
selShape.red=(int) ((maxRed)*selShape.x/width);
selShape.green=(int) ((maxGreen)*selShape.y/height);
/**
* These two if statements are meant to keep the shape from moving off screen.
*/
if(selShape.x>width||selShape.x<(width=0)) {
selShape.x=width;
}
if(selShape.y>height||selShape.y<(height=0)) {
selShape.y=height;
}
/**
* Moves the shape in different directions depending on the key pressed. It also changes the values of red and green
*/
if(arg0.getKeyCode() == KeyEvent.VK_DOWN) {
selShape.setFrame(selShape.x, selShape.y + MOVE_PER_ARROW_KEY,
selShape.width, selShape.height);
selShape.green--;
repaint();
}else if(arg0.getKeyCode() == KeyEvent.VK_UP) {
selShape.setFrame(selShape.x, selShape.y - MOVE_PER_ARROW_KEY,
selShape.width, selShape.height);
selShape.green++;
repaint();
}else if(arg0.getKeyCode() == KeyEvent.VK_LEFT) {
selShape.setFrame(selShape.x - MOVE_PER_ARROW_KEY, selShape.y,
selShape.width, selShape.height);
selShape.red--;
repaint();
}else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
selShape.setFrame(selShape.x + MOVE_PER_ARROW_KEY, selShape.y,
selShape.width, selShape.height);
selShape.red++;
repaint();
}
/**
* If the shape reaches a certain spot, it will keep changing color randomly until it leaves that area.
*
* Still trying to get the shape's center to hit that spot.
*
*/
if(selShape.getCenterX()>=50 && selShape.getCenterX()<=150 && selShape.getCenterY()>=50 && selShape.getCenterY()<=150) {
selShape.red=(int)(Math.random()*maxRed)+1;
selShape.green=(int)(Math.random()*maxGreen)+1;
selShape.blue=(int)(Math.random()*maxBlue)+1;
System.out.println("x: "+selShape.x);
System.out.println("y: "+selShape.y);
}
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
myShape.java
public class myShape extends Rectangle2D.Double implements ActionShape {
static final int size = 50;
Ellipse2D oval;
Ellipse2D oval2;
Ellipse2D oval3;
public int red = 127;
public int green = 127;
public int blue = 0;
public myShape(int x, int y) {
// sets position of square to center
super(x - size / 2, y - size / 2, size, size);
oval = new Ellipse2D.Double(x - size / 2, y - size, size, size);
oval2 = new Ellipse2D.Double(x - size / 2, y + size / 25, size, size);
oval3 = new Ellipse2D.Double(x - size, y - size / 2, size, size);
}
/**
* Move all the shapes comprising this one
*
* #return
*/
#Override
public void draw(Graphics2D g) {
// TODO Auto-generated method stub
g.setColor(Color.black);
g.draw(this); // draw outline
g.draw(oval);
g.draw(oval2);
g.draw(oval3);
g.setColor(new Color(red, green, blue));// set color of all shapes
g.fill(this); // draw inside
g.fill(oval);
g.fill(oval2);
g.fill(oval3);
}
public void setFrame(double x, double y, double w, double h) {
super.setFrame(x, y, w, h);
oval.setFrame(x, y - size / 2, w, h);
oval2.setFrame(x, y + size / 2, w, h);
oval3.setFrame(x - size / 2, y, w, h);
}
public boolean contains(double x, double y) {
if (super.contains(x, y) || oval.contains(x, y) || oval2.contains(x, y) || oval3.contains(x, y)) {
return true;
} else {
return false;
}
}
To be clear, I want to have a blue circle bouncing left to right which stops on click. This part works. But I also need to have a red rectangle bouncing up and down in the same gui which also stops on click. Each object should stop individually. However, two circles appear where one is moving and the other one is just still. Thanks in Advance! Help is appreciated.
/*
* This program creates an animation for a circle.
*/
package circleanimation;
import java.awt.*;
/*
* #author talhaiqbal18
*/
public class CircleAnimation
{
private int centerX, centerY, radius;
private Color color;
private int direction, speed;
private boolean filled;
public CircleAnimation(int x, int y, int r, Color c) {
centerX = x;
centerY = y;
radius = r;
color = c;
direction = 0;
speed = 0;
filled = false;
}
public void draw(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
if (filled) {
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.fillRect(200, 200, 200, 200); }
else {
g.fillRect(200, 200, 200, 200);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor); }
}
public void fill(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.fillRect(200, 200, 200, 200);
g.setColor(oldColor);
}
public boolean containsPoint(int x, int y) {
int xSquared = (x - centerX) * (x - centerX);
int ySquared = (y - centerY) * (y - centerY);
int radiusSquared = radius * radius;
return xSquared + ySquared - radiusSquared <= 0;
}
public void move(int xAmount, int yAmount) {
centerX = centerX + xAmount;
centerY = centerY + yAmount;
}
public int getRadius() {
return radius;
}
public int getX() {
return centerX;
}
public int getY() {
return centerY;
}
public void setSpeed(int s) {
speed = s;
}
public void setDirection(int d) {
direction = d % 360;
}
public void turn(int degrees) {
direction = (direction + degrees) % 360;
}
public void move() {
move((int)(speed * Math.cos(Math.toRadians(direction))),
(int)(speed * Math.sin(Math.toRadians(direction))));
}
public void setFilled(boolean b) {
filled = b;
}
}
/*
* This is the color panel class for the circle animation project.
*/
package circleanimation;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/*
* #author talhaiqbal18
*/
public class ColorPanel extends JPanel
{
private CircleAnimation circle, rectangle;
private javax.swing.Timer timer;
private CircleAnimation selectedCircle, selectedRectangle;
private int x, y;
public ColorPanel(Color backColor, int width, int height) {
setBackground(backColor);
setPreferredSize(new Dimension(width, height));
circle = new CircleAnimation(350, 300, 350, Color.blue);
circle.setDirection(180);
circle.setSpeed(6);
rectangle = new CircleAnimation(350, 300, 400, Color.red);
rectangle.setDirection(90);
rectangle.setSpeed(6);
timer = new javax.swing.Timer(1, new MoveListener());
timer.start();
addMouseListener(new PanelListener());
addMouseMotionListener(new PanelMotionListener());
addMouseMotionListener(new PanelMotionListener1());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
circle.fill(g);
rectangle.fill(g);
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = circle.getX();
int radius = circle.getRadius();
int width = getWidth();
if (x - radius <= 0 || x + radius >= width) {
circle.turn(180);
}
circle.move();
repaint();
}
}
private class MoveListener1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = rectangle.getX();
int radius = rectangle.getRadius();
int width = getWidth();
if (x - radius <= 0 || x + radius >= width) {
rectangle.turn(270);
}
rectangle.move();
repaint();
}
}
private class PanelListener extends MouseAdapter {
public void mousePressed(MouseEvent e)
{
x = e.getX();
y = e.getY();
if (circle.containsPoint(x, y))
selectedCircle = circle;
if (rectangle.containsPoint(x, y))
selectedRectangle = rectangle;
}
public void mouseReleased(MouseEvent e) {
//nothing
}
public void mouseClicked(MouseEvent e) {
if(timer.isRunning())
timer.stop();
else
timer.start();
}
}
private class PanelMotionListener extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
int newX = e.getX();
int newY = e.getY();
int dx = newX - x;
int dy = newY - y;
if (selectedCircle != null) {
selectedCircle.move(dx,dy);
x = newX;
y = newY;
repaint(); }
}
}
private class PanelMotionListener1 extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
int newX = e.getX();
int newY = e.getY();
int dx = newX - x;
int dy = newY - y;
if (selectedRectangle != null) {
selectedRectangle.move(dx,dy);
x = newX;
y = newY;
repaint(); }
}
}
}
/*
* This is the main method which will implement the actions of the previous classes.
*/
package circleanimation;
import java.awt.*;
import javax.swing.JFrame;
/*
* #author talhaiqbal18
*/
public class MainClass
{
public static void main(String[] args) throws Exception {
JFrame theGUI = new JFrame();
theGUI.setTitle("Circle Animation");
theGUI.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
ColorPanel panel = new ColorPanel(Color.white, 100, 100);
Container pane = theGUI.getContentPane();
pane.add(panel);
theGUI.setVisible(true);
}
}
You only register a timer for your circle, but not for your rectangle in the ColorPanel constructor
I was working on an issue where I was getting a cast problem trying to cast from Shape to Area (see previous post cast exception question). Now it seems that my shape that is create is not getting created correctly. Instead of posting all of my source code here I am attaching a link to all the source files here.
Essentially I create the shape as follows with a standard call of
YingYang shape = new YingYang();
shape = shape.moveTo(x, y);
shape = shape.scaleBy(size);
shape.setColor(getNextColor());
and the calls to the Area Class are:
public YingYang()
{
Area mainCircle = new Area(new Ellipse2D.Double(...)
...
yingYang.add(mainCircle);
}
The MoveTo call:
public YingYang moveTo(double x, double y)
{
at.translate(x, y);
at.setToTranslation(x, y);
yingYang.transform(at);
return new YingYang(at.createTransformedShape(yingYang));
}
The ScaleBy:
public YingYang scaleBy(double scale)
{
double cx = this.getBounds2D().getCenterX();
double cy = this.getBounds2D().getCenterY();
at.translate(cx, cy);
at.setToTranslation(cx, cy);
at.scale(scale, scale);
at.translate(-cx, -cy);
return new YingYang(at.createTransformedShape(yingYang));
}
When I call the paintComponent() in my drawing panel:
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for(YingYang s : shapes)
{
System.out.println(s.getBounds2D());
g2.setColor(s.getColor());
g2.fill(s);
}
}
The print statement prints out:
java.awt.geom.Rectangle2D$Double[x=0.0,y=0.0,w=0.0,h=0.0]
I'm at a loss... Any Ideas?
It looks like you have combined both my recommendations into one piece of code. If you are going to use your variable yingYang then you should implement the shape on the class. However if you are going to extend the area you need to remove the yingYang variable and use the class as the area eg: yingYang.add(mainCircle); becomes add(mainCircle);... essentially remove all references of the yingYang variable.
So instead of the "yingYang" variable you are using "this". heres is a modified version of your YingYang class with the references removed.
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public class YingYang extends Area
{
AffineTransform at = new AffineTransform();
private boolean movingRight = true;
private boolean movingUp = true;
private Color color = Color.BLACK;
private int dx = 10, dy = 10;
public YingYang(Shape shape)
{
super(shape);
}
public YingYang()
{
// Construct the Outer Circle & Lower Dot
Area mainCircle = new Area(new Ellipse2D.Double(-210, -210, 420, 420));
Area lowerDot = new Area(new Ellipse2D.Double(-10, 90, 40, 40));
mainCircle.subtract(lowerDot);
// Begin Construction of the whit side of symbol
Area whiteSide = new Area(new Ellipse2D.Double(-200, -200, 400, 400));
Area rect = new Area(new Rectangle2D.Double(0, -200, 200, 400));
whiteSide.subtract(rect);
// Construct the upper white Circle
Area upperCircle = new Area(new Ellipse2D.Double(-100, -200, 200, 200));
whiteSide.add(upperCircle);
// Construct the Upper Dot
Area upperDot = new Area(new Ellipse2D.Double(-10, -110, 40, 40));
whiteSide.subtract(upperDot);
// Remove the lower circle portion
Area lowerCircle = new Area(new Ellipse2D.Double(-100, 0, 200, 200));
whiteSide.subtract(lowerCircle);
// Add Main Circle
add(mainCircle);
// Subtract the white side
subtract(whiteSide);
}
//------------------------ Methods -----------------------------------------
/**
* Sets this shapes color
* (must call getColor before drawing this shape)
* #param color
*/
public void setColor(Color color)
{
this.color = color;
}
/**
* Gets this shapes current color
* #return color
*/
public Color getColor()
{
return this.color;
}
/**
* Determines if the shape is moving left to right
* #return - boolean
*/
public boolean isMovingRight()
{
return movingRight;
}
/**
* Determines if the shape is moving from down to up
* #return - boolean
*/
public boolean isMovingUp()
{
return movingUp;
}
/**
* Changes the Horizontal Path that this shape is traveling
*/
public void changeHorizonalMovement()
{
if(isMovingRight())
{
movingRight = false;
}
else
{
movingRight = true;
}
}
/**
* Changes the Vertical Path that this shape is traveling
*/
public void changeVerticalMovement()
{
if(isMovingUp())
{
movingUp = false;
}
else
{
movingUp = true;
}
}
/**
* Sets the direction of the Horizontal Path of this shape
* true = left to right : false = right to left
* #param dir - boolean
*/
public void setHorizonalMovement(boolean dir)
{
this.movingRight = dir;
}
/**
* Sets the direction of the Vertical Path of this shape
* true = down to up : false = up to down
* #param dir - boolean
*/
public void setVerticalMovement(boolean dir){
this.movingUp = dir;
}
/**
* Moves the current shape by the amount x,y
* #param x - double
* #param y - double
*/
public YingYang moveTo(double x, double y)
{
at.translate(x, y);
at.setToTranslation(x, y);
transform(at);
return new YingYang(at.createTransformedShape(this));
}
/**
* Rotate this shape
* #param theta - amount to rotate shape by
* #return
*/
public YingYang rotate(double theta)
{
double cx = getBounds2D().getCenterX();
double cy = getBounds2D().getCenterY();
at.translate(cx, cy);
at.setToTranslation(cx, cy);
at.rotate(Math.toRadians(theta));
at.translate(-cx, -cy);
return new YingYang(at.createTransformedShape(this));
}
public YingYang moveToAndRotate(double x, double y, double theta)
{
double cx = getBounds2D().getCenterX();
double cy = getBounds2D().getCenterY();
at.translate(cx, cy);
at.setToTranslation(cx, cy);
at.translate(x, y);
at.rotate(Math.toRadians(theta));
at.translate(-cx, -cy);
return new YingYang(at.createTransformedShape(this));
}
/**
* Scales this shape uniformly by the amount of scale
* about the origin
* #param scale - double
*/
public YingYang scaleBy(double scale)
{
double cx = this.getBounds2D().getCenterX();
double cy = this.getBounds2D().getCenterY();
at.translate(cx, cy);
at.setToTranslation(cx, cy);
at.scale(scale, scale);
at.translate(-cx, -cy);
return new YingYang(at.createTransformedShape(this));
}
/**
* Rotates this shape theta degrees about the origin
*/
public YingYang rotate(Double theta)
{
double cx = this.getBounds2D().getCenterX();
double cy = this.getBounds2D().getCenterY();
at.translate(cx, cy);
at.setToTranslation(cx, cy);
at.rotate(Math.toRadians(theta));
at.translate(-cx, -cy);
return new YingYang(at.createTransformedShape(this));
}
public int getDx()
{
return this.dx;
}
public void setDx(int x)
{
this.dx = x;
}
public int getDy()
{
return this.dy;
}
public void setDy(int y)
{
this.dy = y;
}
}
I'm making a clock right now and currently my second hand, minute hand, and hour hand are all drawn graphically using a Line object with an (x0, y0) beginning coordinate and (x1, y1) end coordinate.
What's confusing me right now is how to make the second hand "tick" every time a second passes. That is, how can I update the (x1, y1) coordinate (since the beginning coordinate is always in the center of the clock, we don't need to update it) so that it will move clockwise 6 degrees? This is confusing to me because the direction of the unit circle (and thus the direction of radians) goes counter-clockwise.
There are a few methods. Since you probably know the radius of the clock, you can do
theta = (theta - 6)%360;
x1 = radius*cos(theta * PI/180);
y1 = radius*sin(theta * PI/180);
That example works surprisingly well...
public class TestClock {
public static void main(String[] args) {
new TestClock();
}
public TestClock() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ClockPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected class ClockPane extends JPanel {
public ClockPane() {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected Point getPointTo(float angle) {
int x = Math.round(getWidth() / 2);
int y = Math.round(getHeight() / 2);
double rads = Math.toRadians(angle);
// This is an arbitrary amount, you will need to correct for this
// I'm working of a width of 200 pixels, so that makes the radius
// 100...
int radius = 100;
// Calculate the outter point of the line
int xPosy = Math.round((float) (x + Math.cos(rads) * radius));
int yPosy = Math.round((float) (y - Math.sin(rads) * radius));
return new Point(xPosy, yPosy);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
Calendar cal = Calendar.getInstance();
int seconds = cal.get(Calendar.SECOND);
float angle = -(360f * (seconds / 60f));
angle += 90; // Correct for 0 being out to the right instead of up
Point p = getPointTo(angle);
int x = getWidth() / 2;
int y = getHeight() / 2;
g2d.drawLine(x, y, p.x, p.y);
FontMetrics fm = g2d.getFontMetrics();
String text = Integer.toString(seconds);
g2d.drawString(text, getWidth() - fm.stringWidth(text), getHeight() - fm.getHeight() + fm.getAscent());
g2d.dispose();
}
}
}