I have a combobox in my program, with three options CIRCLE, RECTANGLE, FREEHAND. Each option is connected to a mouselistener. If I swich between the three options the mouselisteners are causing me some problems. Therefore I would like to add a mouselistener only once (for example in the constructor or in the beginning of the method, or somewhere else). Is it even possible, and how would the code look like?
If it is not possible, is there any other way I can solve it?
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(comboBox)) {
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rectangle")) {
contentPane.addMouseListener(new MouseAdapter() { //First mouseListener
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = startX - endX;
int height = startY - endY;
w = Math.abs(width);
h = Math.abs(height);
Rectangle r = new Rectangle(startX, startY, w, h, pickedColor, thickness);
shapeList.add(r);
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Circle")) {
contentPane.addMouseListener(new MouseAdapter() { //Second
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = startX - endX;
int height = startY - endY;
w = Math.abs(width);
h = Math.abs(height);
Circle c = new Circle(startX, startY, w, h, pickedColor, thickness);
shapeList.add(c);
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Freehand")) {
contentPane.addMouseListener(new MouseAdapter() { //Third
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseDragged(MouseEvent e) {
FreeHand fh = new FreeHand(startX, startY, e.getX(), e.getY(), pickedColor, thickness);
shapeList.add(fh);
repaint();
}
});
}
}
Instead of adding a different listener to the panel each time a selection is made in the combo box, you should add a single mouse listener to the panel, in the constructor. And this listener, when one of its methods is called, should first check which option is selected, and act accordingly (i.e. draw a rectangle, or a circle, or by free hand depending on the selection).
The simplest solution would be to store the last listener and remove that before adding a new one:
private MouseListener lastListener;
// ...
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rectangle")) {
if (lastListener != null)
contentPane.removeMouseListener(lastListener);
lastListener = new MouseAdapter() { //First mouseListener
// ...
};
contentPane.addMouseListener(lastListener);
Related
I'm relatively new to Java, but I've made a simple paint program that allows the user to draw, change the color and size of the pen, and clear the drawing area.
The user selects a color from the JColorChooser object 'c' and this is handed off to the Color variable 'selected' through c.getColor(). I want to be able to change the transparency of the selected color, but I don't know if there is a way to convert from Color to RGB so that I can use the setColor(r, g, b, a) method. My code is below. I really appreciate any help!
Color selected;
public class ColorTool extends JPanel {
public ColorTool() {
super(new BorderLayout());
b = new JLabel("Pen Color", JLabel.CENTER);
b.setForeground(Color.black);
c = new JColorChooser(b.getForeground());
c.getSelectionModel().addChangeListener(new ColorListener());
add(c, BorderLayout.PAGE_END);
}
}
public DrawPanel() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
for (int i = 0; i <= 100; i++) {
if (PS == i) {
oldX = (int)(e.getX() - Math.ceil(PS/2));
oldY = (int)(e.getY() - Math.ceil(PS/2));
if (graphics != null) {
graphics.setColor(selected);
graphics.fillOval(oldX, oldY, PS, PS);
}
repaint();
oldX = e.getX();
oldY = e.getY();
}
}
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
BasicStroke size = new BasicStroke(PS,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
currentX = e.getX();
currentY = e.getY();
if (graphics != null) {
graphics.setColor(selected);
graphics.setStroke(size);
graphics.drawLine(oldX, oldY, currentX, currentY);
}
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
public class ColorListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
selected = c.getColor();
}
}
You can access that by calling the method getComponents on the instance of Color.
From the documentation:
public float[] getComponents(float[] compArray)
Returns a float array containing the color and alpha components of the Color, in the ColorSpace of the Color. If compArray is null, an array with length equal to the number of components in the associated ColorSpace plus one is created for the return value. Otherwise, compArray must have at least this length and it is filled in with the components and returned.
Parameters: compArray - an array that this method fills with the color and alpha components of this Color in its ColorSpace and returns
Returns:
the color and alpha components in a float array.
I want to make an application in order to draw forms (rectangle, line, square, arrow) like in paint using Java SWT Canvas. I'm using mouse events (Up, Down and move) to get the canvas Y and X position. And i have a button for each form types that get canvas mouse position and draw the selected form using the mouse events. My problem is, when i draw the first form (Circle, square, line) everything works, but when draw the second, the first erase. How can I make the first form stay on drawn after redraw the canvas?
Variables:
private static boolean drag = false;
private Canvas compCanvas;
private Button btnSend, btnAdd,btnFreeHand,btnArrow,btnCircle,btnSquare,btnLine;
private Composite mainPanel;
compCanvas = new Canvas(mainPanel, SWT.NONE);
mouseEvents():
private void mouseEvents(){
compCanvas.addListener(SWT.MouseDown, new Listener(){
public void handleEvent(Event e){
System.out.println("Mouse event on canvas DOWN: X VALUE:"+e.x+"Y VALUE:"+e.y);
startY = e.y;
startX = e.x;
drag = true;
}
});
compCanvas.addListener(SWT.MouseUp, new Listener(){
public void handleEvent(Event e){
System.out.println("Mouse event on canvas UP: X VALUE:"+e.x+"Y VALUE:"+e.y);
endY = e.y;
endX = e.x;
drag = false;
//compCanvas.redraw();
}
});
compCanvas.addListener(SWT.MouseMove, new Listener(){
public void handleEvent(Event e){
System.out.println("Mouse event on canvas MOVE: X VALUE:"+e.x+"Y VALUE:"+e.y);
if(drag){
endY = e.y;
endX = e.x;
compCanvas.redraw();
}
}
});
};
btnSquare.selectionListener() and Declaration:
btnSquare = new Button(compSendAdd, SWT.NONE);
btnSquare.setLayoutData(new RowData(25, 25));
btnSquare.setImage(squareIcon);
btnSquare.addSelectionListener(new SelectionListener(){
private void btnSquare(){
mouseEvents();
//LightweightSystem lws = new LightweightSystem(compCanvas);
compCanvas.addListener(SWT.Paint, new Listener(){
public void handleEvent(Event e){
if(drag){
GC gc = e.gc;
//gc.setAlpha(128);
int minX = Math.min(startX,endX);
int minY = Math.min(startY,endY);
int maxX = Math.max(startX, endX);
int maxY = Math.max(startY, endY);
int width = maxX - minX;
int height = maxY - minY;
gc.fillRectangle(minX, minY,width,height);
}
}
});
}
public void widgetSelected(SelectionEvent event) {
btnSquare();
}
public void widgetDefaultSelected(SelectionEvent event) {
btnSquare();
}
});
By default controls are filled with current background color each time the SWT.Paint listener is called. You need to turn this off.
Do this by specifying the SWT.NO_BACKGROUND style on the Canvas
compCanvas = new Canvas(mainPanel, SWT.NO_BACKGROUND);
You will also need to fill the background the first time the canvas is drawn.
Create class shape with x, y, width, height fields
class Shape {
public int x; // coordiates
public int y;
public int width;
public int heigth;
String type; // "rect" for example
public Shape(int x, int y, int width, int height, String type) {
this.x = x;
this.y = y;
this.width = width;
this.heigth = height;
this.type = type;
}
}
After mouse up store your shape in list according to which button is selected
List<Shape> shapes = new ArrayList<Shape>();
shapes.add(new Shape(x, y, width, height, getType()));
In PainListener You MUST redraw all shapes from your list
for(Shape s: shapes) {
//draw shape s
}
I have some issues with my paint program in Java.
I have a JComboBox where I can choose to draw either a rectangle or by freehand. The objects are added to an ArrayList. I want to be able to switch between drawing a rectangle and by free hand, and then back to drawing a rectangle, and then by free hand... and so on.
If I do that as the code looks like now, it first draws rectangles fine and then when I switch to free hand it draws lines fine, but then when I switch back to rectangles it still draws lines (or sometimes lines together with weird looking rectangles). The more I switch the weirder it gets.
Can anyone see what is wrong with the code, because I can't?
public abstract class Draw {
public int startX, startY, endX, endY, width, height, w, h;
public String color = "Black";
public Draw(int startX, int startY, int width, int height) {
this.startX = startX;
this.startY = startY;
this.width = width;
this.height = height;
}
public abstract void draw(Graphics2D g);
public int getX() {
return startX;
}
public void setX(int startX) {
this.startX = startX;
}
public int getY() {
return startY;
}
public void setY(int startY) {
this.startY = startY;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void setColor(String color) {
this.color = color;
}
}
public class Rectangle extends Draw {
public Rectangle(int x, int y, int width, int height) {
super(x, y, width, height);
}
#Override
public void draw(Graphics2D g2) {
g2.drawRect(getX(), getY(), getWidth(), getHeight());
}
}
public class FreeHand extends Draw {
public FreeHand(int x, int y, int width, int height) {
super(x, y, width, height);
}
#Override
public void draw(Graphics2D g2) {
g2.drawLine(getX(), getY(), getWidth(), getHeight());
}
}
public class PaintProgram extends JFrame implements ActionListener {
public ArrayList<Draw> shapeList = new ArrayList<>();
int startX, startY, endX, endY, w, h;
private JPanel topPanel;
private JPanel bottomPanel;
private JPanel leftPanel;
private JPanel rightPanel;
private JComboBox comboBox;
private final String[] boxOptions = new String[] {"Rectangle", "Freehand"};
Container cp = getContentPane();
private int count = 0;
public JavaApplication30(String title) {
super(title);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setSize(840, 500);
this.initComponents();
this.setVisible(true);
}
private void initComponents() {
cp.setBackground(Color.WHITE);
comboBox = new JComboBox(boxOptions);
topPanel = new JPanel();
bottomPanel = new JPanel(new GridLayout(1,2));
rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
comboBox.setSelectedIndex(0);
comboBox.addActionListener(this);
topPanel.setPreferredSize(new Dimension(0,40));
bottomPanel.setPreferredSize(new Dimension(0,30));
bottomPanel.setBackground(Color.LIGHT_GRAY);
topPanel.add(comboBox);
bottomPanel.add(leftPanel);
bottomPanel.add(rightPanel);
this.add(topPanel, BorderLayout.PAGE_START);
this.add(bottomPanel, BorderLayout.PAGE_END);
}
#Override
public void paint(Graphics g) {
if(count == 0) {
cp.repaint();
}
Graphics2D g2 = (Graphics2D) g;
for (Draw d : shapeList) {
d.draw(g2);
}
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1));
if (startX != 0 && startY != 0 && endX != 0 && endY != 0) {
int width = Math.abs(startX - endX);
int height = Math.abs(startY - endY);
int minX = Math.min(startX, endX);
int minY = Math.min(startY, endY);
Rectangle r = new Rectangle(minX, minY, width, height);
g2.setPaint(Color.WHITE);
g2.fillRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
r.setColor(pickedColor);
r.draw(g2);
}
}
#Override
public void actionPerformed(ActionEvent e) {
count++;
if (e.getSource().equals(comboBox)) {
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rectangle")) {
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
endX = startX;
endY = startY;
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = Math.abs(startX - endX);
int height = Math.abs(startY - endY);
int minX = Math.min(startX, endX);
int minY = Math.min(startY, endY);
Rectangle r = new Rectangle(minX, minY, width, height);
shapeList.add(r);
r.setColor(pickedColor);
startX = 0;
startY = 0;
endX = 0;
endY = 0;
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
endX = e.getX();
endY = e.getY();
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Freehand")) {
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
addCoordinate(startX, startY);
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g;
FreeHand fh = new FreeHand(startX, startY, e.getX(), e.getY());
shapeList.add(fh);
fh.setColor(pickedColor);
fh.draw(g2);
startX = e.getX();
startY = e.getY();
}
});
}
}
}
public static void main(String args[]) {
new PaintProgram("Paint");
}
}
You add MouseListeners but you do not remove them. Every time you choose something in the combobox, a new listener is added. So when you draw something every listener is applied and weird stuff will happen.
You should remove the previous MouseListener before adding a new one. You might have to remember it in an instance variable.
Alternatively, you can add all listeners at the start, but check the value of the combobox inside the listener. If the value does not correspond to what the listener is for, it should do nothing.
EDIT: Here is how you can remove all listeners
for (MouseListener listener : this.getMouseListeners()) {
this.removeMouseListener(listener);
}
for (MouseMotionListener listener : this.getMouseMotionListeners()) {
this.removeMouseMotionListener(listener);
}
Put this code in before you add the new listeners in the actionPerformed() method
As was stated here and here previously, do not add MouseListeners within your ActionListener, instead, create a single MosueListener and determine what you want to do based on the currently selected item.
Basically, you keep adding a new MouseListener each time actionPerformed is called...they are accumulating...
A solution would be to use a single MouseListener and a factory of some kind...
Start by defining the factory interface...
public interface DrawFactory {
public Draw createDrawing(int x, int y, int width, int height, Color color);
public void addPoint(Draw draw, int x, int y);
}
Create a implementation of the factory for each type of shape you want to draw...
public class RectangleFactory implements DrawFactory {
#Override
public Draw createDrawing(int x, int y, int width, int height, Color color) {
return new Rectangle(x, y, width, height);
}
#Override
public void addPoint(Draw draw, int x, int y) {
// Does nothing...
}
#Override
public boolean isMutable() {
return false;
}
#Override
public String getName() {
return "Rectangle";
}
#Override
public String toString() {
return getName();
}
}
public class FreeHandFactory implements DrawFactory {
#Override
public Draw createDrawing(int x, int y, int width, int height, Color color) {
return new FreeHand(x, y, width, height);
}
#Override
public void addPoint(Draw draw, int x, int y) {
if (draw instanceof FreeHand) {
FreeHand fh = (FreeHand)draw;
//fh.addPoint(x, y);
}
}
#Override
public boolean isMutable() {
return true;
}
#Override
public String getName() {
return "Free Hand";
}
#Override
public String toString() {
return getName();
}
}
Next, create a custom component that extends from JPanel which will act as the primary drawing surface, this will be repsonsible for monitoring the MouseLstener and painting the Draw instances, as was mentioned here
public class DrawSurface extends JPanel {
private DrawFactory factory;
private Draw currentDraw;
private List<Draw> shapeList = new ArrayList<>();
private Color drawColor;
public DrawSurface() {
shapeList = new ArrayList<>(25);
MouseAdapter ma = new MouseAdapter() {
private Point pressPoint;
#Override
public void mousePressed(MouseEvent e) {
pressPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
DrawFactory factory = getDrawFactory();
if (factory != null) {
Point p = e.getPoint();
if (factory.isMutable() && currentDraw != null) {
factory.addPoint(currentDraw, p.x, p.y);
} else {
int x = Math.min(p.x, pressPoint.x);
int y = Math.min(p.y, pressPoint.y);
int width = Math.abs(p.x - pressPoint.x);
int height = Math.abs(p.y - pressPoint.y);
Draw draw = factory.createDrawing(x, y, width, height, getDrawColor());
shapeList.add(draw);
if (factory.isMutable()) {
currentDraw = draw;
}
}
}
}
};
}
public DrawFactory getDrawFactory() {
return factory;
}
public void setDrawFactory(DrawFactory factory) {
this.factory = factory;
currentDraw = null;
}
public Color getDrawColor() {
return drawColor;
}
public void setDrawColor(Color drawColor) {
this.drawColor = drawColor;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Draw draw : shapeList) {
draw.draw(g2d);
}
g2d.dispose();
}
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
Next, change your boxOptions from String to DrawFactory, this will make it easier to determine which factory you should use. Don't forget to add a reference to the DrawSurface
private final DrawFactory[] boxOptions = new DrawFactory[]{new RectangleFactory(), new FreeHandFactory()};
private DrawSurface drawSurface;
In your initComponents create a new instance of DrawSurface and add it to your frame...
private void initComponents() {
//...
drawSurface = new DrawSurface();
this.add(drawSurface);
}
Change your actionPerformed method to look more like...
#Override
public void actionPerformed(ActionEvent e) {
count++;
drawSurface.setDrawFactory((DrawFactory)comboBox.getSelectedItem());
}
Not sure how you are determining the current color as you example code is incomplete, but basically, you want to set the drawColor of the DrawSurface similarly.
Get rid of the paint method in the PaintProgram as you shouldn't be overriding the paint method of top level containers, which you've been advised against at least once, if not twice.
The point of all this is simple, when you want to add a new "drawing shape", you create a Draw and DrawFactory for it and add the factory to the combo box ... work done...
I'm building an app that recognises lines drawn with mouse and creates music. I'm new to java2d so heres the problem i'm having:
When you draw, and then make another drawing, the last point of the previous drawing connects to the first of the new one. I havent been able to figure out how to fix this. Below is the code.
Another question is: I would like to store each stroke of drawing (from mousePressed to mouseReleased) into a ArrayList of type Shape, how can I go into that?
I'd like to be pointed in the right direction as I havent been able to find helpful info online. Thanks!
public class DrawBoard extends JPanel implements MouseListener,
MouseMotionListener {
public JLabel status;
public Point pstart, pfinish;
private Shape currentShape = null;
private ArrayList<Point> points = new ArrayList<Point>();
private ArrayList<Shape> lines = new ArrayList<Shape>();
public DrawBoard() {
Dimension size = getPreferredSize();
size.setSize(1024, 800); // w, h
setPreferredSize(size);
setOpaque(false);
status = new JLabel("default");
add(status, BorderLayout.SOUTH);
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
status.setText(String.format("Clicked at %d,%d", e.getX(), e.getY()));
}
// Where the drawing happens
#Override
public void mousePressed(MouseEvent e) {
status.setText("you pressed down the mouse");
this.pstart = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
status.setText("you draged the mouse");
points.add(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
status.setText("you release the mouse click");
pfinish = e.getPoint();
}
// End of where the drawing happens
#Override
public void mouseEntered(MouseEvent e) {
status.setText("you entered the area");
}
#Override
public void mouseExited(MouseEvent e) {
status.setText("mouse exited the area");
}
#Override
public void mouseMoved(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet.");
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(5));
for (int i = 0; i < points.size() - 2; i++) {
Point p1 = points.get(i);
Point p2 = points.get(i + 1);
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
}
}
}
I have modified it using BufferedImage and it works for drawing normally, now the only thing does nto work is the clear method, i have tried different methods but none have worked. My new code is Below:
public class DrawBoard extends JPanel implements MouseListener, MouseMotionListener{
public JLabel status;
private JLabel imgLabel;
public Point pstart, pfinish;
private Shape currentShape = null;
private List<Point> points = new ArrayList<Point>();
private List<BufferedImage> lines = new ArrayList<BufferedImage>();
private static final int BI_WIDTH = 1024;
private static final int BI_HEIGHT = 800;
private BufferedImage bImage = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
public DrawBoard(){
Graphics2D g2d = bImage.createGraphics();
g2d.dispose();
Dimension size = getPreferredSize();
size.setSize(1024,800); //w, h
setPreferredSize(size);
status = new JLabel("default");
add(status, BorderLayout.SOUTH);
addMouseListener(this);
addMouseMotionListener(this);
imgLabel = new JLabel(new ImageIcon(bImage)) {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintInLabel(g);
}
};
imgLabel.setOpaque(false);
setOpaque(false);
add(imgLabel, BorderLayout.CENTER);
}
private void paintInLabel(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE); // this colour is when mouse is pressed
g2d.setStroke(new BasicStroke(5));
if (points.size() < 2) {
return;
}
for (int i = 1; i < points.size(); i++) {
int x1 = points.get(i - 1).x;
int y1 = points.get(i - 1).y;
int x2 = points.get(i).x;
int y2 = points.get(i).y;
g2d.drawLine(x1, y1, x2, y2);
}
}
#Override
public void mouseClicked(MouseEvent e) {
status.setText(String.format("Clicked at %d,%d", e.getX(), e.getY()));
}
// Where the drawing happens
#Override
public void mousePressed(MouseEvent e) {
status.setText("you pressed down the mouse");
this.pstart = e.getPoint();
points.add(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
status.setText("you draged the mouse");
points.add(e.getPoint());
imgLabel.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
status.setText("you release the mouse click");
Graphics2D g2d = bImage.createGraphics();
g2d.setColor(Color.blue); // this is the final colour
g2d.setStroke(new BasicStroke(5));
if (points.size() >= 2) {
for (int i = 1; i < points.size(); i++) {
int x1 = points.get(i - 1).x;
int y1 = points.get(i - 1).y;
int x2 = points.get(i).x;
int y2 = points.get(i).y;
g2d.drawLine(x1, y1, x2, y2);
}
}
g2d.dispose();
points.clear();
imgLabel.repaint();
}
// End of where the drawing happens
#Override
public void mouseEntered(MouseEvent e) {
status.setText("you entered the area");
}
#Override
public void mouseExited(MouseEvent e) {
status.setText("mouse exited the area");
}
#Override
public void mouseMoved(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void clearDrawBoard() {
imgLabel.setIcon(null);
}
}
A few solutions and suggestions:
Don't draw from a single List<Point> as there's no way of knowing where one line ends and another begins.
Consider drawing each line to a BufferedImage once it is complete and display that BufferedImage in your JComponent in its paintComponent method. You would place it in the BufferedImage in the mouseReleased(...) method.
Or consider creating an List<List<Point>> so you can iterate through each line as needed. You would add the new List<Point> to the original List in the mouseReleased(...) method.
Consider using your List<Shape> and fill it with Line2D objects that can be drawn. The Line2D would be added to the List<Shape> in the mouseReleased(...) method.
Also: You should not override paint(...) but rather `paintComponent(...).
Also: Don't forget the #Override annotation for safer coding.
For example, please see my code and answer here.
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?
Try this...Draw a red line on the screen as the mouse is moved (dragged).
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);
}
The MouseListener interface is your friend for this. You can just implement mousePressed and mouseReleased functions. The MouseListener interface has the following methods that you can play around with:
public void mouseEntered(MouseEvent mouse){ }
public void mouseExited(MouseEvent mouse){ }
public void mousePressed(MouseEvent mouse){ }
public void mouseReleased(MouseEvent mouse){ }
JFrame frame = new JFrame("Lines");
frame.add(new JComponent() {
private Shape line = null;
{
line = new Line2D.Double(100, 100, 200, 200);
prevPoint = new Point();
newPoint = new Point();
MouseAdapter mouseAdapter = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
prevPoint = e.getPoint();
System.out.println("Prev Point=" + prevPoint.toString());
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
int dx = 0;
int dy = 0;
dx = (int) (prevPoint.x - e.getPoint().getX());
dy = (int) (prevPoint.y - e.getPoint().getY());
Line2D shape = (Line2D) line;
int x1 = (int) (shape.getX1() - dx);
int y1 = (int) (shape.getY1() - dy);
int x2 = (int) (shape.getX2() - dx);
int y2 = (int) (shape.getY2() - dy);
Point startPoint = new Point(x1, y1);
Point endPoint = new Point(x2, y2);
if (shape != null) {
shape.setLine(startPoint, endPoint);
prevPoint = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
repaint();
}
};
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(Color.BLUE);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (line != null) {
g2d.draw(line);
}
}
});
frame.setSize(650, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This will move the line as the mouse is moved..
Hope this helps..