Java Swing draw lines with mouse click and drag - java

I want to bring back a question that was asked before: java draw line as the mouse is moved
"I would like to add a feature to my application which allows the user to draw a straight line by clicking the mouse at the start location and releasing it at the end location. The line should move as the mouse moves until it is finally released; similar to the way that a line can be drawn using the Microsoft Paint application.
How can implement this so that the line is repainted as it moves without repainting other things that may already be drawn in that rectangular area?"
Question is: How can I draw multiple lines with the old lines still there?
This is the code that works for me, but the previous line gets erased as soon as you draw a new one:
public static void main(String args[]) throws Exception {
JFrame f = new JFrame("Draw a Red Line");
f.setSize(300, 300);
f.setLocation(300, 300);
f.setResizable(false);
JPanel p = new JPanel() {
Point pointStart = null;
Point pointEnd = null;
{
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
pointStart = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
pointStart = null;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
pointEnd = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
pointEnd = e.getPoint();
repaint();
}
});
}
public void paint(Graphics g) {
super.paint(g);
if (pointStart != null) {
g.setColor(Color.RED);
g.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y);
}
}
};
f.add(p);
f.setVisible(true);
}

This is the code that works for me, but the previous line gets erased as soon as you draw a new one:
There are two common approaches:
Keep an ArrayList of objects to paint. Then the paintComponent() method repaints all the objects each time the component needs to repaint itself
Paint onto a BufferImage and then just paint the BufferedImage.
Check out Custom Painting Approaches for a working example of both of these approaches.

Just set in mouseRelesed
pointStart = e.getPoint instead of pointStart = null.
there is no need for any lists or things like that
when you set it to null it starts from the beginning and deletes the last one

Related

Jittering when trying to move undercorated JFrame

I have made a custome JFrame called mainWindow that is undecorated. I have added a JLabel named dragBar at the top of it and gave it desired dimensions (as shown below). When I click on the label I make the window move according to my mouse by using two listeners; one MouseListener and one MouseMotionListener.
The problem is that whenever I click on the label the window does move according to my mouse's location but it spazzes all over my screen until I stop moving the mouse or let go of the click button.
Is my method wrong? What is causing this issue?
Here is my code:
//what i use to make the dragBar
private JLabel dragBar = new JLabel();
private Point initialClick; //the initial point where I click on the label
//my mainWindow JFrame
private JFrame mainWindow = new JFrame();
private Dimension mainWindowSize = new Dimension(680,410);
//the code I use to set up my mainWindow JFrame
mainWindow.setUndecorated(true);
mainWindow.setShape(new RoundRectangle2D.Double(0, 0, 670, 400, 5, 5));
mainWindow.setSize(mainWindowSize);
mainWindow.setMinimumSize(mainWindowSize);
mainWindow.setResizable(false);
mainWindow.setLocation((screen_size.width/2)- mainWindow.getWidth()/2, (screen_size.height/2)- mainWindow.getHeight()/2);
mainWindow.getContentPane().setBackground(new Color(46, 48, 50, 255));
//the code I use to set up my dragBar label
topContainer.add(dragBar,3); //a Jlayeredpane that contains the dragBar label and is added to the mainWindow
dragBar.setSize(topContainer.getSize());
dragBar.setLocation(0,0);
dragBar.addMouseListener(new MouseListener() {
#Override public void mouseClicked(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
initialClick = e.getPoint();
}
#Override public void mouseReleased(MouseEvent e) {}
#Override public void mouseEntered(MouseEvent e) {}
#Override public void mouseExited(MouseEvent e) {}
});
dragBar.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
int changeX = e.getX()-initialClick.x;
int changeY = e.getY()-initialClick.y;
mainWindow.setLocation(mainWindow.getX()+changeX, mainWindow.getY()+changeY);
}
#Override public void mouseMoved(MouseEvent e) {}
});
a Jlayeredpane that contains the dragBar label
Don't think I would use a JLayeredPane for this. Just add a component to the BorderLayout.PAGE_START of the frame.
The basic logic for dragging a component is something like:
public class DragListener extends MouseInputAdapter
{
Point location;
MouseEvent pressed;
public void mousePressed(MouseEvent me)
{
pressed = me;
}
public void mouseDragged(MouseEvent me)
{
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
However in your case you don't want to drag the label, but instead drag the window, you your logic needs to forward the events to the window.
Check out Moving Windows for a more complex implementation of the above code that also adds additional features that easily allow you to move a window.

Java - Freeze Mouse

Is there a way to lock the mouse in one position in Java for a certain amount of time?
I've tried this:
while(timer == true){
Robot bot = new Robot();
bot.mouseMove(x, y);
}
But when the user moves the mouse it jumps unpleasantly back and forth (from the position the user is dragging to the position where it's supposed to be locked).
Any ideas if there is a better way to do this? Or can I completely disable user input for the mouse? Thanks in advance!
This is as far as you can go (at least with the standard libraries). The mouse "jumps" are system dependent, specifically on the "sampling rate" of the listener. I'm not aware of a JVM parameter affecting it, but wouldn't be surprised if there is something in that spirit. The jumps are in opposite relation to the mouse acceleration (the mouse can move a "long" distance between the samples).
public class Stop extends JFrame {
static Robot robot = null;
static Rectangle bounds = new Rectangle(300, 300, 300, 300);
static int lastX = 450; static int lastY = 450;
Stop() {
try {
robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
addMouseMotionListener(new MouseStop());
getContentPane().add(new JLabel("<html>A sticky situation<br>Hold SHIFT to get out of it", JLabel.CENTER));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(bounds);
setVisible(true);
}
private static class MouseStop extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
if(e.isShiftDown()) {
lastX = e.getXOnScreen();
lastY = e.getYOnScreen();
}
else
robot.mouseMove(lastX, lastY);
}
}
public static void main(String args[]) {
new Stop();
}
}
Edit: I have just gotten an idea involving painting of the cursor to appear as if the mouse is not moving at all. I'll add code if I get something working.

How to draw a String to an applet screen at the point of mouse click?

EDIT: Okay, so I've managed to get it working now with the help of a friend. =)
I am currently creating a Java applet. The applet works by taking text input from the user and displaying it to the screen when they press return. This is the point up to which my program is working at the moment.
I was wondering whether there was a way in which I could make it so the text input/String is drawn when the mouse is clicked, at the point of mouse click.
Many thanks in advance to anyone who can help me out with this. :)
I was wondering whether there was a way in which I could make it so
the text input/String is drawn when the mouse is clicked, at the point
of mouse click.
Answer: Yes...
Would it be rude of me to leave the answer as that...?
This is a relatively simple process, depending on what you want to achieve...
This example just uses Graphics#drawString to render text to a custom component. You could, equally, just at a label to the component at the specified point, but that's another can of worms.
public class TestDrawText {
public static void main(String[] args) {
new TestDrawText();
}
public TestDrawText() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point textPoint;
public TestPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
textPoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (textPoint != null) {
FontMetrics fm = g.getFontMetrics();
g.drawString("You clicked at " + textPoint.x + "x" + textPoint.y, textPoint.x, textPoint.y + fm.getAscent());
}
}
}
}
Check out
How to Write a Mouse Listener
Performing Custom Painting
For more info.

