My question has been alluded to in java draw line as the mouse is moved, however, I have not advanced far enough into this book to have covered JPanels, JFrames and Points as stated by the prior programmer who asked this question.
Answering this question definitely would help most beginner programmers better understand the graphics class and drawing, an often intricate process, especially for beginners.
According to the text I am using (as I am learning Java on my own), this was the example of how to draw a line using Java:
/*
* LineTest
* Demonstrates drawing lines
*/
import java.awt.*;
public class LineTest extends Canvas {
public LineTest() {
super();
setSize(300, 200);
setBackground(Color.white);
}
public static void main(String args[]) {
LineTest lt = new LineTest();
GUIFrame frame = new GUIFrame("Line Test");
frame.add(lt);
frame.pack();
frame.setVisible(true);
}
public void paint(Graphics g) {
g.drawLine(10, 10, 50, 100);
g.setColor(Color.blue);
g.drawLine(60, 110, 275, 50);
g.setColor(Color.red);
g.drawLine(50, 50, 300, 200);
}
}
The specification is:
Create an application that allows you to draw lines by clicking the initial
point and dragging the mouse to the second point. The application should
be repainted so that you can see the line changing size and position as you
are dragging the mouse. When the mouse button is released, the line is
drawn.
As you will recognize, running this program does not create any drawing by the user. I believe this error is encountered due to line 21: g.drawLine(x, y, x2, y2); being incorrect since this is the statement defining the drawing of the line.
Any help is greatly appreciated. Thank you in advance for all your time and cooperation regarding this matter.
My code to answer the question is:
import java.awt.*;
import java.awt.event.*;
public class LineDrawer extends Canvas
implements MouseListener, MouseMotionListener {
int x, y, x2, y2;
public LineDrawer() {
super();
setSize(300, 200);
setBackground(Color.white);
}
public void mouseClicked(MouseEvent me) {
int x = me.getX();
int y = me.getY();
int x2 = me.getX();
int y2 = me.getY();
}
public void paint(Graphics g) {
g.drawLine(x, y, x2, y2);
g.setColor(Color.blue);
}
public void mousePressed(MouseEvent me) {
repaint();
}
public void mouseDragged(MouseEvent me) {
}
public void mouseExited(MouseEvent me) {
}
public void mouseEntered(MouseEvent me) {
}
public void mouseReleased(MouseEvent me) {
}
public void mouseMoved(MouseEvent me) {
}
public static void main(String args[]) {
LineDrawer ld = new LineDrawer();
GUIFrame frame = new GUIFrame("Line Drawer");
frame.add(ld);
frame.pack();
frame.setVisible(true);
}
}
P.S.: I have been hesitant to ask for help since I am concerned that other programmers would answer with methods that I have not yet learned.
int x1, y1, x2, y2;
public void mousePressed(MouseEvent e){
x1 = e.getX();
y1 = e.getY();
}
public void mouseDragged(MouseEvent e){
x2 = e.getX();
y2 = e.getY();
// Now Paint the line
repaint();
}
Hope it helps.
Let's start with
public void mouseClicked(MouseEvent me) {
int x = me.getX();
int y = me.getY();
int x2 = me.getX();
int y2 = me.getY();
}
You have previous declared x, y, x2 and y2, but in this method, you have overridden those decelerations with new ones, meaning that the previous declared variables will not be used and the event parameters will be ignored.
mouseClicked is fired AFTER a mousePressed and mouseReleased event, meaning that this is actually when the user has released the mouse button.
Extreme Coder has pointed out that MouseClicked is only fired when the mouse button is pressed and released at the same point, i.e. no dragging is involved - it's still not the right method to use, but the clarification is nice
What you should do is...
On mousePressed store the x, y position of the click and on mouseReleased store the x2, y2 position.
On the mouseDragged event, you should update the x2, y2 values and call repaint
public void mousePressed(MouseEvent me) {
// Mouse is down, but hasn't yet being released...
x = me.getX();
y = me.getY();
// We need to "override" any previous values...
x2 = x;
y2 = y;
repaint();
}
public void mouseDragged(MouseEvent me) {
x2 = me.getX();
y2 = me.getY();
repaint();
}
public void mouseReleased(MouseEvent me) {
// Here I would store the points so I could re-draw each new line...
}
Instead of using x, y, x2 and y2, it might be better to use two arrays, ie
private int[] startPoint;
private int[] endPoint;
Then you could do something like...
public void mousePressed(MouseEvent me) {
// Mouse is down, but hasn't yet being released...
startPoint = new int[2];
startPoint[0] = me.getX();
startPoint[1] = me.getY();
endPoint = startPoint;
repaint();
}
public void mouseDragged(MouseEvent me) {
endPoint = new int[2];
endPoint[0] = me.getX();
endPoint[1] = me.getY();
repaint();
}
Now I prefer paintComponent from JComponent, but I'll stick to you example for now..
public void paint(Graphics g) {
super.paint(g); // This is super important...
if (startPoint != null && endPoint != null && startPoint.length == 2 && endPoint.length == 2) {
g.drawLine(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
}
}
Additional
This is of some concern...
public void paint(Graphics g) {
g.drawLine(x, y, x2, y2);
g.setColor(Color.blue);
}
The order of operation is VERY important. Setting the color AFTER you've painted the line with have no effect on you paint operations (but may effect paint operations that occur after you).
Also, you MUST call super.paint(g) - this is super important...
Examples
A "basic" example, using int[] arrays for point storage...
public class BasicLineDraw {
public static void main(String[] args) {
new BasicLineDraw();
}
public BasicLineDraw() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new DrawLinePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawLinePane extends JPanel {
private int[] startPoint;
private int[] endPoint;
private List<int[][]> lines;
public DrawLinePane() {
lines = new ArrayList<int[][]>(25);
MouseAdapter handler = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
startPoint = new int[]{e.getX(), e.getY()};
endPoint = startPoint;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
endPoint = new int[]{e.getX(), e.getY()};
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (startPoint != null && endPoint != null && startPoint.length == 2 && endPoint.length == 2) {
lines.add(new int[][]{startPoint, endPoint});
}
startPoint = null;
endPoint = null;
repaint();
}
};
addMouseListener(handler);
addMouseMotionListener(handler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (startPoint != null && endPoint != null && startPoint.length == 2 && endPoint.length == 2) {
g2d.setColor(Color.RED);
g2d.drawLine(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
}
g2d.setColor(Color.BLUE);
for (int[][] line : lines) {
g2d.drawLine(line[0][0], line[0][1], line[1][0], line[1][1]);
}
g2d.dispose();
}
}
}
And a more advanced example, using Point and Java's 2D Graphics API
public class LineDrawer {
public static void main(String[] args) {
new LineDrawer();
}
public LineDrawer() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new DrawLinePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawLinePane extends JPanel {
private Point anchor;
private Point lead;
private List<Line2D> lines;
public DrawLinePane() {
lines = new ArrayList<Line2D>(25);
MouseAdapter handler = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
lead = null;
anchor = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
lead = e.getPoint();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (lead != null && anchor != null && !anchor.equals(lead)) {
lines.add(new Line2D.Float(anchor, lead));
}
repaint();
}
};
addMouseListener(handler);
addMouseMotionListener(handler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
if (lead != null && anchor != null) {
Composite composite = g2d.getComposite();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f));
g2d.draw(new Line2D.Float(anchor, lead));
g2d.setComposite(composite);
}
for (Line2D line : lines) {
g2d.draw(line);
}
g2d.dispose();
}
}
}
Related
I'm attempting to make a little paint app where you input the color you want, and change the size of the brush. I did this, and it works, but if I try to paint quickly, the app doesn't update for a short period of time, leaving dots looking like this:
60 times per second (because 60 times per second should be enough to not leave dots/gaps. See tick method. As a test, I tried putting no limit on the ticksPerSecond, and I got the same output), if the user is causing a mouseDragged or mousePressed event, I add a an instance of the Circle class (seen below)
class Circle {
int x, y;
int radius;
Color color;
Circle(int x, int y, int radius, Color color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
}
}
My tick method: (Called 60 times each second)
private void tick() {
this.middle = this.brush.radius / 2; // Used because java.awt.Graphics will paint from your cursors xy, which will paint the circle down and to the right of the cursor
if (this.frame.isDragging) {
add(new Circle(this.frame.x - this.middle, this.frame.y - this.middle, this.brush.radius, this.brush.color));
}
}
To render, I just run through a foreach loop, seen below
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Paint over everything else
try {
for (Circle circle : this.circles) {
g.setColor(circle.color);
g.fillOval(circle.x, circle.y, circle.radius, circle.radius);
}
} catch (ConcurrentModificationException ignore) {} //TODO MAKE THIS BETTER
}
Ignore that I'm catching a ConcurrentModifictionException, this is a temporary fix because I'm adding to a list that's being read here. (It only causes the paint to flash while I am painting, so it works for now)
I was asked for my Frame, here it is (You probably don't need this, but I included any code you needed. I remove implement methods that I didn't use):
class Frame extends JFrame implements MouseListener, MouseMotionListener {
int x, y;
boolean isDragging, isMouseOnScreen;
Frame(int width) {
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.getContentPane().setPreferredSize(new Dimension(width, width / 3 * 2));
this.setResizable(false);
this.pack();
this.setLocationRelativeTo(null);
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Cursor cursor = this.getToolkit().createCustomCursor(image, new Point(0, 0), "Cursor");
this.setCursor(cursor);
this.setFocusable(true);
this.requestFocus();
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.x = this.y = 0;
this.isDragging = this.isMouseOnScreen = false;
}
#Override
public void mouseDragged(MouseEvent e) {
this.x = e.getX() - 5;
this.y = e.getY() - 35;
}
#Override
public void mouseMoved(MouseEvent e) {
this.x = e.getX() - 5;
this.y = e.getY() - 35;
}
#Override
public void mousePressed(MouseEvent e) {
this.isDragging = true;
}
#Override
public void mouseReleased(MouseEvent e) {
this.isDragging = false;
}
#Override
public void mouseEntered(MouseEvent e) {
isMouseOnScreen = true;
}
#Override
public void mouseExited(MouseEvent e) {
isMouseOnScreen = false;
}
}
I'm trying to create a program that able the user to drag and drop the oval around in the space. I was able to drag and drop but after I tried do it again on the second run, the oval jump all over the places. I was wondering if anyone know why this happen? Am i missing something? Thank you
public class MoveOval extends JFrame {
private Ellipse2D node = new Ellipse2D.Float(200,200,80,120);
private Point offset;
private int preX,preY;
private Image dbImage;
private Graphics dbg;
Adapter ma = new Adapter();
public static void main(String args[]){
JFrame frame = new MoveOval();
frame.setSize(600,600);
frame.setVisible(true);
}
public MoveOval(){
super("Move Oval");
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(ma);
addMouseMotionListener(ma);
}
private class Adapter extends MouseAdapter{
public void mousePressed(MouseEvent e){
if(node.contains(e.getPoint())){
preX = node.getBounds().x-e.getX();
preY = node.getBounds().y-e.getX();
offset = new Point(preX, preY);
}
}
public void mouseDragged(MouseEvent e){
if(node.contains(e.getPoint())){
updateLocation(e);
}
}
public void mouseReleased(MouseEvent e) {
offset=null;
}
}
public void updateLocation(MouseEvent e){
Point to = e.getPoint();
to.x += offset.x;
to.y += offset.y;
Rectangle bounds = node.getBounds();
bounds.setLocation(to);
node.setFrame(bounds);
repaint();
}
public void paint(Graphics g){
dbImage=createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g){
Graphics2D gd = (Graphics2D)g.create();
gd.setColor(Color.blue);
gd.fill(node);
}
}
Actually a very simple mistake and easy to fix.
public void mousePressed(MouseEvent e){
if(node.contains(e.getPoint())){
preX = node.getBounds().x-e.getX();
preY = node.getBounds().y-e.getX(); // <- That's the bad guy.
offset = new Point(preX, preY);
}
}
It has to be -e.getY() not -e.getX().
My boolean drawFlag is being set to false in my code with nothing visible actually telling it to change value to false. This is preventing the code inside method mouseDragged(mouseEvent) to execute. If someone could point out what's making the flag become false so this would stop happening? Thanks.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class DrawAndDrag {
public static void main(String[] args) throws InterruptedException {
GraphicsFrame window = new GraphicsFrame("Draw Rectangle");
window.init();
}
}
class GraphicsFrame extends JFrame {
public GraphicsFrame(String title) {
super(title);
}
public void init() {
Container pane = this.getContentPane();
pane.add(new GraphicsContent().init());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(600, 600);
this.setVisible(true);
}
}
class GraphicsContent extends JPanel {
private int xStart, yStart;
private int width, height;
public JPanel init() {
this.setBackground(Color.WHITE);
this.addMouseListener(new MouseDrag());
this.addMouseMotionListener(new MouseDrag());
return this;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(xStart, yStart, width, height);
}
class MouseDrag implements MouseListener, MouseMotionListener {
private boolean drawFlag;
public void mousePressed(MouseEvent e) {
if(isOutside(e)) {
this.drawFlag = true;
xStart = e.getX();
yStart = e.getY();
width = 0; height = 0;
System.out.println(drawFlag);
}else {
// this.drawFlag = false;
}
}
public void mouseDragged(MouseEvent e) {
System.out.println(drawFlag);
if(drawFlag) {
width = e.getX() - xStart;
height = e.getY() - yStart;
repaint();
}
}
public boolean isOutside(MouseEvent e) {
int xMin = Math.min(xStart, xStart + width); int yMin = Math.min(yStart, yStart + height);
int xMax = Math.max(xStart, xStart + width); int yMax = Math.max(yStart, yStart + height);
if((e.getX() < xMin || e.getX() > xMax)
|| (e.getY() < yMin || e.getY() > yMax)) {
return true;
}else {
return false;
}
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
}
}
Try to move drawFlag attribute from the inner class MouseDrag to the outer class GraphicsContent as follow
class GraphicsContent extends JPanel {
private int xStart, yStart;
private int width, height;
private volatile boolean drawFlag;
// other code
}
However as you drag, the value is constantly being reported as being false
You've got two listeners. One is a motion listener:
this.addMouseListener(new MouseDrag());
this.addMouseMotionListener(new MouseDrag());
mousePressed will not be called on a motion listener, so it will always be false in the drag event.
I expect what you meant is this:
MouseDrag listener = new MouseDrag();
this.addMouseListener(listener);
this.addMouseMotionListener(listener);
Are you sure you need two MouseDrag elements? I.e. using something like
public JPanel init() {
this.setBackground(Color.WHITE);
MouseDrag md = new MouseDrag();
this.addMouseListener(md);
this.addMouseMotionListener(md);
return this;
}
I can at least plot a blue square....
I've got a problem with connecting two classes:
This is the code with basic operations on JPanel:
public class Drawing extends JPanel {
Pencil pencil;
Tool lines;
Tool paintbrush;
public Drawing() {
setBackground(Color.WHITE);
pencil = new Pencil();
addMouseListener(pencil);
addMouseMotionListener(pencil);
addMouseListener(lines);
addMouseMotionListener(lines);
addMouseListener(paintbrush);
addMouseMotionListener(paintbrush);
this.repaint();
}
#Override
public void paintComponent(Graphics g) {
pencil.paintComponent(g);
super.paintComponent(g);
}
}
and this is a specific tool called Pencil, to draw on above JPanel:
public class Pencil implements MouseListener, MouseMotionListener {
private int x, y;
private ArrayList<ArrayList<Point>> pointsList = new ArrayList<ArrayList<Point>>();
private ArrayList<Color> Colors = new ArrayList<Color>();
public Pencil() {
System.out.println("PENCIL SELECTED!");
}
public void paintComponent(Graphics g) {
// super.paintComponent(g);
((Graphics2D) g).setStroke(new BasicStroke(2));
for(int i=0; i<pointsList.size(); i++) {
ArrayList<Point> Points = pointsList.get(i);
Color pencilColor = Colors.get(i);
g.setColor(pencilColor);
for(int j=0; j<Points.size()-1; j++) {
Point p1, p2 = null;
p1 = Points.get(j);
p2 = Points.get(j+1);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
#Override
public void mousePressed(MouseEvent e) {
ArrayList<Point> Points = new ArrayList<Point>();
Color pencilColor = GUI.getColour();
Colors.add(pencilColor);
pointsList.add(Points);
x = e.getX();
y = e.getY();
pointsList.get(pointsList.size()-1).add(new Point(x, y));
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
pointsList.get(pointsList.size()-1).add(new Point(x, y));
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
x = e.getX();
y = e.getY();
pointsList.get(pointsList.size()-1).add(new Point(x, y));
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
Compiler says, Pencil class does not have repaint() method.
I have no idea, how to connect these two classes...
Thanks for help in advance! :)
As the error said, the Pencil class has no repaint() method and it doesn't inherit a repaint() method from a superclass, as the Drawing class does.
One way to solve this would be to pass the Drawing instance to the Pencil instance.
like this:
public Drawing() {
setBackground(Color.WHITE);
pencil = new Pencil(this); // send the instance to `Pencil` by constructor.
addMouseListener(pencil);
addMouseMotionListener(pencil);
addMouseListener(lines);
addMouseMotionListener(lines);
addMouseListener(paintbrush);
addMouseMotionListener(paintbrush);
this.repaint();
}
In Pencil :
private Drawing drawingBoard;
public Pencil(Drawing drawingBoard) {
System.out.println("PENCIL SELECTED!");
this.drawingBoard = drawingBoard;
}
Now when you call repaint(), call it like this: drawingBoard.repaint()
I have some code to draw rectangles. It's used to draw rectangles on a JPanel, to mark boundaries of widgets. Here the code first, after that I'll explain my problem cq. question.
First off, I have a class (WidgetDrawingPanel) which extends JPanel.
public WidgetDrawingPanel(int width, int height) {
/*To make things visible at least*/
widgets.add(new Widget(10,10,100,100, WidgetType.TextField));
widgets.add(new Widget(50,50,100,200, WidgetType.TextField));
this.width = width;
this.height = height;
this.setBackground(Color.BLUE);
addListener(); //adds both MouseMotionListener and MouseListener
}
Below you'll see me reference ch a lot. This is a CoordinateHolder, which holds start and current coordinates of my mouse movement.
private void addListener() {
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent arg0) {
ch.currentX = arg0.getX();
ch.currentY = arg0.getY();
System.out.println("dragging " + ch.currentX + ","+ch.currentY);
WidgetDrawingPanel.this.repaint();
}
});
this.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent event) {
ch.endX = event.getX();
ch.endY = event.getY();
try {
checkCoords();
} catch (OutsidePanelException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "drawn Outside Panel");
}
}
#Override
public void mousePressed(MouseEvent event) {
ch = new CoordinateHolder(event.getX(), event.getY());
}
});
}
and, finally, the paintComponent(Grapics) method. There's loop through Widgets, which are actually just already drawn Rects (x, y, w, h attributes), but which a little more information, which is not useful in the drawing part of the application. Everytime you release the mouse, the CoordinateHolder is converted into a Widget, and added to widgets.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Paint");
g.setColor(Color.BLUE);
g.fillRect(0, 0, width, height); //making the whole panel blue
g.setColor(Color.RED);
Graphics2D g2 = (Graphics2D)g;
g2.setStroke(new BasicStroke(3));
for (Widget w : widgets) {
g.drawRect(w.getX(), w.getY(), w.getW(), w.getH());
}
if (ch != null)
g.drawRect(ch.startX, ch.startY, ch.currentX - ch.startX, ch.currentY - ch.startY);
}
This code is working, but I suspect this is highly inefficient and inperformant, as above code continually refreshes the JPanel on mouse drag, which is, say, once every 10ms? I suppose it'll get slow really soon, especially when the user creates a heck of a lot rectangles (which are also continally redrawn, as seen in painComponent(Graphics)).
Question cq. Problem
Is there a better, less resource consuming method, where the user can drag rectangles smoothly?
I read an answer to this Drag rectangle on JFrame in Java, but the author of that answer seems to do it the same as me. But again, that's way inperformant, right? Or should computers be easily able to redraw the component continually, and is this actually a valid approach?
To show lots of non-changing background shapes, draw them to a BufferedImage and then show that BufferedImage in the paintComponent(...) method. So while a shape is being drawn, draw it in paintComponent(...) but once the shape is done being drawn, perhaps on mouseRelease, then draw it in the background BufferedImage.
Note that what will slow your current drawing code the most may be your debugging SOP statements, but I assume that these will be removed from the finished code.
For example:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final Color DRAWING_COLOR = new Color(255, 100, 200);
private static final Color FINAL_DRAWING_COLOR = Color.red;
private BufferedImage backgroundImg;
private Point startPt = null;
private Point endPt = null;
private Point currentPt = null;
public DrawingPanel() {
backgroundImg = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics g = backgroundImg.getGraphics();
g.setColor(Color.blue);
g.fillRect(0, 0, PREF_W, PREF_H);
g.dispose();
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseMotionListener(myMouseAdapter);
addMouseListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
if (startPt != null && currentPt != null) {
g.setColor(DRAWING_COLOR);
int x = Math.min(startPt.x, currentPt.x);
int y = Math.min(startPt.y, currentPt.y);
int width = Math.abs(startPt.x - currentPt.x);
int height = Math.abs(startPt.y - currentPt.y);
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void drawToBackground() {
Graphics g = backgroundImg.getGraphics();
g.setColor(FINAL_DRAWING_COLOR);
int x = Math.min(startPt.x, endPt.x);
int y = Math.min(startPt.y, endPt.y);
int width = Math.abs(startPt.x - endPt.x);
int height = Math.abs(startPt.y - endPt.y);
g.drawRect(x, y, width, height);
g.dispose();
startPt = null;
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent mEvt) {
currentPt = mEvt.getPoint();
DrawingPanel.this.repaint();
}
#Override
public void mouseReleased(MouseEvent mEvt) {
endPt = mEvt.getPoint();
currentPt = null;
drawToBackground();
}
#Override
public void mousePressed(MouseEvent mEvt) {
startPt = mEvt.getPoint();
}
}
private static void createAndShowGui() {
DrawingPanel mainPanel = new DrawingPanel();
JFrame frame = new JFrame("Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}