Drawing a line from 2 mouse clicks - java

I am trying to draw a line from a series of mouse clicks.
For example, when i click from one point on the screen to the next, it connects up the lines, and then i can keep clicking to next points where it continues to draw a continuous drawing line.
An example is here: http://oneslime.net/java/Tutorial_2 under Exercise 2
I believe there is some error in my logic (does not draw lines, just a point), but I just can't seem to find it!
Can anybody help me out?
Here is my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class RoadCreator extends JPanel {
private MouseHandler mouseHandler = new MouseHandler();
private Point previousPoint = new Point();
private Point nextPoint = new Point();
private boolean drawing;
public RoadCreator() {
this.setPreferredSize(new Dimension(640, 480));
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
g.drawLine(previousPoint.x, previousPoint.y, nextPoint.x, nextPoint.y);
}
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
drawing = true;
nextPoint = e.getPoint();
repaint();
previousPoint = e.getPoint();
}
}
public void display() {
JFrame f = new JFrame("Road Creator");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setVisible(true);
}
}
Any help would be GREATLY appreciated, thank you!

Use a GeneralPath or Path2D instead.
The GeneralPath class represents a geometric path constructed from straight lines, and quadratic and cubic (Bézier) curves. It can contain multiple subpaths.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.GeneralPath;
public class RoadCreator extends JPanel {
private MouseHandler mouseHandler = new MouseHandler();
GeneralPath path = null;
private boolean drawing = false;
public RoadCreator() {
this.setPreferredSize(new Dimension(320, 200));
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(8,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
if (path!=null) {
g2d.draw(path);
}
}
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
if (!drawing) {
path = new GeneralPath();
path.moveTo(p.x, p.y);
drawing = true;
} else {
path.lineTo(p.x, p.y);
}
repaint();
}
}
public void display() {
JFrame f = new JFrame("Road Creator");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
RoadCreator rc = new RoadCreator();
rc.display();
}
}

This won't work.
public void mousePressed(MouseEvent e) {
drawing = true;
nextPoint = e.getPoint();
repaint();
previousPoint = e.getPoint();
}
You're assuming that repaint is a inline call (ie it paints before returning). It doesn't, repaint will queue a request to the repaint manager that will update at some time in the future.
public void mousePressed(MouseEvent e) {
drawing = true;
previousPoint = nextPoint
nextPoint = e.getPoint();
repaint();
}
Should work, just be aware, previousPoint will be null until the user clicks a second time.

I have found a way to accomplish this task with as little effort as possible. However this does not equate to a "good" way of creating the application. You would need to account for future scalability such as the ability to draw other objects...etc. So let's just get down to how to make it work.
1) Let's omit the paintComponent method...I believe this should be paint().
//#Override
/*protected void paintComponent(Graphics g) {
//Do Something...
}*/
2) Let's add this method:
public void drawLineHelper(Point prev, Point next){
Graphics g = getGraphics();
g.setColor(Color.blue);
g.drawLine(previousPoint.x, previousPoint.y, nextPoint.x, nextPoint.y);
}
3) Lastly, we need to make a few changes to the mouseHandler class:
private class MouseHandler extends MouseAdapter {
//twoPoints make sure we have two points.
boolean twoPoints=false;
#Override
public void mousePressed(MouseEvent e) {
if(twoPoints==false){
nextPoint = e.getPoint();
twoPoints = true;
}
else{
//Set previous to next from now on.
previousPoint = nextPoint;
//Get a new next point.
nextPoint = e.getPoint();
//Helper method will draw the line each time.
drawLineHelper(previousPoint,nextPoint);
//repaint() no longer necessary.
}
}
}
Here is a quick reference to another example with the same problem. The last post on the page explains this same method: http://www.ozzu.com/programming-forum/java-repainting-problem-t49362.html

Related

Add a JComponent via Child to Parent