mouse listener on frame

Hi
i am trying to add a mouse listener to my frame to get the position of the mouse clicked and check if it is inside the circle, the problem is that it is not triggering
public class CircleDraw extends Frame implements MouseListener {
static int circles = 0;
private double color;
double mousex = 0;
double mousey = 0;
int score;
public void mouseClicked(MouseEvent evt)
{
mousex = evt.getX();
mousey = evt.getY();
}
public void mouseEntered (MouseEvent me) {}
public void mousePressed (MouseEvent me) {}
public void mouseReleased (MouseEvent me) {}
public void mouseExited (MouseEvent me) {}
public void paint(Graphics g) {
try {
this.addMouseListener(this);
while (circles < 20) {
color = 10*Math.random();
Shape circle = new Ellipse2D.Double(900*Math.random(),900*Math.random(), 50.0f, 50.0f);
Graphics2D ga = (Graphics2D)g;
ga.draw(circle);
if(color >2)
ga.setPaint(Color.green);
else
ga.setPaint(Color.BLACK);
ga.fill(circle);
if(circle.contains(mousex, mousey) && color > 2)
score ++;
else
if(circle.contains(mousex, mousey) && color < 2)
score--;
Thread.sleep(1000);
System.out.println(circles);
System.out.println(mousex);
System.out.println(mousey);
circles ++;
ga.setPaint(Color.white);
ga.fill(circle);
}
System.exit(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
Frame frame = new CircleDraw();
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
frame.setSize(1000, 1000);
frame.setVisible(true);
}}
It is deadly to add your mouselistener in the paint() method, since this method is called very very often (with each repaint), and so many listeners are added (with each repaint).
You should add the listener to your content-panel and not to the JFrame itself. This will do it. You can do this in the constructor of your class:
public CircleDraw() {
this.getContentPane().addMouseListener(this);
}
This won't solve your problem completely I think, since you won't get your mouseclick while your paint-method is active. Your code-design (especially your while-loop) does not give any time to other events to fire. So the mouseclick-event will be handled after your 20 loops. You can check this by adding
public void mouseClicked(MouseEvent evt) {
mousex = evt.getX();
mousey = evt.getY();
System.out.println("X: "+mousex+"/ Y: "+mousey);
}
to your code. You have to run your GUI in a different thread (e.g. use SwingUtilities and a Runnable() therefor). I recommend you to get a good book on JAVA development. Or you can start with online-tutorials like this one.
IMHO you should not try to deal with awt, instead use SWING or SWT for GUI-design, since this is much more compfortable.
add the listener in the constructor, the paint is called repeatedly
Here are some of the problems I see with that source:
Adds the listener in paint()
Calls wait() within the paint() method.
Calls System.exit() within the paint() method (not strictly a problem, but very unusual).
Is poorly formatted and hard to understand
Calls deprecated methods.
Codes in AWT in the wrong millennium.

mouse moved -crosshair cursor

I developed a program to draw polygon triangles. The triangles were drawn using mouse drag. The coordinate of the triangles were stored in array list. Every times the mouse cursor, mouse over on the existing drawn triangles(within the area of triangle), the mouse cursor should turns to "CROSSHAIR_CURSOR", however this were not happened. Help :-(
...
public class DrawingBoardWithMatrix extends JFrame {
public static void main(String[] args) {
new DrawingBoardWithMatrix();
}
public DrawingBoardWithMatrix(){
this.add(new PaintSurface(), BorderLayout.CENTER);
...
}
private class PaintSurface extends JComponent {
java.util.List<Polygon> triangles = new LinkedList<Polygon>();
Point startDrag, endDrag, midPoint;
Polygon triangle;
public PaintSurface() {
...
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startDrag = new Point(e.getX(), e.getY());
endDrag = startDrag;
repaint();
}//end mousePressed
public void mouseReleased(MouseEvent e) {
if (startDrag.x > endDrag.x)
midPoint = new Point((endDrag.x +(Math.abs(startDrag.x - endDrag.x)/2)),e.getY());
else
midPoint = new Point((endDrag.x -(Math.abs(startDrag.x - endDrag.x)/2)),e.getY());
int[] xs = { startDrag.x, endDrag.x, midPoint.x };
int[] ys = { startDrag.y, startDrag.y, midPoint.y };
triangles.add( new Polygon(xs, ys, 3));
startDrag = null;
endDrag = null;
repaint();
}//end mouseReleased
});//end addMouseListener
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
endDrag = new Point(e.getX(), e.getY());
repaint();
}//end mouseDragged
});//end this.addMouseMotionListener
}//end paintSurface
//THIS CODE DOESNT WORK - AND I AM STUCK :-(
public void mouseMoved(MouseEvent e) {
startDrag = new Point(e.getX(), e.getY());
if (triangles.contains(startDrag))
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
else
setCursor(Cursor.getDefaultCursor());
}// end mouseMoved
private void paintBackground(Graphics2D g2){
...
}
public void paint(Graphics g) {
...
}
}//end private class PaintSurface
}//end public class DrawingBoardMatrix
Do you see the mouseMoved method being invoked at all? The way this is written, the mouseMoved method is a member of PaintSurface, but PaintSurface is not a MouseMotionListener. Implementing 'MouseMotionListener' will force it to implement mouseMoved and mouseDragged. After you have done that, you can add your PaintSurface to itself as a MouseMotionListener. Alternatively, you could move the mouseMoved method inside the MouseMotionAdapter anonymous class that you have already defined:
//paintSurface constructor
....
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
endDrag = new Point(e.getX(), e.getY());
repaint();
}//end mouseDragged
//TRY THIS CODE :-)
public void mouseMoved(MouseEvent e) {
startDrag = new Point(e.getX(), e.getY());
if (triangles.contains(startDrag))
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
else
setCursor(Cursor.getDefaultCursor());
}// end mouseMoved
});//end this.addMouseMotionListener
}//end paintSurface
EDIT (in response to your comment):
It would appear that your conditional if (triangles.contains(startDrag)) depends on the List<Polygon> finding a Point that considers itself equal to the passed in Point. As far as I can tell from looking at the code in Polygon(it doesnt override the equals method, so it takes the implementation from Object), you will not be able to perform this test 'successfully.' You will need to iterate over your Polygons in your triangles collection and perform a contains operation on each in turn.
EDIT 2:
You are probably over-thinking this a bit. In order to implement the suggestion 'to iterate over your Polygons in your triangles collection...' you could do something like the following:
public void mouseMoved(MouseEvent e) {
startDrag = new Point(e.getX(), e.getY());
Cursor cursor = Cursor.getDefaultCursor();
//you have a List<Polygon>, so you can use this enhanced for loop
for (Polygon p : triangles) {
if (p.contains(startDrag)) {//Polygon has a 'contains(Point)' method
cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
break; //you've found a hit, break from the loop
}
}
setCursor(cursor);
}// end mouseMoved
You could also consider not setting the cursor with every mouse movement. For that, you can put a test in to check the type of the current cursor and the type of the cursor that your mouse movement is intending to set, and only set it if there is a change:
if (cursor.getType() != getCursor().getType()) {
setCursor(cursor);
}

Categories

Resources