So I have a program that is basically like paint but made in Java and can only draw a few colours. By default the background of the program is white, but what I'd like to do is try to load an image and then be able to draw on top of that image. I can load the image but fro some reason it wont show the lines when I try drawing on it. Here is the code.
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Paint {
public static void main(String[] args) {
PaintWindow frame = new PaintWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
}
class PaintWindow extends JFrame {
public PaintWindow() {
setTitle("JavShot Edit");
setSize(668, 600);
setLocationRelativeTo(null);
panel = new JPanel();
drawPad = new PadDraw();
panel.setPreferredSize(new Dimension(75, 68));
//Creates a new container
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
//sets the panel to the left, padDraw in the center
content.add(panel, BorderLayout.WEST);
content.add(drawPad, BorderLayout.CENTER);
//add the color buttons:
makeColorButton(Color.BLUE);
makeColorButton(Color.MAGENTA);
makeColorButton(Color.RED);
makeColorButton(Color.GREEN);
makeColorButton(Color.BLACK);
makeColorButton(Color.WHITE);
//creates the clear button
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawPad.clear();
}
});
panel.add(clearButton);
}
/*
* makes a button that changes the color
* #param color the color used for the button
*/
public void makeColorButton(final Color color) {
JButton tempButton = new JButton();
tempButton.setBackground(color);
tempButton.setPreferredSize(new Dimension(16, 16));
panel.add(tempButton);
tempButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawPad.changeColor(color);
}
});
}
private JPanel panel;
private PadDraw drawPad;
}
class PadDraw extends JComponent {
//this is gonna be your image that you draw on
Image image;
//this is what we'll be using to draw on
Graphics2D graphics2D;
//these are gonna hold our mouse coordinates
int currentX, currentY, oldX, oldY;
public PadDraw() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
//if the mouse is pressed it sets the oldX & oldY
//coordinates as the mouses x & y coordinates
public void mousePressed(MouseEvent e) {
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
//while the mouse is dragged it sets currentX & currentY as the mouses x and y
//then it draws a line at the coordinates
//it repaints it and sets oldX and oldY as currentX and currentY
public void mouseDragged(MouseEvent e) {
currentX = e.getX();
currentY = e.getY();
graphics2D.drawLine(oldX, oldY, currentX, currentY);
graphics2D.drawLine(oldX + 1, oldY + 1, currentX + 1, currentY + 1);
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
//this is the painting bit
//if it has nothing on it then
//it creates an image the size of the window
//sets the value of Graphics as the image
//sets the rendering
//runs the clear() method
//then it draws the image
public void paintComponent(Graphics g) {
try {
image = ImageIO.read(new File("C:\\Users\\user\\Desktop\\Untitled.png"));
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
} catch (IOException e) { }
if(image == null) {
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 0, 0, null);
}
//this is the clear
//it sets the colors as white
//then it fills the window with white
//thin it sets the color back to black
public void clear() {
graphics2D.setPaint(Color.white);
graphics2D.fillRect(0, 0, getSize().width, getSize().height);
graphics2D.setPaint(Color.black);
repaint();
}
public void changeColor(Color theColor) {
graphics2D.setPaint(theColor);
repaint();
}
}
I load the image here:
image = ImageIO.read(new File("C:\\Users\\user\\Desktop\\Untitled.png"));
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
} catch (IOException e) { }
Does anyone know what the problem is?
Painting is a destructive process. That is, each time paintComponent is called, you are expected to repaint what ever it is you need to displayed the screen, entirely from scratch.
There are (at least) two immediate issues with your approach
You are not calling super.paintComponent, this will effect the way in which the paint process updates the screen, this VERY important as you have extended from JComponent which is transparent by default and may compromise the ability for the framework to function correctly (leaving nasty paint artifacts all over the place) - also remember, Graphics is a shared resource. All the other components that are to be painted will share this resource, meaning that you could end up with what ever was painted before you being left on the screen.
You are re-loading your image EVERY time paintComponent is called. This means, that what ever you painted to graphics2D is going to be lost.
I wouldn't bother setDoubleBuffered(false) as this will effect the way in which the component is updated and could produce undesirable results.
I would add each point you want to draw to a List of some kind and paint this list within the paintComponent method.
Don't load resources within any paintXxx method. These should be prepared before hand.
I can see that you are "trying" to perform some kind of double buffering, but this isn't really how it should be done. You are going little from it other then problems. Start with a simple solution first.
Related
I want to prohibit my Sprite object to move on certain coordinates of canvas. How can I do this ? What I have done until now:
Package project1;
import java.awt.*;
// Using AWT's Graphics and Color
import java.awt.event.*;
// Using AWT's event classes and listener
interfaces import javax.swing.*;
// Using Swing's components and containers
/**
* Custom Graphics Example: Using key/button to move a object left or right.
* The moving object (sprite) is defined in its own class, with its own
* operations and can paint itself. *
*/ class Sprite {
// Variables (package access)
public int x;
public int y;
int width, height;
// Use an rectangle for illustration
Color color = Color.RED; // Color of the object
// Constructor
public Sprite(int x, int y, int width, int height, Color color) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
}
// Paint itself given the Graphics context
public void paint(Graphics g) {
g.setColor(color);
g.fillRect(x, y, width, height); // Fill a rectangle
// g.drawLine(20, 0, 20, 240);
System.out.println("paint X: "+x+" Y: "+y);
//System.out.println("paint 2nd X: "+x+" Y: "+y); } }
public class Project1 extends JFrame {
// Define constants for the various dimensions
public static final int CANVAS_WIDTH = 400;
public static final int CANVAS_HEIGHT = 240;
public static final Color CANVAS_BG_COLOR = Color.CYAN;
private DrawCanvas canvas;
// the custom drawing canvas (an inner class extends JPanel)
private Sprite sprite; // the moving object
// Constructor to set up the GUI components and event handlers
public Project1() {
// Construct a sprite given x, y, width, height, color
int x = 0,y = 0;
sprite = new Sprite(CANVAS_WIDTH / 2 - 30, CANVAS_HEIGHT / 2 - 30,
10, 10, Color.RED);
// Set up a panel for the buttons
JPanel btnPanel = new JPanel(new FlowLayout());
JButton btnLeft = new JButton("Move Left ");
btnPanel.add(btnLeft);
btnLeft.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
moveLeft();
requestFocus(); // change the focus to JFrame to receive KeyEvent
}
});
//JPanel btnPanel1 = new JPanel(new FlowLayout());
JButton btnDown = new JButton("Move down ");
btnPanel.add(btnDown);
btnDown.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
moveDown();
requestFocus(); // change the focus to JFrame to receive KeyEvent
}
});
JButton btnRight = new JButton("Move Right");
btnPanel.add(btnRight);
btnRight.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
moveRight();
requestFocus(); // change the focus to JFrame to receive KeyEvent
}
});
JButton btnUp = new JButton("Move Up");
btnPanel.add(btnUp);
btnUp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
moveUp();
requestFocus(); // change the focus to JFrame to receive KeyEvent
}
});
// Set up the custom drawing canvas (JPanel)
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Add both panels to this JFrame
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(btnPanel, BorderLayout.SOUTH);
// "super" JFrame fires KeyEvent
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent evt) {
switch(evt.getKeyCode()) {
case KeyEvent.VK_LEFT: moveLeft(); break;
case KeyEvent.VK_RIGHT: moveRight(); break;
case KeyEvent.VK_DOWN: moveDown(); break;
case KeyEvent.VK_UP: moveUp(); break;
}
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Move a Sprite");
pack(); // pack all the components in the JFrame
setVisible(true); // show it
requestFocus(); // "super" JFrame requests focus to receive KeyEvent }
// Helper method to move the sprite left private void moveLeft() {
// Save the current dimensions for repaint to erase the sprite
int savedX = sprite.x;
// update sprite
sprite.x -= 10;
// Repaint only the affected areas, not the entire JFrame, for efficiency
canvas.repaint(savedX, sprite.y, sprite.width, sprite.height); // Clear old area to background
canvas.repaint(sprite.x, sprite.y, sprite.width, sprite.height); // Paint new location }
// Helper method to move the sprite right private void moveRight() {
// Save the current dimensions for repaint to erase the sprite
int savedX = sprite.x;
// update sprite
sprite.x += 10;
// Repaint only the affected areas, not the entire JFrame, for efficiency
canvas.repaint(savedX, sprite.y, sprite.width, sprite.height); // Clear old area to background
canvas.repaint(sprite.x, sprite.y, sprite.width, sprite.height); // Paint at new location }
private void moveDown() {
//Save the current dimensions for repaint to erase the sprite
int saved = sprite.y;
// update sprite
sprite.y += 10;
// Repaint only the affected areas, not the entire JFrame, for efficiency
canvas.repaint( sprite.x, saved, sprite.width, sprite.height); // Clear old area to background
canvas.repaint(sprite.x, sprite.y, sprite.width, sprite.height); // Paint new location } private void moveUp() {
//Save the current dimensions for repaint to erase the sprite
int savedY = sprite.y;
// update sprite
sprite.y -= 10;
// Repaint only the affected areas, not the entire JFrame, for efficiency
canvas.repaint( sprite.y, savedY, sprite.width, sprite.height); // Clear old area to background
canvas.repaint(sprite.x, sprite.y, sprite.width, sprite.height); // Paint new location }
// Define inner class DrawCanvas, which is a JPanel used for custom drawing class DrawCanvas extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(CANVAS_BG_COLOR);
sprite.paint(g); // the sprite paints itself
} }
// The entry main() method public static void main(String[] args) {
// Run GUI construction on the Event-Dispatching Thread for thread safety
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Project1(); // Let the constructor do the job
}
});
}
}
Too many comments in the code making it difficult to spot the issue, but, going from your question, you could use a grid to keep track of the x&y coordinates. And then check if the coordinates your object is at corresponds with the location(s) you don't want the object to move to. I am using the same strategy for my simulation.
I know it's a stupid question for the Java cracks out there.
At the moment I'm writing a little paintingprogramm.
So my problem is, that i want to set the stroke size in a little dropdownmenu.
The code for the dropdown is here:
DefaultComboBoxModel model = new DefaultComboBoxModel();
model.addElement("1");
model.addElement("5");
model.addElement("10");
JComboBox comboBox = new JComboBox(model);
panel.add(comboBox);
And the Code of the stroke size is here:
public void mouseDragged(MouseEvent e) {
currentX = e.getX();
currentY = e.getY();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Stroke stroke = new BasicStroke(10);
graphics2D.setStroke(stroke);
graphics2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
}
The 10 in the BasicStroke is just some random number. I wanted to realize it, that it reads from the dropdown (standart 1), saves it in a variable and the variable get used in the BasicStroke function.
Here is the whole code (Netbeans project):
package paint;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Paint {
public static void main(String[] args) {
PaintWindow frame = new PaintWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
}
class PaintWindow extends JFrame {
public PaintWindow() {
setTitle("Paint it");
setSize(700, 600);
panel = new JPanel();
panel.setPreferredSize(new Dimension(64, 64));
drawPad = new PadDraw();
//Creates a new container
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
//sets the panel to the left, padDraw in the center
content.add(panel, BorderLayout.NORTH);
content.add(drawPad, BorderLayout.CENTER);
//add the color buttons:
makeColorButton(Color.BLACK);
makeColorButton(Color.BLUE);
makeColorButton(Color.MAGENTA);
makeColorButton(Color.RED);
makeColorButton(Color.ORANGE);
makeColorButton(Color.YELLOW);
makeColorButton(Color.GREEN);
makeColorButton(Color.CYAN);
DefaultComboBoxModel model = new DefaultComboBoxModel();
model.addElement("1");
model.addElement("5");
model.addElement("10");
JComboBox comboBox = new JComboBox(model);
panel.add(comboBox);
//creates the clear button
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawPad.clear();
}
});
panel.add(clearButton);
panel = new JPanel();
JLabel jlabel = new JLabel("Copyright© by Jan Büttiker");
panel.setPreferredSize(new Dimension(0, 20));
panel.add(jlabel);
content.add(panel, BorderLayout.SOUTH);
}
/*
* makes a button that changes the color
* #param color the color used for the button
*/
public void makeColorButton(final Color color) {
JButton tempButton = new JButton();
tempButton.setBackground(color);
tempButton.setPreferredSize(new Dimension(56, 56));
panel.add(tempButton);
tempButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawPad.changeColor(color);
}
});
}
private JPanel panel;
private PadDraw drawPad;
}
class PadDraw extends JComponent {
//this is gonna be the image that you draw on
Image image;
//this is what we'll be using to draw on
Graphics2D graphics2D;
//these are gonna hold the mouse coordinates
int currentX, currentY, oldX, oldY;
public PadDraw() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
//if the mouse is pressed it sets the oldX & oldY
//coordinates as the mouses x & y coordinates
public void mousePressed(MouseEvent e) {
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
//while the mouse is dragged it sets currentX & currentY as the mouses x and y
//then it draws a line at the coordinates
//it repaints it and sets oldX and oldY as currentX and currentY
public void mouseDragged(MouseEvent e) {
currentX = e.getX();
currentY = e.getY();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Stroke stroke = new BasicStroke(10);
graphics2D.setStroke(stroke);
graphics2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
//this is the painting bit
//if it has nothing on it then
//it creates an image the size of the window
//sets the value of Graphics as the image
//sets the rendering
//runs the clear() method
//then it draws the image
public void paintComponent(Graphics g) {
if (image == null) {
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D) image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 0, 0, null);
}
//this is the clear
//it sets the colors as white
//then it fills the window with white
//thin it sets the color back to black
public void clear() {
graphics2D.setPaint(Color.white);
graphics2D.fillRect(0, 0, getSize().width, getSize().height);
graphics2D.setPaint(Color.black);
repaint();
}
public void changeColor(Color theColor) {
graphics2D.setPaint(theColor);
repaint();
}
}
It's my first post, so please be kind, I'm still in the learning phase ^^.
Thanks for the help and have a nice day
For that purposes you need to use ItemListener on your JComboBox. read more about ComboBox in tutorial.
1) add instance variable public float strokeSize = 10.0f; to your PadDraw as default value.
2) use Stroke stroke = new BasicStroke(strokeSize); instead of Stroke stroke = new BasicStroke(10);
3) Create your ComboBox in next way, it will change strokeSize value if you change value in JComboBox:
DefaultComboBoxModel<Float> model = new DefaultComboBoxModel<Float>();
model.addElement(1f);
model.addElement(5f);
model.addElement(10f);
final JComboBox<Float> comboBox = new JComboBox<Float>(model);
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent arg0) {
Float selectedItem = (Float) comboBox.getSelectedItem();
if(selectedItem != null){
drawPad.strokeSize = selectedItem;
}
}
});
I am quite new to Java and Swing, and this is also my first post so sorry if it doesn't make too much sense.
What I am trying to do is when I click on a JPanel, I want it to add a circle where I click. At the moment, all that seems to happen is when I click, a small grey square appears inside the JPanel I want to add to, but I can't seem to find any way of making it draw as a circle.
I have a class that extends JPanel called "Ball" which is what is being added when I click.
At the moment, I am not too worried about it being in the correct location, just for it to draw the ball correctly.
Below is the code for my "Ball" class:
package paintsliders;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
class Ball extends JPanel{
private int x,y,w,h;
//I will use this constructor to put the ball in the correct location later.
Ball(){
/*this.w = 100;
this.h = 100;
this.x = 200;
this.y = 200;*/
}
//draw the ball
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(200,200,10,10);
g.setColor(Color.RED);
}
}
I can kind of guess that it is something to do with the paintComponent method, but everywhere I have looked doesn't seem to have a solution for me.
Any help would be great, thanks!
The Graphcis context has already been translated to meet the x/y location that the component should appear within it's parent container, this means that the top, left corner of the Graphics context within the paintComponent method is actually 0x0.
You need to define some size for the ball, you're painting at 10x10, which would suggest that your ball component should return a preferredSize of 10x10
public Dimension getPreferredSize() {
return new Dimension(10, 10);
}
You will become responsible for providing appropriate layout details to the ball when it's added to the parent container...
public void mouseClicked(MouseEvent evt) {
Point p = evt.getPoint();
Ball ball = new Ball();
Dimension size = ball.getPreferredSize();
ball.setBounds(new Rectangle(p, size));
add(ball);
}
This, of course, assumes you have a null layout set for the parent container
UPDATED
Something like...
public class PaintBalls {
public static void main(String[] args) {
new PaintBalls();
}
public PaintBalls() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new Board());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Board extends JPanel {
public Board() {
setLayout(null);
setBackground(Color.WHITE);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Point p = e.getPoint();
Ball ball = new Ball();
Dimension size = ball.getPreferredSize();
p.x -= size.width / 2;
p.y -= size.height / 2;
ball.setBounds(new Rectangle(p, size));
add(ball);
repaint();
}
});
}
}
public class Ball extends JPanel {
public Ball() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(10, 10);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.fillOval(0, 0, 10, 10);
g2d.dispose();
}
}
}
You probably have a main JPanel where you click.
I would rather design the main panel to handle the mouse click and the Ball class to be a simple Object that defines a drawBall(Graphics g, int x, int y) method that knows how to paint a Ball. This would be called by the paintComponent() method in the main panel. In the main panel, you handle the mouse click, create an object of type Ball and call repaint(). Inside the paintComponent() you call ball.drawBall().
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".
i am using java.
i want to draw rectangle based on mousedrag event. if user dragging the mouse, then the rectangle on the applet should increase or decrease basing on current mouse coordinates.
i have the following code.
in the following code i am using [b]SelectionArea[/b] class which extends a canvas on which i am performing drawing operation. i am using [b]image[/b] variable in this class for double buffering to reduce flickering and to save the applet's previous state(i.e drawing content of applet)
but the code is working fine if i draw first rectangle. if i start to draw second rectangle the previously drawn rectangle is disappearing. i want the previously drawn rectangle to be on the screen
can any one tell me how to solve this.
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
/*
* This displays a framed area. When the user drags within
* the area, this program displays a rectangle extending from
* where the user first pressed the mouse button to the current
* cursor location.
*/
public class RectangleDemo extends Applet {
SelectionArea drawingPanel;
Label label;
public void init() {
GridBagLayout gridBag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
setLayout(gridBag);
drawingPanel = new SelectionArea(this);
c.fill = GridBagConstraints.BOTH;
c.weighty = 1.0;
c.gridwidth = GridBagConstraints.REMAINDER; //end row
gridBag.setConstraints(drawingPanel, c);
add(drawingPanel);
label = new Label("Drag within the framed area.");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
c.weighty = 0.0;
gridBag.setConstraints(label, c);
add(label);
drawingPanel.setVisible(true);
validate();
}
public void paint(Graphics g){
drawingPanel.repaint();
}
public void update(Graphics g){
paint(g);
}
}
class SelectionArea extends Canvas implements ActionListener, MouseListener, MouseMotionListener{
Rectangle currentRect;
RectangleDemo controller;
//for double buffering
Image image;
Graphics offscreen;
public SelectionArea(RectangleDemo controller) {
super();
this.controller = controller;
addMouseListener(this);
addMouseMotionListener(this);
}
public void actionPerformed(ActionEvent ae){
repaintoffscreen();
}
public void repaintoffscreen(){
image = createImage(this.getWidth(), this.getHeight());
offscreen = image.getGraphics();
Dimension d = getSize();
if(currentRect != null){
Rectangle box = getDrawableRect(currentRect, d);
//Draw the box outline.
offscreen.drawRect(box.x, box.y, box.width - 1, box.height - 1);
//repaint();
}
}
public void mouseEntered(MouseEvent me) {}
public void mouseExited(MouseEvent me){ }
public void mouseClicked(MouseEvent me){}
public void mouseMoved(MouseEvent me){}
public void mousePressed(MouseEvent me) {
currentRect = new Rectangle(me.getX(), me.getY(), 0, 0);
repaintoffscreen();
}
public void mouseDragged(MouseEvent me) {
System.out.println("here in dragged()");
currentRect.setSize(me.getX() - currentRect.x, me.getY() - currentRect.y);
repaintoffscreen();
repaint();
}
public void mouseReleased(MouseEvent me) {
currentRect.setSize(me.getX() - currentRect.x, me.getY() - currentRect.y);
repaintoffscreen();
repaint();
}
public void update(Graphics g){
paint(g);
}
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
}
Rectangle getDrawableRect(Rectangle originalRect, Dimension drawingArea) {
int x = originalRect.x;
int y = originalRect.y;
int width = originalRect.width;
int height = originalRect.height;
//Make sure rectangle width and height are positive.
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
//The rectangle shouldn't extend past the drawing area.
if ((x + width) > drawingArea.width) {
width = drawingArea.width - x;
}
if ((y + height) > drawingArea.height) {
height = drawingArea.height - y;
}
return new Rectangle(x, y, width, height);
}
}
also if i run this code on full screen mode then i am seeing that the rectangle is appering on screen only after i released the mouse. but i want the rectangle to be on the screen while dragging the mouse and it should change it's dimension according to the current mouse coordinates.
can any one help me pls.
homework?
basically what you need to do is:
on mouse down keep the mouse-down coordinates and repaint
on mouse move keep current mouse coordinates and repaint
on mouse up, nullify the mouse-down coordinates to indicate there is no rect, and repaint.
on paint, draw background and then rect between mousedown and cur-mouse coordinates.
if you don't want to keep a background image, you can do a trick with the Graphics xor function, drawing the same rect twice will erase the old rect, so you can use it to restore the old image straight on the graphics object.
Edit: code xor usage sample:
public void paint(Graphics g)
{
g.setXORMode(Color.black);
// draw old rect if there is one. this will erase it
// draw new rect, this will draw xored
g.setDrawMode(); // restore normal draw mode
}
Xor has the an interesting property:
xor(xor(x)) = x
so xoring the same pixel twice restores it's original color.
There are a couple issues that need to be addressed.
First, regarding only one rectangle can be drawn, this is due to the design of your program. In your code, whenever the repaintoffscreen method is called, the currectRect field is used to draw a rectangle. However, there is no provision to keep holding onto rectangles which were made in the past.
One way to keep a hold of past rectangles would be perhaps to make another field which is, for example, a List<Rectangle> which is used to store past rectangles. Then, when the mouse is released, add the current rectangle to that list.
Then, in order for all rectangles, currentRect and past rectangles to appear, repaintoffscreen will need to not only perform getDrawableRect and offscreen.drawRect using the currentRect but also with the past rectangles which are stored in the List<Rectangle>. (Hint, use a for loop to iterate through the list.)
Second, regarding the rectangle not appearing until after releasing the mouse button, rather than using the mouseDragged method, maybe using the mouseMoved method along with a check to see that the mouse button is depressed may be a workaround. (I think I've also had trouble dealing with the mouseDragged method in the past.)
The MouseEvent passed into the mouseMoved method can be used to check if a button is depressed by the getButton method:
public void mouseMoved(MouseEvent e)
{
// Check if button1 is pressed.
if (e.getButton() == MouseEvent.BUTTON1)
{
// Perform sizing of rectangle and off-screen drawing, and repaint.
}
}
My question was about create a select rectangle invert mouse click position, but, in the end I got make this with this method:
... //to set the selection area
private int iniSelX;
private int iniSelY;
private int endSelX;
private int endSelY;
private JPanel myJPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
g.drawLine(260, 5, 260, 260);
g.setColor(Color.BLUE);
//verify if go draw the rectangle
if (iniSelX != 0 || endSelX != 0) {
boolean revertX = iniSelX < endSelX;
boolean revertY = iniSelY < endSelY;
//Simple way
//g.drawRect(iniSelX, iniSelY, endSelX - iniSelX, endSelY - iniSelY);
//reverse way
g.drawRect(revertX ? iniSelX : endSelX, revertY ? iniSelY : endSelY,
revertX ? endSelX - iniSelX : iniSelX - endSelX, revertY ? endSelY - iniSelY : iniSelY - endSelY);
}
}
}; ...
addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent m) {
//update selection area
endSelX = m.getX();
endSelY = m.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent m) {
repaint();
}
});
addMouseListener(new MouseListener() {
...
#Override
public void mousePressed(MouseEvent e) {
//start drawing the selection
iniSelX = e.getX() - 15;
iniSelY = e.getY() - 20;
}
#Override
public void mouseReleased(MouseEvent e) {
//start drawing the selection
iniSelX = 0;
iniSelY = 0;
endSelX = 0;
endSelY = 0;
}
...
});
}
public void log() {
System.out.println("iniSelX" + iniSelX);
System.out.println("iniSelY" + iniSelY);
System.out.println("endSelX" + endSelX);
System.out.println("endSelY" + endSelY);
} ...
I hope this is useful.