Drawing a straight line drag and drop in class Graphics2D - java

How can I draw a straight line on a drag and drop, that there was only one line and moved around?
My code:
panelPaint.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
point1 = e.getPoint();
}
});
panelPaint.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
point2 = e.getPoint();
g2.draw(new Line2D.Double(point1, point2));
panelPaint.repaint();
}
});
Current effect:

Looks like you are drawing to a BufferedImage or something. You should not be doing painting using a Graphics object in the mouse event.
Instead you should be doing custom painting on a panel and override the paintCompnent(...) method. Your paintComponent() method should look like:
#Override
protected void paintComponent(Grapahics g)
{
super.paintComponent(g);
// custom painting here
g.drawLine(...);
}
The first statement will clear the background. The next statement will draw the line between your starting/ending points.
Check out Custom Painting Approaches for more information and examples. The example will dynamically draw a Rectangle as you drag the mouse, but the concept is the same for a single line.

Related

Draw and redraw on a canvas in swing

I know there's no direct replacement for java.awt.Canvas in swing, and I know I'm supposed to use a JPanel and override paintComponent, for example like so:
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.drawOval(0, 0, 100, 100);
}
And this would draw a black circle on the JPanel when it is created. The problem I have is that I want a dynamic canvas: I want to be able to draw things in response to user input, and redraw continuously, not just once when the application starts. An example would be having a moving object on a canvas, that would need to be redrawn at a rate of say 60 frames per second. How could I achieve this without using AWT components?
EDIT: what I mean is, in an actual canvas, I'd be able to arbitrarily call, say, drawOval anywhere in my code, and that would draw an oval on the canvas; is this doable with JPanel?
Store the information to be drawn (e.g. a Shape or a group of them) and call repaint() from a Swing Timer. Each time the paintComponent(..) method is called, first call the super(..) method to erase the previous drawings, then iterate the list of shapes, move them if necessary, and draw each one.
Here's one way to do it:
public class Renderer extends JComponent implements ActionListener {
private int x;
public Renderer() {
Timer timer = new Timer(1000/60, this);
timer.start();
x = 0;
}
#Override
public void paintComponent(Graphics g) {
super.paint(g);
// drawing code
g.setColor(Color.black);
g.drawOval(x, 0, 100, 100);
}
private void update() {
this.x++;
}
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
}
Now just add this to your component (JPanel or whatever):
comp.add(new Renderer());

Java graphics being drawn on top of existing graphic

Main class:
public Main() {
Frame f = new Frame();
final Panel p = f.p;
final Player player = new Player();
Timer t = new Timer(UPDATE_PERIOD, new ActionListener() {
public void actionPerformed(ActionEvent e) {
Graphics g = p.getGraphics();
p.render(g);
player.tick();
player.render(g);
g.dispose();
}
});
t.start();
}
Player render method:
public void render(Graphics g) {
g.drawImage(Images.get("player"), x, y, null);
}
The problem is, that all previous drawn images are still there. Example (when I change the drawn image's x or y):
To draw in Swing, you should not be getting the Graphics object directly from the JPanel. Instead, override the paintComponent method and use the parameter Graphics object to perform your custom drawing, with a call to the parent method to erase previous painting
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//custom painting goes here
}
If you wish to trigger a repaint, use the method by that name on the JPanel:
p.repaint();
Rather than doing custom rendering your your timer, you should really be doing all your painting in your paintComponent method. Something like:
public void actionPerformed(ActionEvent e) {
player.tick();
p.repaint();
}
And then re-render the player and the background in paintComponent()
Painting like you currently are runs into issues when you resize the panel, etc
Try calling 'p.repaint()' in your ActionListener once you have changed the position of the Graphic.

Drawing a shape with an undefined size

