So here is my problem, my professor is having us make a paint program in which we pick an item and draw on it. However, the issue is that he wants us to draw on a buffered image and then have that on top of the JPanel.
As of right now almost everything works, you can pick one of the buttons I have set up, you can draw a rectangle and resize the frame. When you do this the image of the rectangle will not go away and the JPanel will extend. However the buffered image will not extend, you can see in the code that in my paintComponent method I make a buffered image if the grid == null, and if it is then it creates a image the width and height of my board. When I try and add a call to this method any other time it does not resize since the grid is no longer equal to null. I don't know how to call a resize on a buffered image.
Any ideas would be great!
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import java.awt.event.*;
import java.awt.image.BufferedImage;
/**
*
* #author Calvin Moss
*/
public class Drawing extends JPanel implements MouseListener
{
public int x1, x2 ,y1, y2;
public static Drawing instance;
BufferedImage grid;
static Graphics2D gc;
Drawing()
{
setBackground(Color.RED);
addMouseListener(this);
}
public static Drawing getInstance()
{
if(instance == null)
instance = new Drawing();
return instance;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
int w = Board.getInstance().getWidth();
int h = Board.getInstance().getHeight();
if(grid == null)
{
grid = (BufferedImage)(this.createImage(w,h));
gc = grid.createGraphics();
gc.setColor(Color.BLUE);
BufferedImage grid;
Graphics2D gc;
}
g2.drawImage(grid, null, 0, 0);
check();
}
public void draw()
{
Graphics2D g = (Graphics2D)getGraphics();
int w = x2 - x1;
if (w<0)
w = w *(-1);
int h = y2-y1;
if (h<0)
h= h*(-1);
switch(Main.choice)
{
case 1:
{
System.out.println("double gay");
gc.drawLine(x1, y1, x2, y2);
repaint();
break;
}
case 2:
{
check();
System.out.println("quad gay");
gc.drawRect(x1, y1, w, h);
repaint();
break;
}
}
}
public void check()
{
if (x1 > x2)
{
int z = 0;
z = x1;
x1 = x2;
x2 =z;
}
if (y1 > y2)
{
int z = 0;
z = y1;
y1 = y2;
y2 = z;
}
}
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseClicked(MouseEvent e){
System.out.println("Gay");
}
public void mousePressed(MouseEvent evt)
{
x1 = evt.getX();
y1= evt.getY();
}
public void mouseReleased(MouseEvent evt)
{
x2 = evt.getX();
y2 = evt.getY();
draw();
}
}
Make the BufferedImage the size of the desktop,then you don't have to worry about resizing.
Or, add a ComponentListener to the panel. When the component resizes, create a new BufferedImage to reflect the new panel size. Then draw old buffered image on to the new one. Of course with this approach data will be lost if the panel shrinks and then grows again.
Related
I am trying to rotate a circle around a separate point in a program. right now I can get the circle to rotate but it slowly starts getting closer and closer to the point it's rotating from. I am trying to do this using JPanel and implementing it as a rectangle.
package WoffindenZone;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
import java.lang.Math;
public class Protector extends Rectangle{
double Velocity;
int speed = 3;
Protector(int x, int y, int PROTECTOR_DIAMETER){
super(x,y,PROTECTOR_DIAMETER,PROTECTOR_DIAMETER);
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode()==KeyEvent.VK_A) {
setDirection(speed);
move();
}
if(e.getKeyCode()==KeyEvent.VK_D) {
setDirection(speed);
move();
}
}
public void keyReleased(KeyEvent e){
if(e.getKeyCode()==KeyEvent.VK_A) {
setDirection(0);
move();
}
if(e.getKeyCode()==KeyEvent.VK_D) {
setDirection(0);
move();
}
}
public void setDirection(int Direction){
Velocity = Direction*Math.PI/180;
}
public void move(){
x = (int)Math.round(500 + Math.cos(Velocity) * (x-500) - Math.sin(Velocity) * (y-((1000*0.5555)/2)));
y = (int)Math.round(((1000*0.5555)/2) + Math.sin(Velocity) * (x-500) + Math.cos(Velocity) * (y-((1000*0.5555)/2)));
System.out.println(x);
System.out.println(y);
}
public void draw(Graphics g){
g.setColor(Color.blue);
g.fillOval(x,y,width,height);
}
Use a rotation instance of an AffineTransform. See getRotateInstance(theta,anchorx,anchory) for details.
Returns a transform that rotates coordinates around an anchor point. This operation is equivalent to translating the coordinates so that the anchor point is at the origin (S1), then rotating them about the new origin (S2), and finally translating so that the intermediate origin is restored to the coordinates of the original anchor point (S3).
How do you rotate a circle about a point in JPanel?
Here's how I rotate a circle about a point in a JPanel.
I don't know how to make an animated GIF. Just imagine the blue circle rotating clockwise around the center of the drawing JPanel.
So, let's start at the beginning. Basically, I have a circle rotating on the circumference of another circle. So, I create a Circle model class from plain Java.
public class Circle {
private final int radius;
private final Color color;
private Point center;
public Circle(int radius, Color color) {
this.radius = radius;
this.color = color;
}
public Point calculateCircumferencePoint(int theta) {
double radians = Math.toRadians(theta);
int x = center.x + (int) Math.round(Math.cos(radians) * radius);
int y = center.y + (int) Math.round(Math.sin(radians) * radius);
return new Point(x, y);
}
public void setCenter(int x, int y) {
this.center = new Point(x, y);
}
public void setCenter(Point center) {
this.center = center;
}
public int getRadius() {
return radius;
}
public Color getColor() {
return color;
}
public Point getCenter() {
return center;
}
}
The class consists of basic getters and setters. I make the radius and color final because they don't change value in this Java application.
The calculateCircumferencePoint method is the only interesting method. It takes an int angle in degrees, and calculates the point on the circumference represented by that angle, rounded to the nearest X and Y integer points.
Next, we create two Circle instances, an inner circle and an outer circle. Here's the class constructor setting the preferred size of the drawing area, the inner circle, and the outer circle. We start the outer circle at zero degrees (to the right);
private Circle innerCircle;
private Circle outerCircle;
private Dimension drawingPanelSize;
public RotateCircle() {
this.drawingPanelSize = new Dimension(400, 400);
int innerCircleRadius = drawingPanelSize.width / 4;
int centerX = drawingPanelSize.width / 2;
int centerY = drawingPanelSize.height / 2;
int outerCircleRadius = drawingPanelSize.width / 10;
this.innerCircle = new Circle(innerCircleRadius, null);
this.innerCircle.setCenter(centerX, centerY);
this.outerCircle = new Circle(outerCircleRadius, Color.BLUE);
Point point = innerCircle.calculateCircumferencePoint(0);
this.outerCircle.setCenter(point);
}
Now, we can start coding the GUI. First, we start the Java application by calling the SwingUtilities invokeLater method. This method ensures that we create and execute the Swing components on the Event Dispatch Thread.
Next, we define the JFrame. Here's the code we have so far.
public static void main(String[] args) {
SwingUtilities.invokeLater(new RotateCircle());
}
private Animation animation;
private Circle innerCircle;
private Circle outerCircle;
private DrawingPanel drawingPanel;
private Dimension drawingPanelSize;
public RotateCircle() {
this.drawingPanelSize = new Dimension(400, 400);
int innerCircleRadius = drawingPanelSize.width / 4;
int centerX = drawingPanelSize.width / 2;
int centerY = drawingPanelSize.height / 2;
int outerCircleRadius = drawingPanelSize.width / 10;
this.innerCircle = new Circle(innerCircleRadius, null);
this.innerCircle.setCenter(centerX, centerY);
this.outerCircle = new Circle(outerCircleRadius, Color.BLUE);
Point point = innerCircle.calculateCircumferencePoint(0);
this.outerCircle.setCenter(point);
}
#Override
public void run() {
JFrame frame = new JFrame("Rotate Circle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel(drawingPanelSize,
outerCircle);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
animation = new Animation(0);
new Thread(animation).start();
}
The JFrame methods must be called in a certain order. This is the order I use for most of my SWwing applications.
I pack the JFrame. I don't set a JFrame size. I let the Swing layout managers set the size of my JFrame. The default layout of a JFrame content pane is a BorderLayout. I put my drawing JPanel in the center of the BorderLayout.
Next, I create the drawing JPanel.
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Circle circle;
public DrawingPanel(Dimension size, Circle circle) {
this.circle = circle;
this.setBackground(Color.WHITE);
this.setPreferredSize(size);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Point center = circle.getCenter();
int radius = circle.getRadius();
int diameter = radius + radius;
g2d.setColor(circle.getColor());
g2d.fillOval(center.x - radius, center.y - radius,
diameter, diameter);
}
}
All the drawing JPanel does is paint a Circle object. Pretty straightforward.
The fillOval method paints an oval from the upper left hand corner. We calculate the upper left hand point from the center point.
The responsibility for calculating and updating the outer circle center point falls to my controller class, the Animation class. I use a simple loop to update the theta angle, calculate the new outer circle center point, paint the outer circle, and wait a period of time.
Here's that code.
public class Animation implements Runnable {
private int theta;
public Animation(int theta) {
this.theta = theta;
}
#Override
public void run() {
while (true) {
theta++;
theta = (theta >= 360) ? 0 : theta;
Point center = innerCircle.calculateCircumferencePoint(theta);
outerCircle.setCenter(center);
repaint();
sleep(30L);
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The Animation repaint method makes the call to the drawing JPanel repaint method inside another SwingUtilities invokeLater method. This method ensures that the drawing happens on the Event Dispatch Thread.
Finally, here's the complete, runnable, example. I used inner classes so I could post the code as one block, and you can copy and run this code as one block. Generally, classes should be in separate files and for a more complex GUI, separate packages.
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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RotateCircle implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new RotateCircle());
}
private Animation animation;
private Circle innerCircle;
private Circle outerCircle;
private DrawingPanel drawingPanel;
private Dimension drawingPanelSize;
public RotateCircle() {
this.drawingPanelSize = new Dimension(400, 400);
int innerCircleRadius = drawingPanelSize.width / 4;
int centerX = drawingPanelSize.width / 2;
int centerY = drawingPanelSize.height / 2;
int outerCircleRadius = drawingPanelSize.width / 10;
this.innerCircle = new Circle(innerCircleRadius, null);
this.innerCircle.setCenter(centerX, centerY);
this.outerCircle = new Circle(outerCircleRadius, Color.BLUE);
Point point = innerCircle.calculateCircumferencePoint(0);
this.outerCircle.setCenter(point);
}
#Override
public void run() {
JFrame frame = new JFrame("Rotate Circle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawingPanel = new DrawingPanel(drawingPanelSize,
outerCircle);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
animation = new Animation(0);
new Thread(animation).start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Circle circle;
public DrawingPanel(Dimension size, Circle circle) {
this.circle = circle;
this.setBackground(Color.WHITE);
this.setPreferredSize(size);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Point center = circle.getCenter();
int radius = circle.getRadius();
int diameter = radius + radius;
g2d.setColor(circle.getColor());
g2d.fillOval(center.x - radius, center.y - radius,
diameter, diameter);
}
}
public class Animation implements Runnable {
private int theta;
public Animation(int theta) {
this.theta = theta;
}
#Override
public void run() {
while (true) {
theta++;
theta = (theta >= 360) ? 0 : theta;
Point center = innerCircle.calculateCircumferencePoint(theta);
outerCircle.setCenter(center);
repaint();
sleep(30L);
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Circle {
private final int radius;
private final Color color;
private Point center;
public Circle(int radius, Color color) {
this.radius = radius;
this.color = color;
}
public Point calculateCircumferencePoint(int theta) {
double radians = Math.toRadians(theta);
int x = center.x + (int) Math.round(Math.cos(radians) * radius);
int y = center.y + (int) Math.round(Math.sin(radians) * radius);
return new Point(x, y);
}
public void setCenter(int x, int y) {
this.center = new Point(x, y);
}
public void setCenter(Point center) {
this.center = center;
}
public int getRadius() {
return radius;
}
public Color getColor() {
return color;
}
public Point getCenter() {
return center;
}
}
}
I Have 3 Questing Regarding My Code
1==> How to remove Selected Shape in my code; when i right click every shape is deleted,
2==> I TOTALLY don't know how to highlight the overlapped are
3==> right now when i click on my JPanel, shape drawn from the point where mouse clicked, where as it should be the in the center of the mouse pointer
Thanks In advance
actually i'm new to Java. this is my code,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import javax.swing.JPanel;
import javax.swing.JButton;
import Delete.Selection;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.util.ArrayList;
public class MyPanel extends JPanel {
ArrayList<MyRect> list = new ArrayList<MyRect>();
public MyPanel() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) {
MyRect r = new MyRect(e.getX(), e.getY());
list.add(r);
repaint();
}
else {
list.clear();
repaint();
}
}
}
);
setPreferredSize(new Dimension(600, 400));
setBackground(Color.CYAN);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for (int i = 0; i < list.size(); i++) {
MyRect r = list.get(i);
g.fillRect(r.x, r.y, r.w, r.h);
}
}
class MyRect {
int x, y, w=100, h=100;
Color c = Color.BLACK;
public MyRect(int x, int y, int w, int h, Color color) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.c = color;
}
public MyRect(int x, int y) {
this.x = x;
this.y = y;
}
}}
how to highlight the overlapped area
You can use the intersection(...) method of the Rectangle class to get a Rectangle to paint:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
public class IntersectingRectangles extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Dimension d = getSize();
int width = d.width * 3 / 4;
int height = d.height * 3 / 4;
Rectangle r1 = new Rectangle(0, 0, width, height);
g2d.setColor( Color.BLUE );
g2d.fill( r1 );
Rectangle r2 = new Rectangle(d.width - width, d.height - height, width, height);
g2d.setColor( Color.YELLOW );
g2d.fill( r2 );
// Specific solution when using Rectangles only
Rectangle r3 = r1.intersection(r2);
g2d.setColor(Color.GREEN);
g2d.fill(r3);
/*
// For a more generic solution using any Shape
Area area = new Area(r1);
area.intersect( new Area(r2) );
g2d.setColor(Color.GREEN);
g2d.fill(area);
*/
g2d.dispose();
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(300, 300);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Intersecting Rectangles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new IntersectingRectangles());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
How to remove Selected Shape in my code; when i right click every shape is deleted,
You need to iterate through the ArrayList containing the Rectangles. Then you can use the Rectangle.contains( yourMousePoint ) method to determine which Rectangle you clicked on. You will need to save the reference to the Rectangle. Then when the loop finishes executing you can remove the Rectangle from the ArrayList.
shape drawn from the point where mouse clicked, where as it should be the in the center of the mouse pointer
Then you need to change the x/y location of the Rectangle. It should be:
int x = mousePoint.x - (width / 2);
int y = mousePoint.y - (height / 2);
where width/height represent the size of the Rectangle you want to draw.
I've been trying to use mousePressed and mouseReleased but to no avail. The purpose of this program is to obtain an initial coordinate for the center of a circle from the mousepressed and to use the mousereleased to determine the radius of this circle. For some reason, I can't get the ball to repaint such that its center is the same position as the mousePressed(). I know that the first two parameters of the Ellipse2D object determine top-left corner of the ellipse, so if the radius length is subtracted from the x coordinate and the radius length is added to the y coordinate, shouldn't the ball appear at the first mouse click? I'm having difficulty understanding why it won't construct where I want it to.
Edit 1: Reformatted program for readability, made program compilable.
Here is the relevant portion of my program...
Main Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main{
public static void main(String[] args){
CircleComponent component = new CircleComponent();
JFrame frame = new JFrame("Bouncing Ball");
class mousePressedListener implements MouseListener
{
int x1, y1, x2, y2;
public void mouseClicked(MouseEvent e) { }
#Override
public void mouseEntered(MouseEvent e) { }
#Override
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
System.out.println(x1+ "|x1");
System.out.println(y1+ "|y1");
}
public void mouseReleased(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
System.out.println(x2 + "|x2");
System.out.println(y2 + "|y2");
frame.getHeight();
frame.getWidth();
component.moveBall(frame.getHeight(), frame.getWidth(), x1, y1, x2, y2);
}
}
class timeListener implements ActionListener{
public void actionPerformed(ActionEvent event)
{
frame.getHeight();
frame.getWidth();
component.moveBall(frame.getWidth(), frame.getHeight());
}
}
frame.add(component); //adds the ball to frame
frame.setVisible(true);
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//creates square panel with specific size and the default exit
ActionListener listener = new timeListener();
Timer timer = new Timer(500, listener);
timer.start();
frame.addMouseListener(new mousePressedListener());
}
}
CircleComponent Class
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import java.awt.Color;
public class CircleComponent extends JComponent{
private int x, y, a, b;
int radius = 50;
private Color color = Color.WHITE;
private int dx = 1, dy = 1;//initializes the speed of the ball
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setColor(color);
Ellipse2D ball = new Ellipse2D.Double(x, y, 2*radius, 2*radius);
g2.fill(ball);
}
public void moveBall(int inWidth, int inHeight){
if(x<0 || x>inWidth-65){
dx = -dx;
}
if(y<0 || y>inHeight-150) {
dy = -dy;
}
x = x + dx;
y = y + dy;
repaint();
}
public void moveBall(int inWidth, int inHeight, int x1, int y1, int x2, int y2){
double r = (double) (Math.pow((x1-x2),2) + Math.pow((y1-y2),2));
radius = (int) Math.sqrt(r);
System.out.println(radius+"|radius");
if(x<0 || x>inWidth-65){
dx = -dx;
}
if(y<0 || y>inHeight-150) {
dy = -dy;
}
x = x1-radius;
y = y1+radius;
x = x + dx;
y = y + dy;
System.out.println(x+"X"+y+"Y");
repaint();
}
}
A MouseListener needs to be added to a viable GUI component for its magic to work, and you never seem to add your MouseListener to anything. You need to call .addMouseListener(...) on your CircleComponent object and pass in your created MouseListener.
As an aside, your code as formatted is very difficult to read. Please consider editing your post and fixing your indentation style so that it is uniform and consistent. I usually avoid using tabs for indenting (forum software often doesn't play well with tabs) and indent each code block 4 spaces.
Edit
Other suggestions:
Again, add the MouseListener to the CircleComponent instance, what you name "component".
I'd not make the MouseListener an inner class, but rather make it its own stand alone class.
You don't need a reference to the JFrame in the MouseListener, only the CircleComponent instance, which you can get by passing in a reference into the MouseListener's constructor, or by calling (CircleComponent) e.getSource()
In the MouseListener get the CircleComponent's width and height.
You will need to call the super's method inside of your paintComponent override.
Your calculations are off and you will need to debug these.
I was given the assignment to make a simple paint program in java that utilizes a GUI and has basic I/O capabilities. That was all I was told to do by my professor. However, I've only made one GUI program before, so jumping straight into this paint program has been a headache. Now I'm nearly done, but the program isn't really behaving as I expected. When new objects are drawn on the Panel, they draw invisible white rectangles on the objects underneath them that erases those objects. I think this is the result of the repaint(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1); method in DrawShapes, but can't think of a way to fix it.
On the other hand, the objects are also not saving properly. I can get it to export a jpg as I intended, however, it will only export the last image drawn and not everything on the paintComponent canvas.
Lastly, the clear method in DrawShapes is working in a very similar way. When the clear method is activated, it will clear everything but the last image drawn.
Is there anyone more familiar than me with these tools that can see a way to fix these? This is only the first program I've utilized draw on, and I/O.
Here is the class for the panel that the shapes are supposed to drawn on:
/**
* #author me
*/
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class DrawShapes extends JPanel{
Point startPoint = null;
Point endPoint = null;
public int drawType = 1;
BufferedImage image;
Graphics2D g2d;
public DrawShapes(){
setBackground(Color.WHITE);
MyMouseListener m1 = new MyMouseListener();
addMouseListener(m1);
addMouseMotionListener(m1);
}//end constructor
//sets draw type, which is the decider of what is being drawn.
public void setType(int type){
if(type == 1)
{
drawType = 1;
}
else if(type == 2)
{
drawType = 2;
}
else if(type == 3)
{
drawType = 3;
}
}//end setType
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (image == null)
{
createEmptyImage();
}
g.drawImage(image, 0, 0, null);
if (startPoint != null && endPoint != null)
{
int x = Math.min(startPoint.x, endPoint.x);
int y = Math.min(startPoint.y, endPoint.y);
int width = Math.abs(startPoint.x - endPoint.x);
int height = Math.abs(startPoint.y - endPoint.y);
switch (drawType)
{
case 1:
g.drawRect(x, y, width, height);
break;
case 2:
g.drawOval(x, y, width, height);
break;
case 3:
g.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
break;
}
}
}//end paintComponent
public void save()
{
BufferedImage bi = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
this.paint(g);
g.dispose();
try{ImageIO.write(bi, "png",new File("test.png"));
}catch (Exception e){}
}
private void createEmptyImage()
{
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
g2d = (Graphics2D)image.getGraphics();
g2d.setColor(Color.BLACK);
g2d.drawString("Add a shape by clicking and dragging.", 40, 15);
}
public void addRect(int x, int y, int width, int height, Color color)
{
g2d.setColor( color );
g2d.drawRect(x, y, width, height);
repaint();
}
public void addOval(int x, int y, int width, int height, Color color)
{
g2d.setColor( color );
g2d.drawOval(x, y, width, height);
repaint();
}
public void addLine(int x1, int y1, int x2, int y2, Color color)
{
g2d.setColor(color);
g2d.drawLine(x1, y1, x2, y2);
repaint();
}
public void clear()
{
createEmptyImage();
repaint();
}
class MyMouseListener extends MouseInputAdapter
{
private int xMin;
private int xMax;
private int yMin;
private int yMax;
public void mousePressed(MouseEvent e)
{
startPoint = e.getPoint();
endPoint = startPoint;
xMin = startPoint.x;
xMax = startPoint.x;
yMin = startPoint.y;
yMax = startPoint.y;
}
public void mouseDragged(MouseEvent e)
{
//This is code I found that should make it so the only area affected by the dragging is repainted.
endPoint = e.getPoint();
xMin = Math.min(xMin, endPoint.x);
xMax = Math.max(xMax, endPoint.x);
yMin = Math.min(yMin, endPoint.y);
yMax = Math.max(yMax, endPoint.y);
repaint(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
}
public void mouseRelease(MouseEvent e)
{
//This code paints the shapes on the Buffered Image created as a canvas
int x = Math.min(startPoint.x, endPoint.x);
int y = Math.min(startPoint.y, endPoint.y);
int width = Math.abs(startPoint.x - endPoint.x);
int height = Math.abs(startPoint.y - endPoint.y);
if (width != 0 || height != 0)
{
g2d.setColor( e.getComponent().getForeground() );
// g2d.drawRect(x, y, width, height);
switch (drawType)
{
case 1:
addRect(x, y, width, height, e.getComponent().getForeground());
break;
case 2:
addOval(x, y, width, height, e.getComponent().getForeground());
break;
case 3:
addLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, e.getComponent().getForeground());
break;
}//end switch statement.
}
startPoint = null;
// repaint();
}
}
}//end class
And here is the code for the UI:
/*#author Me*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyDrawUI extends JFrame
{
private DrawShapes draw = new DrawShapes();
private JPanel ButtonPanel = new JPanel();
private JFrame window = new JFrame("Draw!");
//constructor
MyDrawUI(){
buildUI();
}
void buildUI()
{
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridLayout(2,2));
window.add(draw);
window.add(ButtonPanel, BorderLayout.SOUTH);
ButtonPanel.setBackground(Color.LIGHT_GRAY);
draw.setBackground(Color.WHITE);
//define buttons
JButton rectangle = new JButton("Rectangle");
JButton oval = new JButton("Oval");
JButton line = new JButton("Line");
JButton exit = new JButton("Exit");
JButton save = new JButton("Save");
JButton clear = new JButton("Clear");
//add buttons
ButtonPanel.add(rectangle, BorderLayout.SOUTH);
ButtonPanel.add(oval, BorderLayout.SOUTH);
ButtonPanel.add(line, BorderLayout.SOUTH);
ButtonPanel.add(clear, BorderLayout.SOUTH);
ButtonPanel.add(save, BorderLayout.SOUTH);
ButtonPanel.add(exit, BorderLayout.SOUTH);
ButtonPanel.setSize(100, 100);
save.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
draw.save();
}
});
clear.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
draw.clear();
}
});
rectangle.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
draw.setType(1);
}
});
oval.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
draw.setType(2);
}
});
line.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
draw.setType(3);
}
});
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
window.setVisible(true);
window.setSize(1024, 800);
}
}
There are a few issues I can see, the main one is the fact that you "think" you've overridden a method in the MouseAdaptor class, but haven't
mouseRelease is not method that will cause any events to trigger it. The method you're after is mouseReleased.
When overriding methods, make use the #Override annotation, it will cause a compiler error if the method you "think" you're overriding doesn't exist in any of the parent classes.
#Override
public void mouseReleased(MouseEvent e) {
Several other things pop out.
You're MyDrawUI classes extends from JFrame, but you create a instance of another JFrame called window, onto which you create your UI. In this case, drop the extends JFrame from the MyDrawUI class, as it just adds confusion...
Maintaining a reference to a Graphics context, even one you created, is ill advised in this context. On some systems, until you call dispose it's possible that nothing will be committed to the underlying implementation. Instead, simply use image.getGraphics when you need it and call g2d.dispose when you're done with it.
i have been working on mouse motion listener in Java couldn't sort it out completely because i want the object to move towards the direction where ever on the screen the mouse is pointed at but unforunately when the mouse is inside the applet window, the object moves only towards a single direction. Here is my code below..
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.applet.*;
import java.awt.event.*;
import javax.swing.*;
public class MouseOver extends Applet implements KeyListener, MouseListener,
MouseMotionListener {
private int[] Xpoints = { 0, -5, 5 };
private int[] Ypoints = { -10, -2, -2 };
private double xpos, ypos;
private Polygon poly;
int polyrot = 0;
private int width; // !! added
private int height; // !! added
public void init() {
poly = new Polygon(Xpoints, Ypoints, Xpoints.length);
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform id = new AffineTransform();
width = getSize().width;
height = getSize().height;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.RED);
g2d.draw(poly);
g2d.translate(width / 2, height / 2);
g2d.rotate(Math.toRadians(polyrot));
g2d.scale(5, 5);
}
public void keyReleased(KeyEvent k) {
}
public void keyTyped(KeyEvent k) {
}
public void keyPressed(KeyEvent k) {
switch (k.getKeyCode()) {
case KeyEvent.VK_LEFT:
if (polyrot < 0) {
polyrot = 359;
polyrot++;
}
repaint();
break;
case KeyEvent.VK_RIGHT:
if (polyrot > 360) {
polyrot = 0;
polyrot--;
}
repaint();
break;
}
}
public void mouseEntered(MouseEvent m) {
}
public void mouseExited(MouseEvent m) {
}
public void mouseReleased(MouseEvent m) {
}
public void mouseClicked(MouseEvent m) {
}
public void mousePressed(MouseEvent m) {
switch (m.getButton()) {
case MouseEvent.BUTTON1:
if (polyrot < 0) {
polyrot = 359;
polyrot--;
}
repaint();
break;
case MouseEvent.BUTTON2:
if (polyrot > 360) {
polyrot = 0;
polyrot++;
}
repaint();
break;
}
}
public void mouseMoved(MouseEvent e) {
xpos = getX();
if (xpos < 0) {
polyrot--;
} else if (xpos > 0) {
polyrot++;
}
repaint();
// !! break; // Doesn't belong here
}
#Override
public void mouseDragged(MouseEvent e) {
// You forgot this method
}
}
Your problem is with this line:
public void mouseMoved(MouseEvent e){
xpos=getX(); // ******
if(xpos<0){polyrot--;}
else if(xpos>0){polyrot++;}
repaint();
break;
}
That returns the x position of the applet not the mouse cursor. You need to use your MouseEvent object, e and instead get the mouse's position. Change it to:
xpos = e.getX();
Please don't ignore the comment that I made to your question. Please remember that we're volunteers who help on our free time. Please don't make it any more difficult than it has to be to help you.
I've tried to edit your code so that it compiles, and now is indented. Consider creating a Swing application, not an AWT application, since Swing apps are more flexible, powerful and robust.
This:
if (xpos < 0) {
means "if the cursor is outside of the panel".
This:
xpos = getX();
does not get a mouse coordinate.
Change your event to something like this:
public void mouseMoved(MouseEvent e) {
xpos = e.getX();
if (xpos < getWidth() / 2) {
polyrot--;
} else {
polyrot++;
}
repaint();
}
Now it rotates counter-clockwise if the cursor is on the left side of the panel and clockwise if the cursor is on the right side.
This:
g2d.draw(poly);
g2d.translate(width / 2, height / 2);
g2d.rotate(Math.toRadians(polyrot));
g2d.scale(5, 5);
will not do anything to change the image because you are doing your transforming after drawing it.
This:
Graphics2D g2d = (Graphics2D) g;
is a bad idea because you are applying transforms to the global graphics context which would carry on to subsequent repaints of other components.
Change your paint to something like this:
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g.create();
width = getSize().width;
height = getSize().height;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height);
g2d.translate(width / 2, height / 2);
g2d.rotate(Math.toRadians(polyrot));
g2d.scale(5, 5);
g2d.setColor(Color.RED);
g2d.draw(poly);
g2d.dispose();
}
Further reading:
Painting in AWT and Swing
How to Write a Mouse Listener
There are a few things...
In your keyPressed and mousePressed events, are are only ever process the out of bounds conditions, for example...
if (polyrot < 0) {
polyrot = 359;
polyrot++;
}
//...
if (polyrot > 360) {
polyrot = 0;
polyrot--;
}
But you never process what it should do when it's within the acceptable bounds (0-359)...
Instead, you could simply add or subtract the amount from polyrot and allow the API to deal with it (surprisingly, it's capable for dealing with angles < 0 and > 359), for example...
public void mousePressed(MouseEvent m) {
switch (m.getButton()) {
case MouseEvent.BUTTON1:
polyrot--;
repaint();
break;
case MouseEvent.BUTTON2:
polyrot++;
repaint();
break;
}
}
Now, I'm not sure what you mean by "object to move towards the direction where ever on the screen the mouse is pointed". Does this mean that the object should actually change it's x/y coordinates or should it just "look" at the mouse cursor...
Based on the fact that you actually have no movement code and you basically have the object painted in a fixed location, I'm assuming "look at"...
Basically, you need to know where the mouse is and where the object is, then determine the angle between them...
public void mouseMoved(MouseEvent e) {
int x = width / 2;
int y = height / 2;
Point mousePoint = e.getPoint();
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
polyrot = -Math.atan2(deltaX, deltaY);
polyrot = Math.toDegrees(polyrot) + 180;
repaint();
}
You should note that I changed 'polyrot' to 'double'
Your paint method is also wrong. Basically, you are painting your object BEFORE you've transformed it, instead, you should be using something more like...
g2d.translate(width / 2, height / 2);
g2d.rotate(Math.toRadians(polyrot));
g2d.draw(poly);
You should also be calling super.paint(g) before you apply you own custom painting...
As a side note, you should avoid overriding paint of top level containers, like JApplet, but instead, create a custom component, extending from something like JPanel and override it's paintComponent method, performing your custom painting there (don't forget to call super.paintComponent). Take a look at Performing Custom Painting for more details
You should also avoid using KeyListener and instead use the Key Bindings API as it doesn't suffer from the same focus issues that KeyListener does...
Updated with runnable example
So I had a play around with code and produced this simple example...
Basically, I tossed out Polygon in favour of Path2D, basically because it provides much greater functionality and is easy to deal with when scaling ;)
import java.applet.Applet;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
public class MouseOver extends Applet implements KeyListener, MouseListener,
MouseMotionListener {
private double xpos, ypos;
private Path2D poly;
private double polyrot = 0;
private int width; // !! added
private int height; // !! added
public void init() {
poly = new Path2D.Double();
poly.moveTo(0, 10);
poly.lineTo(5, 0);
poly.lineTo(10, 10);
poly.lineTo(0, 10);
poly.closePath();
addKeyListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
public void paint(Graphics g) {
super.paint(g);;
Graphics2D g2d = (Graphics2D) g;
AffineTransform id = new AffineTransform();
width = getSize().width;
height = getSize().height;
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.RED);
id.scale(5, 5);
Shape scaled = poly.createTransformedShape(id);
Rectangle bounds = scaled.getBounds();
g2d.translate((width - bounds.width) / 2, (height - bounds.height) / 2);
g2d.rotate(Math.toRadians(polyrot), bounds.width / 2, bounds.height / 2);
g2d.setStroke(new BasicStroke(5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.draw(scaled);
}
public void keyReleased(KeyEvent k) {
}
public void keyTyped(KeyEvent k) {
}
public void keyPressed(KeyEvent k) {
switch (k.getKeyCode()) {
case KeyEvent.VK_LEFT:
polyrot++;
repaint();
break;
case KeyEvent.VK_RIGHT:
polyrot--;
repaint();
break;
}
}
public void mouseEntered(MouseEvent m) {
}
public void mouseExited(MouseEvent m) {
}
public void mouseReleased(MouseEvent m) {
}
public void mouseClicked(MouseEvent m) {
}
public void mousePressed(MouseEvent m) {
switch (m.getButton()) {
case MouseEvent.BUTTON1:
polyrot--;
repaint();
break;
case MouseEvent.BUTTON2:
polyrot++;
repaint();
break;
}
}
public void mouseMoved(MouseEvent e) {
int x = width / 2;
int y = height / 2;
Point mousePoint = e.getPoint();
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
polyrot = -Math.atan2(deltaX, deltaY);
polyrot = Math.toDegrees(polyrot) + 180;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
// You forgot this method
}
}
From here:
public void mouseMoved(MouseEvent e){
xpos=getX();
if(xpos<0){polyrot--;}
else if(xpos>0){polyrot++;}
repaint();
break;
}
It seems you update only the xpos. You should update also the variable ypos.
You might want to do it with something like this:
ypos=e.getY();
if (this.ypos<0){
this.polyrot--;
}else if (this.ypos>0) {
this.polyrot++;
}
this.repaint();