I want to accomplish something very similar to the image a Rectangle whit a Selector Line.
Basically, I have a Rectangle and I want to have a selector line all around it.
For that, I wanted to create an additional JComponent.
At the moment I can only draw the Rectangle. How could I get the parentPanel JPanel inside the Rectangle class, so that I could add the selector?
public class TestPanel extends JFrame {
public class Rectangle extends JComponent {
public Rectangle(){
setBounds(x1, y1, x2, y2);
JPanel Selector = new JPanel();
//Adds Selector to parentPanel within Rectangle
//setBounds(x1-1, y1-1, x2+1, y2+1)
//!Problem parent is initially null! cant even a use property
//Life hacks?
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, getWidth(), getHeight());
}
}
public TestPanel() {
Rectangle Rectangle = new Rectangle();
JPanel parentFrame = new JPanel();
parentFrame.add(Rectangle);
setSize(200, 200);
setVisible(true);
}
public static void main(String[] args) {
new TestPanel();
}
}
If I try to add the selector inside the rectangle, it will get out of the drawing area. If I resize the drawing area, it won't be scalable for later development.
If possible I would avoid dual binding like:
public TestPanel() {
Rectangle Rectangle = new Rectangle();
JPanel parentPanel = new JPanel();
parentPanel.add(Rectangle);
Rectangle.addParent(parentPanel)
...
}
Again, I'm not 100% clear on what you're trying to achieve. If what you wish to create is a user-created dashed line, one that can change with mouse press/drag/release, then you don't need to create a new component but rather use a MouseAdapter as a MouseListener and MouseMotionListener, all to help you create the Rectangle, and then simply draw the Rectangle with a dashed line using an appropriate Stroke, as per this answer.
For example, something like would create a dashed line that is user-selectable:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class SelectorPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Stroke DASHED_STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 5 }, 0);
private static final Color DASHED_COLOR = Color.LIGHT_GRAY;
private Rectangle rectangle = null;
public SelectorPanel() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
private class MyMouse extends MouseAdapter {
private Point p1 = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
rectangle = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 != null) {
createRectangle(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p1 != null) {
createRectangle(e);
p1 = null;
}
}
private void createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int width = Math.abs(p1.x - p2.x);
int height = Math.abs(p1.y - p2.y);
rectangle = new Rectangle(x, y, width, height);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(DASHED_COLOR);
g2.setStroke(DASHED_STROKE);
g2.draw(rectangle);
g2.dispose();
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SelectorPanel mainPanel = new SelectorPanel();
JFrame frame = new JFrame("SelectorPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

How to fill ellipses smoothly while dragging mouse

I'm using MouseMotion Listeners to add shapes to a HashSet, and then filling them in using Graphics2D. However when I move my mouse too fast the points no longer make a coherent line.
I've tried googling, but haven't found a relevant answer.
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
//points.add(new Point(e.getX(), e.getY()));
shapes.add(new ShapeInfo(circle, new Point(e.getX(), e.getY()), color));
repaint();
}
});
for(ShapeInfo info : shapes) {
Point location = info.point.getLocation();
g2d.translate(location.x, location.y);
g2d.setColor(info.color);
g2d.fill(info.shape);
g2d.translate(-location.x, -location.y);
}
I hope to get a nice, smooth line made of circles, but end up with sacttered circles. https://imgur.com/a/KLOyPcn <- Here is what happends when I drag the mouse too fast while painting.
Your mouse works at a certain frequency (normal mouse works around 100Hz) so it will pick a certain number of points while you move it.
If you cover 1000 px in half second (which is not really fast) it will pick 50 points, they will be spaced every 20 pixel.
If your circle has a radius of less than that you will see a dotted line.
Even using very a fast mouse could not lead you to have a continuous line.
You could draw a line between points instead of drawing a circle if you want, or interpolate coordinate between last circle and current one and create other circles in between the 2.
Here try this.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
public class FillOvals extends JPanel {
private JFrame frame = new JFrame();
private List<Point> points = new ArrayList<>();
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new FillOvals().start());
}
public FillOvals() {
setPreferredSize(new Dimension(500, 500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null); // center on screen
frame.setVisible(true);
}
public void start() {
MyMouseListener ml = new MyMouseListener();
addMouseMotionListener(ml);
addMouseListener(ml);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (points.size() < 1) {
return;
}
Graphics2D g2d = (Graphics2D) g.create();
// keep the line smooth on the edges
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.BLUE);
Point p = points.get(0);
int lastx = p.x;
int lasty = p.y;
g2d.setStroke(new BasicStroke(10.f));
for (int i = 1; i < points.size(); i++) {
p = points.get(i);
g2d.drawLine(lastx, lasty, p.x, p.y);
lastx = p.x;
lasty = p.y;
}
g2d.dispose();
}
private class MyMouseListener extends MouseAdapter {
public void mouseDragged(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
public void mousePressed(MouseEvent e) {
points.add(e.getPoint());
repaint();
}
}
}
The JVM/mouse can't keep up with drawing circles that fast. The example I provided draws a line between two points on a continuous basis.

How to add Panel on mouse location?