I have been looking at the Java2D tutorials and was wondering how to draw a shape using the mouse to define its size(i.e the size of the shape is not fixed). I haven't come across a tutorial specifically for this and was wondering how I could implement this for a rectangle for example.
Basically, the size is FIXED at every moment. When you add a MouseMotionListener, before the next event is captured, you can paint the shape on the screen with the size depending on current MouseEvent.getPoint() which tells you the coordinates of your mouse location.
Override the paintComponent(Graphics g) method of the component. and call repaint() method after each update of the mouse location and the size of the shape:
class YourPanel extends JPanel extends MouseMotionListener, MouseListener {
private Rectangle rect = new Rectangle();
public YourPanel () {
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public void paintComponent (Graphics g) {
super.paintComponent(g);
g.draw(rect);
}
#Override
public void mouseDragged (MouseEvent me) {
rect.setSize(me.getX() - rect.x, me.getY() - rect.y);
repaint();
}
#Override
public void mousePressed (MouseEvent me) {
rect.setLocation(me.getX(), me.getY());
repaint();
}
// Other methods...
}
Shapes is a word and java class that represents differnet geometric figures like rectangles, ellipses, poly lines, etc.
So first the user would have to decide which shape, e.g a poly line.
You then would catch mouse left click events, and for each click read the mouse coordinates and add that coordinate pair (e.g java.awt.geom.Point2D()) to an ArrayList<Point2D>.
The size of such an list is (practically) unbounded. On each click you will create a current shaped object that will be drawn. Once the user clicks right mouse, the shape is ready und you store it in list of shapes.
You should have your class implement a mouse listener, then save the variables of the mouse listener with getX and getY to draw the shape.

Drawing a rectangle over an existing Graphics page

I have a Java application which draws a drawing. I want to give the user the possibility to mark an area with the mouse (in order to, for example, zoom into it).
For that I use the MouseMotionListener class, and when the mouse is (clicked and then) moved, I save the location of the currently selected (it isn't final since the user haven't released the mouse) rectangle, and use the repaint() function. I wish to display that rectangle over the original drawing, making it similar to the Selection tool in MSPaint.
The problem is that when I call the repaint() function, the method paintComponent (Graphics page) is invoked, in which I use the method super.paintComponent(page) which erases my drawing. However, if I don't use that method when I know the user is selecting a rectangle, I get that all the selected rectangles are "packed" one above the other, and this is an undesirable result - I wish to display the currently selected rectangle only.
I thought I should be able to save a copy of the Graphics page of the drawing and somehow restore it every time the user moves the mouse, but I could not find any documentation for helpful methods.
Thank you very much,
Ron.
Edit: Here are the relevant pieces of my code:
public class DrawingPanel extends JPanel
{
public FractalPanel()
{
addMouseListener (new MyListener());
addMouseMotionListener (new MyListener());
setBackground (Color.black);
setPreferredSize (new Dimension(200,200));
setFocusable(true);
}
public void paintComponent (Graphics page)
{
super.paintComponent(page);
//that's where the drawing takes place: page.setColor(Color.red), page.drawOval(..) etc
}
private class MyListener implements MouseListener, MouseMotionListener
{
...
public void mouseDragged (MouseEvent event)
{
//saving the location of the rectangle
isHoldingRectangle = true;
repaint();
}
}
}
I'm betting that you are getting your Graphics object via a getGraphics() call on a component, and are disatisfied since this obtains a Graphics object which does not persist. It is for this reason that you shouldn't do this but instead just do your drawing inside of the JPanel's paintComponent. If you do this all will be happy.
As an aside -- we'll be able to help you better if you tell us more of the pertinent details of your problem such as how you're getting your Graphics object and how you're trying to draw with it, key issues here. Otherwise we're limited to taking wild guesses about what you're trying to do.
e.g.,
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class MandelDraw extends JPanel {
private static final String IMAGE_ADDR = "http://upload.wikimedia.org/" +
"wikipedia/commons/thumb/b/b3/Mandel_zoom_07_satellite.jpg/" +
"800px-Mandel_zoom_07_satellite.jpg";
private static final Color DRAWING_RECT_COLOR = new Color(200, 200, 255);
private static final Color DRAWN_RECT_COLOR = Color.blue;
private BufferedImage image;
private Rectangle rect = null;
private boolean drawing = false;
public MandelDraw() {
try {
image = ImageIO.read(new URL(IMAGE_ADDR));
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
#Override
public Dimension getPreferredSize() {
if (image != null) {
return new Dimension(image.getWidth(), image.getHeight());
}
return super.getPreferredSize();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if (image != null) {
g.drawImage(image, 0, 0, null);
}
if (rect == null) {
return;
} else if (drawing) {
g2.setColor(DRAWING_RECT_COLOR);
g2.draw(rect);
} else {
g2.setColor(DRAWN_RECT_COLOR);
g2.draw(rect);
}
}
private class MyMouseAdapter extends MouseAdapter {
private Point mousePress = null;
#Override
public void mousePressed(MouseEvent e) {
mousePress = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
drawing = true;
int x = Math.min(mousePress.x, e.getPoint().x);
int y = Math.min(mousePress.y, e.getPoint().y);
int width = Math.abs(mousePress.x - e.getPoint().x);
int height = Math.abs(mousePress.y - e.getPoint().y);
rect = new Rectangle(x, y, width, height);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
drawing = false;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MandelDraw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MandelDraw());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You need to repaint on every mouse movement:
public void mouseDragged(MouseEvent e){
int x = e.getX();
int y = e.getY();
//Update the rectangle holder object with that point coordinates
repaint();
}
You'll probably have a holder rectangle object to hold the initial and final rectangle points. The initials are set on mouse click, the final are modified on mouse dragged and on mouse released.
In paint method, clear the graphics and draw a rectangle with the coordinates in the holder. This is the basic idea.
UPDATE: How to draw a new shape on top of the existing image:
I'm thinking of two options:
If you are only drawing shapes (such as lines, rectangles and other Java2D stuff) you could have a Collection holding these shapes coordinates, and draw all of them on each paint. Pros: good when there are few shapes, allows undoing. Cons: When the number of shapes increase, the paint method will take more and more time in each pass.
Have a "background image". On each paint call, draw first the image and then the currently active shape on top. when an active shape is made persistent (onMouseReleased), it is saved to the background image. Pros: efficient, constant time. Cons: drawing a big background image on every mouse movement could be "expensive".

painting from an external method

In my applet I have a method paint that paints on screen.
public void init() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent evt) {
storeCoordinates(evt,Graphics g); // results in error
}
});
}
public void paint(Graphics g) {
// do something
}
public void storeCoordinates(MouseEvent evt , Graphics g) {
// from this method i want to modify the scene painted by paint
}
Now in another method I want to modify a bit of a scene that was painted by the paint method. How can I do this ? Like I want to draw blue lines using g.drawLine(.,.,.,.) from another method.
The above snippet generates an error saying ) expected ; expected , cannot find symbol variable Graphics when i call the function from mouseMoved
In response to edits:
So what I would do in this case is not use the graphics right there. Instead, I would do something like this... Keep a list of your points, and when you click, add the point to your list. Then when you draw, draw your points. (If you're only going to be drawing on click, you could just store the last point, draw a line between the current point and the last point, and set the last point to the current point. But this is more extensible.)
List<Point> points = new ArrayList<Points>();
public void init() {
addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent evt) {
storeCoordinates(evt); // graphics removed
}
});
}
public void paint(Graphics g) {
for(int i = 1; i < points.size(); i++) {
Point first = points.get(i - 1);
Point second = points.get(i);
g.setColor(Color.BLUE);
g.drawLine(first.getX(), first.getY(), second.getX(), second.getY());
}
}
public void storeCoordinates(MouseEvent evt) {
int x = evt.getX();
int y = evt.getY();
points.add(new Point(x,y));
}
.
Old Answer
Pass your graphics object as a parameter to that other method.
public void paint(Graphics g) {
externalPaint(g);
}
private void externalPaint(Graphics g) {
g.drawLine(1,2,3,4);
}
Now in another method I want to modify a scene on that was painted by the paint method. How can I do this?
Call Component.repaint(int,int,int,int) or JComponent.repaint(Rectangle).

Categories

Resources