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.
Related
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());
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.
I am creating an applet that lets the user draw different shapes using the rubber band effect, letting the user see the shape while it is being drawn. What I want is for the program to draw shapes that stay on the screen. The problem is that the program draws a shape wherever the mouse is.
Take the program below, for example. Say the user clicks the applet at point (50,50) and drags the mouse to draw a rectangle with the bottom-right corner at (70,70). The program will draw several rectangles inside the final rectangle (i.e. rectangles with the bottom-right corner at (54,56), (63,61), etc.). I only want the final rectangle to be shown, but also while using the rubber band effect. If the user were to draw a second rectangle, the first one would remain on the screen while the user draws the second one.
How can I alter the code to make this work?
import java.awt.Graphics;
import java.awt.event.*;
public class Test extends java.applet.Applet implements MouseListener, MouseMotionListener {
int downX, downY, dragX, dragY;
public void init() {
downX = downY = dragX = dragY = 0;
addMouseListener(this);
addMouseMotionListener(this);
}
public void paint(Graphics g) {
g.drawRect(downX,downY,dragX-downX,dragY-downY);
}
public void update(Graphics g) {
paint(g);
}
public void mouseClicked(MouseEvent e) {
downX = e.getX();
downY = e.getY();
}
public void mouseDragged(MouseEvent e) {
dragX = e.getX();
dragY = e.getY();
repaint();
}
public void /*Other MouseEvent methods*/ {}
}
You've broken the paint chain. Failing to call super.paint is preventing the applet from preparing the Graphics context for painting, by removing anything that might have been painted to it before. There's no need to override update, as you're not doing anything with it.
Typically, you should avoid overriding paint of top level containers, as they aren't double buffered and will flicker as they are repainted
You should avoid using Applet and instead use a combination of JApplet a (for example) JPanel as your drawing surface . In fact, if you're just learning. It would be better to use JFrame as applets have a lot of additional management
Painting by its very nature is destructive. You need to maintain a list of things that you want to draw. In this, I would recommend a List of Points, which can be used to paint lines, where the last point is the current drag point
Also take a look at Painting in AWT and Swing for details about how painting works
I have a Ball class which I want to have extend JComponent and implement mouseListener.
public class Ball extends JComponent implements MouseListener {
Int x, y, radius;
public Ball(int X, int Y, int Radius){
//contains only three ints and redefines x,y,radius
x=X;
y=Y;
radius=Radius;
}
public void draw(Graphics g){
//draw oval using x,y,radius
}
//5 mouselisteners undefined yet
}
So ball is the constructor which is used by a panel which is within a frame.
Sorry I have not yet entered all the code. I will submit my complete code soon.
So what I would have to do is use MouseEntered listener in the ball class so that when the mouse enters the component (the ball/oval) .
But I don't know how to define the component so that it knows it has been entered.
Does it need some dimensions? Because all I am doing is using the draw function in a panel.
If this were my class, I wouldn't have it extend JComponent and wouldn't give it a MouseListener or MouseMotionListener especially if I wanted to display multiple balls in a single JComponent. Instead I would give it public methods that allow other classes to get its boundaries (such as is available from the Shape interface), and whether something is contained in the shape or not (again the Shape interface works well for this), and other public methods that allow outside classes to change the state (appearance?) of this object.
I would then have a JComponent hold one Ball or an ArrayList<Ball>, and in the MouseListener/MouseMotionListener/MouseAdapter for this JComponent, iterate through the ArrayList<Ball> seeing if the mouse is inside of any ball, and if so, change that ball's state. Then in the JComponent's paintComponent method, I'd iterate through the ArrayList<Ball> calling draw(g) on each Ball contained.
You should call
this.addMouseListener(new MouseAdapter() {
....
});
in the constructor. Override mouseEntered() and mouseExited() inside of the adapter.
I would prefer that you implement the whole MouseListener. It could be possible that you want later more from your Ball-Component, like for example that it moves if you click on it or something. If you implement the interface you are applicable for later changes.
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
public class Ball extends JComponent implements MouseListener {
int x, y, radius;
public Ball(int x, int y, int radius){
//contains only three ints and redefines x,y,radius
this.x= x;
this.y= y;
this.radius= radius;
}
public void draw(Graphics g){
//draw oval using x,y,radius
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
//your code to do things, when the mouse entered your ball
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
Besides the remarks already made by Hovercraft Full Of Eels, I think you confuse the concept of a being a listener, and adding a listener to something.
It is not by implementing MouseListener that those methods will be called. A listener is the interested party and you add it to the object in which you are interested. So in this case you want to add a MouseListener to your Ball class, which is completely different from letting your Ball class implement MouseListener.
More information can be found on Wikipedia: Observer pattern or a more simple and more Swing oriented document can be found in the Swing tutorials
I have asked a similar question a while ago here, but didn't get an answer. The original question was about changing the color of a shape after clicking on it. But I am puzzled on how to access the shape at all after it is drawn.
This is my paintComponent method
#Override
protected void paintComponent(Graphics graph) {
super.paintComponent(graph);
Graphics2D g = (Graphics2D) graph;
// smooth graphics
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// moving to the middle of the panel
g.translate(this.getWidth()/2, this.getHeight()/2);
// painting colored arcs
for(int i = 0; i < 4; i++) {
g.setColor(dimColors[i]);
g.fill(arcs[i]);
}
// painting borders
g.setColor(Color.BLACK);
g.setStroke(new BasicStroke(5F));
g.drawLine(-98, 0, 98, 0);
g.drawLine(0, -98, 0, 98);
g.draw(circle);
// painting central white circle
g.setColor(Color.WHITE);
g.fill(smallCircle);
g.setColor(Color.BLACK);
g.draw(smallCircle);
}
the arcs[] array contains a bunch of Arc2D's that are drawn on the panel. My question is now, if I want to change the color of, for example arcs[0], how do I do that?
Thanks!
EDIT: I now have this MouseAdapter event
private class MyMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
Component c = getComponentAt(p);
Graphics g = c.getGraphics();
dimColors[1] = Color.RED;
paintComponent(g);
}
}
And it works, it changes the color of arc[1] because arcs[1] has dimColors[1] set as color when drawing it.
However, I still can't figure out how to check wether the right arc was clicked. Right now you just click anywhere on the graphics panel and it changes the color of that specific arc
This doesn't answer your earlier question, however it does answer your question of click detection. To do this it is best to use Graphics2D because it is a lot easier to write than most other options. Here is an example:
public class GraphicsPanel extends JPanel implements MouseListener
{
private Rectangle2D rect;
First we create our Graphics2D rectangle rect.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)(g);
g2d.setColor(Color.GREEN);
rect = new Rectangle2D.Double(70, 70, 100, 100);
g2d.fill(rect);
this.addMouseListener(this);
}
And then we override the paintComponent method and create our new Rectangle2D.Double object.
We then fill the rectangle with g2d.fill() and then add a mouse listener to the JPanel.
public void mousePressed(MouseEvent e)
{
if(rect.contains(e.getX(), e.getY()))
System.out.println("Rectangle clicked");
}
}
Finally, we need to see if that rectangle contains the point where the user clicked. To do this, simply see if the rectangle we created contains the user's click location by using the Rectangle2D.double's contains(int x, int y) method. That's it!
if I want to change the color of, for example arcs[0], how do I do that?
A line (or whatever) only exists as a bunch of pixels that were painted in the original color. To change its color you must change the current color and draw it again.