I want to add a Panel (which is on other panel) on mouse position. When I add now, panel's location is next to previous panel.
jPanel1.setLayout(new FlowLayout());
JPanel newPanel = new JPanel();
newPanel.setBackground(Color.red);
jPanel1.add(newPanel);
newPanel.setLocation(300,300);
jPanel1.revalidate();
jPanel1.repaint();
Point point = newPanel.getLocation();
int x = point.x;
int y = point.y;
newPanel.setLocation(x+5,y+5);
If you need to place a Swing component in a random position, then you will need a layout manager that would allow this, and FlowLayout, along with most standard managers, won't. The most common one to use is the simplest -- a null layout, e.g., someJPanel.setLayout(null); -- that is complete absence of a layout manager, but this comes with its own host of troubles, and so I try to avoid use of these as much as possible.
If your goal however is to move a red square, then best to keep things as simple as possible, and instead of creating and moving a JPanel, create and move something much lighter in weight, a Rectangle.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class MovingRect extends JPanel {
private static final long serialVersionUID = 1L;
private static final Color RECT_COLOR = Color.RED;
private static final int RECT_W = 300;
private Rectangle rect = new Rectangle(0, 0, RECT_W, RECT_W);
public MovingRect() {
setPreferredSize(new Dimension(800, 650));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
((Graphics2D) g).fill(rect);
}
private class MyMouse extends MouseAdapter {
private Point p0;
private Point pRect;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
if (rect.contains(e.getPoint())) {
p0 = e.getPoint();
pRect = rect.getLocation();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
drag(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
drag(e);
p0 = null;
}
}
private void drag(MouseEvent e) {
// use simple geometry to move the rectangle
Point p1 = e.getPoint();
int x = p1.x - p0.x + pRect.x;
int y = p1.y - p0.y + pRect.y;
rect = new Rectangle(x, y, RECT_W, RECT_W);
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
MovingRect mainPanel = new MovingRect();
JFrame frame = new JFrame("Moving Rectangle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Code explanation
The rectangle to draw, initially placed at 0, 0:
private Rectangle rect = new Rectangle(0, 0, RECT_W, RECT_W);
In the constructor, set the drawing JPanel's preferred size, and create our mouse listener (actually a MouseAdapter) that will move the rectangle, and add the MouseAdapter as a MouseListener and MouseMotionListener to our drawing (main) JPanel:
public MovingRect() {
setPreferredSize(new Dimension(800, 650));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
Draw the rectangle within this JPanel's paintComponent method after doing clean-up painting by calling the super's method:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
((Graphics2D) g).fill(rect);
}
The mouse adapater that does the moving. It uses simple geometry of vector addition to calculate where to move
private class MyMouse extends MouseAdapter {
private Point p0;
private Point pRect;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
// if not button 1, then get out of here
return;
}
if (rect.contains(e.getPoint())) {
// get the first point of the mouse press and the rectangle's first position
p0 = e.getPoint();
pRect = rect.getLocation();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
drag(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
drag(e);
p0 = null; // set the first pressed point to null -- stop the listener
}
}
private void drag(MouseEvent e) {
// use simple geometry to move the rectangle
Point p1 = e.getPoint();
int x = p1.x - p0.x + pRect.x;
int y = p1.y - p0.y + pRect.y;
// create a new Rectangle with the position calculated above
rect = new Rectangle(x, y, RECT_W, RECT_W);
// ask Java to repaint the main JPanel
repaint();
}
}

Drawing multiple rectangles on a panel in Swing

I'm trying to draw multiple rectangles on a panel. I created an ArrayList<Shape> and initialized in my constructor. In my paintComponent method, I draw a rectangle and then add it to the ArrayList. But when I do that, the drawing outcome on my panel turns out weird. As I drag to draw my first rectangle, I get this:
Here's part of my code:
public class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(final MouseEvent theEvent) {
myStartPoint = theEvent.getPoint();
repaint();
}
#Override
public void mouseReleased(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
public class MyMouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
/**
* Paints some rectangles.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
// for better graphics display
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(51, 0, 111));
g2d.setStroke(new BasicStroke(3));
final double x = myStartPoint.getX();
final double y = myStartPoint.getY();
final double xEnd = myEndPoint.getX();
final double yEnd = myEndPoint.getY();
if (xEnd> x && yEnd > y) {
final Shape rectangle = new Rectangle2D.
Double(x, y, xEnd - x, yEnd - y);
g2d.draw(rectangle);
myDrawings.add(rectangle);
}
for (Shape s : myDrawings) {
g2d.draw(s);
}
}
Don't do any code logic within paintComponent -- that method is for drawing and drawing only, and that is the source of your bug. Add the rectangle to the ArrayList in the mouse listener, on mouse release.
When I have done a similar project, I usually have one Rectangle field that I use to draw with the mouse listener on mouse drag, and which is draw within paintComponent. Then on mouse release I place that rectangle into the ArrayList, and set the class field as null.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class RectangleDraw extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color TEMP_RECT_COLOR = Color.LIGHT_GRAY;
private static final Color SHAPE_COLOR = Color.RED;
private Rectangle tempRect = null;
private List<Shape> shapes = new ArrayList<>();
public RectangleDraw() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw the temporary rectangle if not null
if (tempRect != null) {
g2.setColor(TEMP_RECT_COLOR);
g2.draw(tempRect);
}
// draw all the rectangles in the list
g2.setColor(SHAPE_COLOR);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
// size the GUI to my specification
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
// My mouse listener and mouse motion listener
private class MyMouse extends MouseAdapter {
private Point p1; // start point
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
// create temporary rectangle
tempRect = createRectangle(e);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempRect = null; // null temp rectangle and
// add rectangle to List
shapes.add(createRectangle(e));
repaint();
}
// create a rectangle from start point and current point
private Rectangle createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
Rectangle rect = new Rectangle(x, y, w, h);
return rect;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Rectangle Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RectangleDraw());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

How to draw a continuous curve of repeated ovals on speedy mouse cursor dragging?

This code is for drawing on a JPanel. In the paintComponent(Graphics) I am trying to draw curves via repeated Graphics2D#fillOval(x, y, with, height).
The app is working OK, and when I drag the mouse cursor slowly; it draws a continuous curve as I need. But when I speed up dragging the mouse cursor, the result is separated dots and not a continuous curve.
So how to make it draw a continuous curve even if I speed up dragging?
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Painter extends JPanel {
int x, y;
ArrayList<Point> points;
public Painter() {
setBackground(Color.white);
points = new ArrayList<>();
MouseHandler listener = new MouseHandler();
this.addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
points.add(point);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Point point : points) {
g2d.fillOval(point.x, point.y, 15, 15);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
As mentioned in comment to your previous similar question:
Don't draw discrete ovals in your paintComponent method.
Instead connect the points hold in the List in the paintComponent by drawing lines between adjacent points.
If you need to make the line thicker, change the Stroke property of the Graphics2D object, using one that has a wider thickness.
Be careful with Strokes however since often you don't want the property change to propagate down the paint chain. This means that sometimes you will want to copy the Graphics object and set the Stroke on the new Graphics object and paint with that, then dispose of it.
The simplest way to create a Stroke is to use the BasicStroke class, e.g., new BasicStroke(6f) will get you a nice thick curve.
For example:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Painter2 extends JPanel {
private static final float STROKE_WIDTH = 15f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
int x, y;
ArrayList<Point> points;
public Painter2() {
setBackground(Color.white);
points = new ArrayList<>();
MouseHandler listener = new MouseHandler();
this.addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
points.add(point);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(STROKE);
for (int i = 1; i < points.size(); i++) {
int x1 = points.get(i - 1).x;
int y1 = points.get(i - 1).y;
int x2 = points.get(i).x;
int y2 = points.get(i).y;
g2d.drawLine(x1, y1, x2, y2);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter2());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
Or better still:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Painter2 extends JPanel {
private static final float STROKE_WIDTH = 15f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
private static final Color CURVES_COLOR = Color.BLUE;
private static final Color TEMP_CURVE_COLOR = Color.PINK;
private List<List<Point>> curvesList = new ArrayList<>();
private List<Point> tempCurve = null;
public Painter2() {
setBackground(Color.white);
MouseHandler listener = new MouseHandler();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mousePressed(MouseEvent e) {
tempCurve = new ArrayList<>();
tempCurve.add(e.getPoint());
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
tempCurve.add(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempCurve.add(e.getPoint());
curvesList.add(tempCurve);
tempCurve = null;
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(STROKE);
g2.setColor(CURVES_COLOR);
for (List<Point> curve : curvesList) {
drawCurve(g2, curve);
}
if (tempCurve != null) {
g2.setColor(TEMP_CURVE_COLOR);
drawCurve(g2, tempCurve);
}
g2.dispose();
}
private void drawCurve(Graphics2D g2, List<Point> ptList) {
for (int i = 1; i < ptList.size(); i++) {
int x1 = ptList.get(i - 1).x;
int y1 = ptList.get(i - 1).y;
int x2 = ptList.get(i).x;
int y2 = ptList.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter2());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}

Categories

Resources