Drag to draw more shapes - java

So right now I have a program that draws a circle when I right click, and a square when I left click, and when I shift click it clears the screen.
• What I want to do is to be able to drag and make the mouse leave a trail of figures as I drag. How do I do that? Here is my program.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;`
public class SimpleStamper extends JPanel implements MouseListener {
public static void main(String[] args) {
JFrame window = new JFrame("Simple Stamper");
SimpleStamper content = new SimpleStamper();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
// ------------------------------------------------------------------
public SimpleStamper() {
setBackground(Color.BLACK);
addMouseListener(this);
}
public void mousePressed(MouseEvent evt) {
if ( evt.isShiftDown() ) {
repaint();
return;
}
int x = evt.getX();
int y = evt.getY();
Graphics g = getGraphics();
if ( evt.isMetaDown() ) {
g.setColor(Color.RED);
g.fillOval( x - 30, y - 30, 60, 60 );
g.setColor(Color.RED);
g.drawOval( x - 30, y - 30, 60, 60 );
}
else {
g.setColor(Color.PINK);
g.fillRect( x - 15, y - 15, 30, 30 );
g.setColor(Color.PINK);
g.drawRect( x - 15, y - 15, 30, 30 );
}
g.dispose();
}
public void mouseEntered(MouseEvent evt) { }
public void mouseExited(MouseEvent evt) { }
public void mouseClicked(MouseEvent evt) { }
public void mouseReleased(MouseEvent evt) { }
}

Basically you need to add a MouseMotionListener, same as a MouseListener.
public class SimpleStamper
extends JPanel implements MouseListener, MouseMotionListener {
List<Shape> shapes = new ArrayList<>();
public void mouseDragged(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
//... create another shape and add it to the list of shapes
// (see Adrian's comment)
}
public void mouseMoved(MouseEvent evt) {
}
//...
}
To continue the same shape, you must store the "current" shape in a class variable, to be done in mousePressed.
Note that this produces nothing but a wide line tracking the mouse movement. If you want to have distinct shapes drawn, you have to keep track of the last x and y, and create another shape only if the distance is greater than some parameter DMIN.
Below is a full rewrite.
public class Drag
extends JPanel implements MouseListener, MouseMotionListener {
public static void main(String[] args) {
JFrame window = new JFrame("Simple Stamper");
Drag content = new Drag();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
public Drag() {
setBackground(Color.BLACK);
addMouseListener(this);
addMouseMotionListener( this );
}
// ------------------------------------------------------------------
private java.util.List<Shape> shapes = new ArrayList<>();
private enum Form {
CIRCLE, SQUARE;
}
private Form lastForm;
private int lastX;
private int lastY;
private static final int DMIN = 20;
private void addShape( Form form, int x, int y, int a ){
switch( form ){
case CIRCLE:
shapes.add( new Ellipse2D.Double( x-a/2.0, y-a/2.0, a, a ) );
break;
case SQUARE:
shapes.add( new Rectangle2D.Double( x-a/2.0, y-a/2.0, a, a ) );
break;
}
repaint();
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g;
for( Shape s: shapes ){
if( s instanceof Rectangle2D ){
g2.setColor(Color.PINK);
} else {
g2.setColor(Color.RED);
}
g2.fill( s );
g2.draw( s );
}
}
public void mouseDragged(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
int dx = lastX - x;
int dy = lastY - y;
if( dx*dx + dy*dy > DMIN*DMIN ){
lastX = x;
lastY = y;
addShape( lastForm, lastX, lastY, 60 );
}
}
public void mouseMoved(MouseEvent evt) {
}
public void mousePressed(MouseEvent evt) {
if ( evt.isShiftDown() ) {
shapes.clear();
repaint();
return;
}
lastX = evt.getX();
lastY = evt.getY();
if ( evt.isMetaDown() ) {
lastForm = Form.CIRCLE;
} else {
lastForm = Form.SQUARE;
}
addShape( lastForm, lastX, lastY, 60 );
}
public void mouseEntered(MouseEvent evt) { }
public void mouseExited(MouseEvent evt) { }
public void mouseClicked(MouseEvent evt) { }
public void mouseReleased(MouseEvent evt) { }
}

Related

Java Non-Static Variable Referenced from Static Context Error

I'd like to state that this question is very possibly a duplicate, but I'm not sure exactly what the issue is: I'm unable to do a proper search because of this.
I'm currently working on a painting program in Java. I'm trying to store the instructions for drawing the shapes in an ArrayList of Shape objects. I'm also using a MouseListener to get the coordinates.
The goal is that when the mouse is pressed, it keeps a record of that point. When it is released, it keeps record of that second point, then sends the two coordinates to the constructor, in the line history.add(new Shape(x, y, x2, y2)).
The relevant code is the following:
// Create an ArrayList for the History
static ArrayList history = new ArrayList(0);
.
.
.
// Co-ordinates for rectangle painting
static int x = 0;
static int y = 0;
static int x2 = 0;
static int y2 = 0;
.
.
.
/**
* A class for handling mouse input
*
* All methods within the MouseHandler class MUST be there
* If not, the code will not compile.
*/
private static class MouseHandler implements MouseListener
{
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
}
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getY();
//repaint() is a special method that must be called to "repaint"
//your shapes on the screen.
canvas.repaint();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
// Create a new shape on the button unclick
history.add(new Shape(x, y, x2, y2));
}
}
This code throws an exception at the line history.add(new Shape(x, y, x2, y2)); : "Non-static method this cannot be referenced from a static context." The error seems to specifically reference (new Shape(x, y, x2, y2)). I don't understand why this method would be non-static.
Any help is greatly appreciated in advance,
Placowdepuss
Edit: Here is my full code:
//Import packages needed
// For the GUI
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// For the ArrayList
import java.util.*;
/**
* A simple drawing application.
*
* #author (Massimo A. Lipari)
* #version (1.0.0)
*/
public class PaintProgram
{
// Create the frame and the panels for the GUI
static JFrame frame = new JFrame("PaintIt");
static JPanel panel = new JPanel();
static JPanel buttonPanel = new JPanel();
static MyPanel canvas = new MyPanel();
static JLabel sampleText = new JLabel("Label");
// Create an array for the buttons
static JButton[] buttonArray = new JButton[12];
// Create an ArrayList for the History
static ArrayList<Shape> history = new ArrayList<Shape>();
// Co-ordinates for rectangle painting
static int x, y, x2, y2;
// Create a variable for keeping track of the active tool
static String activeTool;
// Variables for holding the current colour and fill settings
static boolean currentFill;
static Color currentColour;
public static void main(String[] args)
{
// Set the frame size
frame.setSize(1920,1040);
// Create the mouse listeners
canvas.addMouseListener(new MouseHandler());
// Set the size for the canvas portion of the screen
canvas.setSize(1920, 880);
// Add panels to frame
// Set layout for panel
panel.setLayout(new BorderLayout());
createButtonPanel();
panel.add(buttonPanel, BorderLayout.NORTH);
panel.add(canvas, BorderLayout.CENTER);
frame.getContentPane().add(panel);
// Set frame to visible and allows it to exit on closing of the frame
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void createButtonPanel()
{
// Set the buttonPanel size, and creates a grid layout for it
buttonPanel.setSize(1920, 160);
buttonPanel.setLayout(new GridLayout(1, 12));
// Initialize the buttons
for (int i = 0; i < buttonArray.length; i++) {
buttonArray[i] = new JButton("Button " + (i + 1));
// Create and add a button handler
buttonArray[i].addActionListener(new ButtonHandler());
buttonArray[i].setIcon(new ImageIcon("icon" + i + ".png"));
buttonArray[i].setBackground(Color.WHITE);
buttonPanel.add(buttonArray[i]);
}
}
/**
* A class for handling button input (the tools)
*/
private static class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == buttonArray[0]) {
buttonArray[0].setBackground(JColorChooser.showDialog(null, "Choose a Color", sampleText.getForeground()));
} else if (e.getSource() == buttonArray[1]) {
currentFill = true;
buttonArray[1].setBackground(Color.LIGHT_GRAY);
buttonArray[2].setBackground(null);
} else if (e.getSource() == buttonArray[2]) {
currentFill = false;
buttonArray[1].setBackground(null);
buttonArray[2].setBackground(Color.LIGHT_GRAY);
} else if (e.getSource() == buttonArray[3]) {
activeTool = "paint";
} else if (e.getSource() == buttonArray[4]) {
activeTool = "rectangle";
} else if (e.getSource() == buttonArray[5]) {
activeTool = "triangle";
} else if (e.getSource() == buttonArray[6]) {
activeTool = "circle";
} else if (e.getSource() == buttonArray[7]) {
activeTool = "line";
} else if (e.getSource() == buttonArray[8]) {
activeTool = "text";
} else if (e.getSource() == buttonArray[9]) {
} else if (e.getSource() == buttonArray[10]) {
} else if (e.getSource() == buttonArray[11]) {
}
}
}
/**
* A class for handling mouse input
*
* All methods within the MouseHandler class MUST be there
* If not, the code will not compile.
*/
private static class MouseHandler implements MouseListener
{
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
}
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getY();
//repaint() is a special method that must be called to "repaint"
//your shapes on the screen.
canvas.repaint();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
// Create a new shape on the button unclick
history.add(new Shape(x, y, x2, y2));
}
}
/**
* A class for painting the shapes
*/
private static class MyPanel extends JPanel
{
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
setBackground(Color.white);
}
public Dimension getPreferredSize() {
return new Dimension(600,600);
}
// ALL drawing of shapes must be done in the paintComponent method
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Drawing a basic rectangle from top left corner to bottom right on canvas
if (x2 >= x && y2 >= y)
g.drawRect(x, y, x2 - x, y2 - y);
else if (x2 >= x && y2 <= y)
g.drawRect(x, y2, x2 - x, y - y2);
else if (x2 <= x && y2 >= y)
g.drawRect(x2, y, x - x2, y2 - y);
else if (x2 <= x && y2 <= y)
g.drawRect(x2, y2, x - x2, y - y2);
}
}
/**
* A class that creates a colour picker
*
* This code is the property of Oracle Systems Inc. It is copyrighted.
*/
static class ColorChooser_01 extends JFrame
{
public static void main(String[] args) {
new ColorChooser_01();
}
public ColorChooser_01() {
this.setSize(300, 100);
JPanel panel1 = new JPanel();
sampleText.setBackground(null);
panel1.add(sampleText);
this.add(panel1);
this.setVisible(true);
}
public class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
Color c = JColorChooser.showDialog(null, "Choose a Color", sampleText.getForeground());
if (c != null){
sampleText.setForeground(c);
buttonArray[0].setBackground(c);
}
else{
sampleText.setForeground(Color.WHITE);
}
}
}
}
/**
* A class for creating objects of type Shape
*/
public class Shape
{
// Variable for storing the type of shape
String type;
// Initialize variables for storing points for shape creation
int xcoord;
int ycoord;
int xcoord2;
int ycoord2;
// Boolean variable to control whether the shape is filled or not -- defaults to false
boolean fill = false;
// Variable to hold the coulour
Color colour;
public Shape(int newX, int newY, int newX2, int newY2)
{
type = activeTool;
xcoord = newX;
ycoord = newY;
xcoord2 = newX2;
ycoord2 = newY2;
fill = currentFill;
colour = currentColour;
}
public String getType()
{
return type;
}
public int getX()
{
return xcoord;
}
public int getY()
{
return ycoord;
}
public int getX2()
{
return xcoord2;
}
public int getY2()
{
return ycoord2;
}
public boolean getFill()
{
return fill;
}
public Color getColour()
{
return colour;
}
}
}
You need to move the shape class to another file because you cannot have two public classes in the same file

Java - boolean set to false with nothing telling it to do so

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....

Java - MouseListener Action Event in paintComponent

Here i have a code which draws a rectangle on the mouseClicked position using the paintComponent.I can get the output message but anything related to graphics and .draw() wont work.
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public final class testclass extends JFrame {
static JPanel p;
Timer t;
int x = 1;
int y = 1;
int xspeed = 1;
int yspeed = 1;
public testclass() {
initComponents();
this.setBounds(100, 300, 500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.start();
this.add(p);
}
public void initComponents() {
final ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
p.repaint();
}
};
t = new Timer(50, action);
p = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D gD = (Graphics2D) g;
moveBALL();
gD.drawOval(x, y, 25, 25);
p.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("a");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("b");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("c");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("d");
}
#Override
public void mouseClicked(MouseEvent e) {
gD.drawRect(e.getX(), e.getY(), 10, 60);
gD.setColor(Color.green);
System.out.println("clicked");
}
});
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > p.getWidth() - 20) {
x = p.getWidth() - 20;
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > p.getHeight() - 20) {
y = p.getHeight() - 20;
yspeed = -yspeed;
}
}
};
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new testclass().setVisible(true);
p.setBackground(Color.WHITE);
}
});
}
}
What is the proper way to implement a mouseListener() in this program?
Thanks.
Some suggestions on current code:
Watch class naming scheme i.e testclass should be TestClass or even better Test (but thats nit picking). All class names begin with capital letter and each new word thereafter is capitalized.
Dont extend JFrame unnecessarily.
Dont call setBounds on JFrame rather use appropriate LayoutManager and/or override getPreferredSize() of JPanel and return dimensions which fits its content.
Always call pack() on JFrame before setting it visible (taking above into consideration).
Use MouseAdapter vs MouseListener
Dont call moveBall() in paintComponent rather call it in your Timer which repaints the screen, not only slightly better design but we also should not do possibly long running tasks in paint methods.
As for your problem I think your logic is a bit skewed.
One approach would see the Rectangle (or Rectangle2D) get replaced by its own custom class (which will allow us to store attributes like color etc). Your ball would also have its own class which has the method moveBall() and its attributes like x and y position etc. On every repaint() your JPanel would call the method to move the ball, the JPanel itself could wrap the moveBall() in its own public method which we could than call from the timer which repaints the screen.
Here is an example of your code with above fixes implemented (please analyze it and if you have any questions let me know):
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.*;
public class Test {
private MyPanel p;
private Timer t;
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents();
frame.add(p);
frame.pack();
frame.setVisible(true);
t.start();
}
private void initComponents() {
final ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
p.moveEntities();//moves ball etc
p.repaint();
}
};
t = new Timer(50, action);
p = new MyPanel();
p.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN);
System.out.println("clicked");
}
});
p.setBackground(Color.WHITE);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class MyPanel extends JPanel {
int width = 300, height = 300;
ArrayList<MyRectangle> entities = new ArrayList<>();
MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height);
void addEntity(int x, int y, int w, int h, Color c) {
entities.add(new MyRectangle(x, y, w, h, c));
}
void moveEntities() {
ball.moveBALL();
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(ball.getColor());
g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height);
for (MyRectangle entity : entities) {
g2d.setColor(entity.getColor());
g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
class MyRectangle extends Rectangle2D.Double {
Color color;
public MyRectangle(double x, double y, double w, double h, Color c) {
super(x, y, w, h);
color = c;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
class MyBall extends Ellipse2D.Double {
int xspeed = 1;
int yspeed = 1;
Color color;
private final int maxWidth;
private final int maxHeight;
public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) {
super(x, y, w, h);
color = c;
this.width = w;//set width and height of Rectangle2D
this.height = h;
//set max width and height ball can move
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > maxWidth - ((int) getWidth() / 2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed
x = maxWidth - ((int) getWidth() / 2);
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > maxHeight - ((int) getHeight() / 2)) {
y = maxHeight - ((int) getHeight() / 2);
yspeed = -yspeed;
}
}
}
First of all the paint component is called every time swing needs to redraw the component.
And you are adding a new instance of mouse listener to the panel every time the paint is called.
Just move the line
p.addMouseListener(new MouseListener() {...}
out of the paint component, preferably after the initialization of the panel.
default template is
JPanel p = new JPanel(){
#Override
public void paintComponent(Graphics g) {
}
};
p.addMouseListener(new MouseListener() or new MouseAdapter()
//Your overridden methods
});
Hope this helps.

Java Challenge on Permitting the User to Draw A Line

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();
}
}
}

Drawing a line using a Mouse Motion Listener

I'm new at using actionListener and mouselistner. I want to track the Mouse movements and connect the dots as I go. So it will be one continuous line. I am using the MouseMotionListener every time I move the mouse across the screen and get a new set of points. I am not using mousePressed or mouseReleased.
Everytime I move the mouse, I can get every point of where my mouse's position is on my JPanel to show up on my results window, but in order to draw the line between two points, I'm not sure how to decipher between each different set of points so I can have a beginning and ending set of points to use for drawing a line? I checked through here and the API and I'm stuck.
I was asked to put more code and so I gave you my code.
I am basically creating a Jpane that tracks mouse movement when the Track Mouse button or Draw Track Radio button is pressed
These results will print out as (x,y) on the output screen
FYI: You can also draw circles once the Draw circles RadioButton is checked
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class MouseTest {
private JFrame frame;
private boolean tracking;
private boolean drawing;
private boolean connectdots;
private int xstart;
private int ystart;
private int xend;
private int y;
private int x;
private int yend;
private int borderWidth = 5;
String drawCircles = "Draw Circles";
String drawTrack = "Draw Track";
public static void main (String [] arg) {
MouseTest first = new MouseTest();
}//main
$
public MouseTest() {
tracking = false;
frame = new JFrame();
frame.setBounds(250,98,600,480);
frame.setTitle("Window number three");
Container cp = frame.getContentPane();
JButton track = new JButton("Track Mouse");
track.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
trackMouse();
}
});
JPanel top = new JPanel();
top.add(track);
cp.add(top,BorderLayout.NORTH);
MyPanel pane = new MyPanel();
cp.add(pane,BorderLayout.CENTER);
pane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
xstart = e.getX();
ystart = e.getY();
}
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
if (xend < xstart) { int tmp = xstart; xstart = xend; xend = tmp; }
if (yend < ystart) { int tmp = ystart; ystart = yend; yend = tmp; }
frame.repaint();
}
});
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
if (tracking) {
x = e.getX();
y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
});
JRadioButton circleButton = new JRadioButton(drawCircles);
circleButton.setMnemonic(KeyEvent.VK_B);
circleButton.setActionCommand(drawCircles);
circleButton.setSelected(false);
JRadioButton trackButton = new JRadioButton(drawTrack);
trackButton.setMnemonic(KeyEvent.VK_C);
ButtonGroup group = new ButtonGroup();
group.add(circleButton);
group.add(trackButton);
JPanel radioPanel = new JPanel(new GridLayout(2,0));
radioPanel.add(circleButton);
radioPanel.add(trackButton);
cp.add(radioPanel,BorderLayout.EAST);
drawing = false;
connectdots = false;
circleButton.addActionListener(new ActionListener() { //Set drawing to true when the button is clicked
public void actionPerformed(ActionEvent ae) {
tracking = !tracking;
drawCircles();
}
});
trackButton.addActionListener(new ActionListener() { //Set drawing to true when the button is clicked
public void actionPerformed(ActionEvent ae) {
drawing = false;
tracking = true;
connectDots();
}
});
frame.setVisible(true);
}//constructor
$
public void trackMouse() {
tracking = !tracking;
}//trackMouse
public void msg(String s) { //new method to simplify the system.out.print method
System.out.println(s);
}
public void drawCircles() {
drawing = true;
}//Allow Drawing of Circles
public void connectDots() {
connectdots = !connectdots;
}//Trying to use for connecting the mouse motion listener points when tracking
$
public class MyPanel extends JPanel {
ArrayList<Circle> circles = new ArrayList<Circle>();
public void paintComponent(Graphics g) {
int width = this.getWidth();
int height = this.getHeight();
msg("H = " + height + ", w = " + width);
g.setColor(Color.BLACK);
Circle c = new Circle(xstart, ystart);
circles.add(c);
if (drawing){
for(int k=0; k<circles.size(); k++){
circles.get(k).draw(g);
}
} // draw the circle
if (connectdots && tracking) { //trying to use for drawing the lines
g.drawLine(x,y,x,y);
}
for (int delta = 0; delta < borderWidth; delta++) {
g.drawRect(delta,delta,width-(2*delta),height-(2*delta));
}
if (xstart != xend || ystart != yend) {
int red = (int)(256*Math.random());
int green = (int)(256*Math.random());
int blue = (int)(256*Math.random());
g.setColor(new Color(red, green, blue));
msg("Colors are: " + red + " - " + green + " - " + blue );
msg("Drawing from: (" + xstart + ", " + ystart + ") to (" + xend + ", " + yend + ")");
msg("Width is " + (xend-xstart) + " - Height is " + (yend-ystart));
g.fillRect(xstart,ystart,xend-xstart,yend-ystart);
}
}
}
}
$
public class Circle {
// instance variables:
int radius; //random radius
int x, y; // coords of the center point
private Graphics g;
public Circle(int xIn, int yIn) {
radius = (int)(127*Math.random());
x = xIn;
y = yIn;
}
public void draw(Graphics g){
g.drawOval(x-radius, y-radius, radius, radius);
g.fillOval(x-radius, y-radius, radius, radius);
int red = (int)(256*Math.random());
int green = (int)(256*Math.random());
int blue = (int)(256*Math.random());
g.setColor(new Color(red, green, blue));
}
public int getX(int xstart) {
// TODO Auto-generated method stub
return x;
}
public int getY(int ystart) {
// TODO Auto-generated method stub
return y;
}
}
You just have to save x and y in some attribute for your class (like lastX and lastY.) When you get the event the second time, your first point coordinates are saved in your attributes and you can then draw your line. This new point has to be saved too to serve as your new lastX and lastY.
Even better: since you'll probably need to redraw your lines each frame (if you want a set of lines and not just a single line to be drawn each frame), use Point to save your coordinates and some kind of list like ArrayList. Save the full set of tracked points in an ArrayList<Point> and then draw each frame iterating over this list.
An example of an sscce:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo3 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private boolean tracking = false;
private int x, y;
public Foo3() {
add(new JToggleButton(new AbstractAction("TrackMouse") {
public void actionPerformed(ActionEvent ae) {
trackMouse(ae);
}
}));
MyMouseAdapter myMA = new MyMouseAdapter();
addMouseMotionListener(myMA);
}
private void trackMouse(ActionEvent ae) {
JToggleButton toggleBtn = (JToggleButton) ae.getSource();
tracking = toggleBtn.isSelected();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void msg(String message) {
System.out.println(message);
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
if (tracking) {
x = e.getX();
y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
}
private static void createAndShowGui() {
Foo3 mainPanel = new Foo3();
JFrame frame = new JFrame("MouseMotion Eg");
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();
}
});
}
}
Edit: Example 2
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class MouseTestHovercraft extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int MAX_CLR = 5;
private static final Color CURRENT_LIST_COLOR = new Color(190, 190, 255);
private List<Color> colors = new ArrayList<Color>();
private boolean tracking = false;
private List<Point> currentList = null;
private BufferedImage bufferedImage = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
private Random random = new Random();
public MouseTestHovercraft() {
for (int redIndex = 0; redIndex < MAX_CLR; redIndex++) {
int r = (redIndex * 256) / (MAX_CLR - 1);
r = (r == 256) ? 255 : r;
for (int greenIndex = 0; greenIndex < MAX_CLR; greenIndex++) {
int g = (greenIndex * 256) / (MAX_CLR - 1);
g = (g == 256) ? 255 : g;
for (int blueIndex = 0; blueIndex < MAX_CLR; blueIndex++) {
int b = (blueIndex * 256) / (MAX_CLR - 1);
b = (b == 256) ? 255 : b;
Color c = new Color(r, g, b);
colors.add(c);
}
}
}
add(new JToggleButton(new AbstractAction("TrackMouse") {
public void actionPerformed(ActionEvent ae) {
trackMouse(ae);
}
}));
add(new JButton(new AbstractAction("Clear Image") {
public void actionPerformed(ActionEvent e) {
bufferedImage = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
repaint();
}
}));
MyMouseAdapter myMA = new MyMouseAdapter();
addMouseListener(myMA);
addMouseMotionListener(myMA);
}
private void trackMouse(ActionEvent ae) {
JToggleButton toggleBtn = (JToggleButton) ae.getSource();
tracking = toggleBtn.isSelected();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void msg(String message) {
System.out.println(message);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bufferedImage, 0, 0, null);
if (currentList != null) {
drawList(g, currentList, CURRENT_LIST_COLOR, 1f);
}
}
private void drawList(Graphics g, List<Point> ptList, Color color,
float strokeWidth) {
if (ptList.size() > 1) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(color);
g2.setStroke(new BasicStroke(strokeWidth));
for (int j = 0; j < ptList.size() - 1; j++) {
int x1 = ptList.get(j).x;
int y1 = ptList.get(j).y;
int x2 = ptList.get(j + 1).x;
int y2 = ptList.get(j + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.dispose();
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (tracking && e.getButton() == MouseEvent.BUTTON1) {
currentList = new ArrayList<Point>();
currentList.add(e.getPoint());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (tracking && e.getButton() == MouseEvent.BUTTON1) {
currentList.add(e.getPoint());
Graphics2D g2 = bufferedImage.createGraphics();
Color color = colors.get(random.nextInt(colors.size()));
drawList(g2, currentList, color, 3f);
currentList = null;
repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (tracking && currentList != null) {
currentList.add(e.getPoint());
repaint();
}
}
}
private static void createAndShowGui() {
MouseTestHovercraft mainPanel = new MouseTestHovercraft();
JFrame frame = new JFrame("MouseMotion Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories