I'm new to Java and I am trying to make a simple paint program where the user presses button to draw lines by mouse dragging
My problem is that lines aren't drawn on canvas although the properties of each line are saved.
When I try to draw line in the method of "mouse released" it works so I suppose that the problem is with "PaintComponent" but I can't find it.
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
public class GUI extends JPanel{
public JFrame frame = new JFrame();
public Canvas canvas = new Canvas();
private Point p1,p2;
private List<pro> lineList = new ArrayList<>();
private pro currentLine = null;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI window = new GUI();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public GUI() {
initialize();
}
public void paintComponent(Graphics page) {
super.paintComponent(page);
for (pro line : lineList) {
line.draw(page);
System.out.println(line);
}
if (currentLine != null) {
currentLine.draw(page);
}
}
private void initialize(){
frame.getContentPane().setBackground(Color.BLACK);
frame.setBounds(0, 0, 346, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(canvas);
Canvas canvas = new Canvas();
canvas.setLocation(10, 10);
canvas.setSize(200, 241);
canvas.setBackground(Color.DARK_GRAY);
frame.getContentPane().add(canvas);
JButton btnLine = new JButton("Line");
frame.getContentPane().add(btnLine);
btnLine.setBackground(Color.DARK_GRAY);
btnLine.setForeground(Color.RED);
btnLine.setFont(new Font("Stencil", Font.BOLD, 16));
btnLine.addActionListener(new ActionListener() {
int x1;
int y1;
public void actionPerformed(ActionEvent e) {
canvas.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
}
public void mouseReleased(MouseEvent e) {
pro line = createLine(e,Color.red);
lineList.add(line);
currentLine = null;
canvas.repaint();
}
});
canvas.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, Color.white);
repaint();
}
});
}
private pro createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new pro(x1, x2, y1, y2, currentColor);
}
});
btnLine.setBounds(229, 95, 91, 31);
frame.getContentPane().add(btnLine);
}
class pro {
private int x1, x2, y1, y2;
private Color color;
public pro(int x1, int x2, int y1, int y2, Color color) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.color = color;
}
public void draw(Graphics page) {
page.setColor(color);
page.drawLine(x1, y1, x2, y2);
}
}
}
JFrames are not meant to override paintComponent: they're multi-layered containers. If you want to paint a custom component, create a subclass of JComponent (or JPanel), and then put it in (the content pane of) your JFrame.
This works for me:
public class SketchPad extends JComponent {
private final List<Line> lineList = new ArrayList<>();
private Line currentLine = null;
private Color drawingColor = Color.RED;
public SketchPad() {
initialize();
}
public Color getDrawingColor() {
return drawingColor;
}
public void setDrawingColor(Color newColor) {
if (newColor == null) {
throw new IllegalArgumentException("Drawing color cannot be null");
}
this.drawingColor = newColor;
}
private void initialize() {
addMouseListener(new MouseAdapter() {
int x1;
int y1;
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
}
#Override
public void mouseReleased(MouseEvent e) {
Line line = createLine(e, drawingColor);
lineList.add(line);
currentLine = null;
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
currentLine = createLine(e, Color.BLACK);
repaint();
}
private Line createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new Line(x1, x2, y1, y2, currentColor);
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Line line : lineList) {
line.draw(g);
System.out.println(line);
}
if (currentLine != null) {
currentLine.draw(g);
}
}
private static class Line {
private final int x1;
private final int x2;
private final int y1;
private final int y2;
private final Color color;
public Line(int x1, int x2, int y1, int y2, Color color) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.color = color;
}
public void draw(Graphics page) {
page.setColor(color); //!! This first!
page.drawLine(x1, y1, x2, y2); // **Then** this
}
}
}
Main frame:
public class MainFrame extends javax.swing.JFrame {
private SketchPad pad;
public MainFrame() {
initComponents();
}
#SuppressWarnings("unchecked")
private void initComponents() {
pad = new SketchPad();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().add(pad, java.awt.BorderLayout.CENTER);
pack();
}
}
UPDATE: a mouseMotionListener is needed:
private void initialize() {
MouseAdapter adapter = new MouseAdapter() {
int x1;
int y1;
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
addMouseMotionListener(this);
}
#Override
public void mouseReleased(MouseEvent e) {
Line line = createLine(e, drawingColor);
lineList.add(line);
currentLine = null;
repaint();
removeMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, Color.BLACK);
repaint();
}
private Line createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new Line(x1, x2, y1, y2, currentColor);
}
};
addMouseListener(adapter);
addMouseMotionListener(adapter);
}
UPDATE 2: handle enable/disable
private final MouseAdapter adapter = new MouseAdapter() {
int x1;
int y1;
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
}
#Override
public void mouseReleased(MouseEvent e) {
Line line = createLine(e, drawingColor);
lineList.add(line);
currentLine = null;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, Color.BLACK);
repaint();
}
private Line createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new Line(x1, x2, y1, y2, currentColor);
}
};
...
private void initialize() {
setEnabled(isEnabled());
}
...
#Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (enabled) {
addMouseListener(adapter);
addMouseMotionListener(adapter);
} else {
removeMouseListener(adapter);
removeMouseMotionListener(adapter);
}
}
Related
I'm trying to create Circles in JFrame using JComponent. Here's what I'm trying to achieve:
And here's what's happening with my code:
I have no idea what's causing this problem. Here's my code:
CircleViewer.java
import javax.swing.JFrame;
import java.awt.event.*;
public class CircleViewer
{
public static void main(String[] args)
{
final CirclePanel panel = new CirclePanel();
class MousePressListener implements MouseListener, MouseMotionListener
{
public void mouseClicked(MouseEvent event) { }
public void mouseEntered(MouseEvent event) { }
public void mouseExited(MouseEvent event) { }
public void mouseWheelMoved(MouseWheelEvent event) { }
public void mouseMoved(MouseEvent event) { }
public void mousePressed(MouseEvent event)
{
var x = event.getX();
var y = event.getY();
panel.addCircle(x, y);
}
public void mouseDragged(MouseEvent event)
{
var x = event.getX();
var y = event.getY();
panel.moveTo(x, y);
}
public void mouseReleased(MouseEvent event)
{
panel.finalMove();
}
}
MousePressListener listener = new MousePressListener();
panel.addMouseListener(listener);
panel.addMouseMotionListener(listener);
JFrame frame = new JFrame("Circle Shapes");
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
private static final int FRAME_WIDTH = 700;
private static final int FRAME_HEIGHT = 500;
}
CirclePanel.java
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.util.ArrayList;
import java.awt.Color;
import java.lang.Math;
import java.awt.BasicStroke;
import java.awt.Stroke;
public class CirclePanel extends JComponent
{
private int lineX;
private int lineY;
private boolean isDraged;
private ArrayList<Circle> circleList;
private BasicStroke dashLine;
public CirclePanel()
{
this.circleList = new ArrayList<Circle>();
this.isDraged = false;
this.lineX = 0;
this.lineY = 0;
this.dashLine = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{6}, 0);
}
public void addCircle(int x, int y)
{
lineX = x;
lineY = y;
isDraged = true;
circleList.add(new Circle(x, y, 0, Color.RED));
repaint();
}
public void moveTo(int x, int y)
{
var circleTemp = circleList.get(circleList.size() - 1);
isDraged = true;
var tempR = (int)Math.sqrt(Math.pow(x - circleTemp.get(0), 2) + Math.pow(y - circleTemp.get(1), 2));
System.out.println(tempR);
var tempX = circleTemp.get(0) - (tempR / 2);
var tempY = circleTemp.get(1) - (tempR / 2);
circleList.get(circleList.size() - 1).setCords(tempX, tempY, tempR);
lineX = x;
lineY = y;
repaint();
}
public void finalMove()
{
isDraged = false;
circleList.get(circleList.size() - 1).setColor(Color.BLUE);
repaint();
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Stroke defaultStroke;
defaultStroke = g2.getStroke();
if (!circleList.isEmpty())
{
if (isDraged)
{
g2.setColor(Color.RED);
g2.setStroke(dashLine);
g2.drawLine(circleList.get(circleList.size() - 1).get(0), circleList.get(circleList.size() - 1).get(1), lineX, lineY);
}
for (Circle circle : circleList)
{
g2.setStroke(defaultStroke);
circle.draw(g2);
isDraged = false; //this is prob reduntant
}
}
}
}
And finally, Circle.java
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class Circle
{
private int x;
private int y;
private int radius;
private Color color;
public Circle(int x, int y, int radius, Color color)
{
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
}
public int get(int option)
{
switch (option)
{
case 0:
return this.x;
case 1:
return this.y;
case 2:
return this.radius;
}
return 0;
}
public Color get()
{
return this.color;
}
public void setCords(int x, int y, int r)
{
this.x = x;
this.y = y;
this.radius = r;
}
public void set(int option, int value)
{
switch (option)
{
case 0: //set x
this.x = value;
break;
case 1:
this.y = value;
break;
case 2:
radius = value;
break;
}
}
public void setColor(Color color)
{
this.color = color;
}
public void draw(Graphics2D g2)
{
g2.setColor(color);
g2.draw(new Ellipse2D.Double(x, y, radius, radius));
}
}
Rather than finding the specific problem in you code, I just decided to make a cleaner implementation. Using this circle class
class Circle {
final int x;
final int y;
int radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
}
You can implement CirclePanel like this:
public class CirclePanel extends JPanel {
private static final Stroke DASHED = new BasicStroke(1,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL,
0, new float[]{6}, 0);
public Color oldCircleColor = Color.BLUE;
public Color newCircleColor = Color.RED;
public Color backgroundColor = Color.LIGHT_GRAY;
private final List<Circle> oldCircles = new ArrayList<>();
private Circle newCircle = null;
private int mouseX = 0;
private int mouseY = 0;
private class MouseHelper implements MouseListener, MouseMotionListener {
#Override public void mouseMoved(MouseEvent e) {}
#Override public void mouseClicked(MouseEvent e) {}
#Override public void mousePressed(MouseEvent e) {}
#Override public void mouseEntered(MouseEvent e) {}
#Override public void mouseExited(MouseEvent e) {}
#Override
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
if (newCircle == null) {
newCircle = new Circle(mouseX, mouseY, 0);
} else {
int dX = newCircle.x - mouseX;
int dY = newCircle.y - mouseY;
newCircle.radius = (int) Math.sqrt(dX*dX + dY*dY);
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (newCircle != null) {
oldCircles.add(newCircle);
newCircle = null;
repaint();
}
}
}
public CirclePanel() {
MouseHelper helper = new MouseHelper();
addMouseListener(helper);
addMouseMotionListener(helper);
setPreferredSize(new Dimension(400, 400));
}
#Override
public void paint(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(oldCircleColor);
for (Circle c : oldCircles) {
drawCircle(g, c);
}
Circle c = newCircle;
if (c != null) {
g.setColor(newCircleColor);
drawCircle(g, c);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(DASHED);
g2.drawLine(c.x, c.y, mouseX, mouseY);
g2.dispose();
}
}
private void drawCircle(Graphics g, Circle c) {
// note: drawOval takes top-left corner and diameter, NOT center and radius
g.drawOval(c.x - c.radius, c.y - c.radius, c.radius * 2, c.radius * 2);
}
}
And test to see that it works
public static void main(String[] args) {
JFrame frame = new JFrame();
CirclePanel panel = new CirclePanel();
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
Like #SirLenz0rlot mentioned in the comments there is a bug in your moveTo method. The problem is the call circleList.get(circleList.size() - 1).setCords(tempX, tempY, tempR); which is setting the position of the circle to tempX, tempY, but you probably only want to set the radius of the circle, while the coords are not changed.
Changing the moveTo method to the code below should help:
public void moveTo(int x, int y)
{
var circleTemp = circleList.get(circleList.size() - 1);
isDraged = true;
var tempR = (int)Math.sqrt(Math.pow(x - circleTemp.get(0), 2) + Math.pow(y - circleTemp.get(1), 2));
System.out.println(tempR);
var tempX = circleTemp.get(0) - (tempR / 2);
var tempY = circleTemp.get(1) - (tempR / 2);
//EDITED HERE
circleList.get(circleList.size() - 1).setCords(circleTemp.get(0), circleTemp.get(1), tempR);//using getX() and getY() on your circle would be easier to understand here, but this should also work...
lineX = x;
lineY = y;
repaint();
}
For some reason your circleTemp.get(0) and (1) doesn't give you the (x,y) coordinates
circleTemp.get(0)
What you should do is save the circle's (x,y) coordinates, and use them in the moveTo method.
Correct Change
And in the end for the draw line, you should again, use the saved (x,y) coordinates and the new coordinated of the mouse. (not the circleList.size() -1).get(0) - Line 67)
(Ex. I added the drawLineX and drawLineY)
I have to drag multiple JLabels simultaneously after selecting them. I figured out how to drag a single JLabel and how to select multiple ones but I don't how move more than one at a time.
Code of JFrame class
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
public class HallViewer extends JFrame {
private String nomeSala;
private JPanel draggableSeatsPanel;
private List<MyDraggableSeat> draggableSeats = new ArrayList<>();
public HallViewer(String nomeSala) {
this.nomeSala = nomeSala;
initDraggableSeatsList();
initDraggableSeatsPanel();
initFrame();
addMouseListener(mouseHandler);
addMouseMotionListener(mouseMotionHandler);
}
private void initDraggableSeatsList() {
MyDraggableSeat mds1 = new MyDraggableSeat(253, 210);
mds1.setText("A1");
MyDraggableSeat mds2 = new MyDraggableSeat(408, 341);
mds2.setText("A2");
MyDraggableSeat mds3 = new MyDraggableSeat(157, 213);
mds3.setText("A3");
draggableSeats = new ArrayList<>();
draggableSeats.add(mds1);
draggableSeats.add(mds2);
draggableSeats.add(mds3);
}
private void initDraggableSeatsPanel() {
draggableSeatsPanel = new JPanel();
draggableSeatsPanel.setMinimumSize(new Dimension(300, 150));
draggableSeatsPanel.setLayout(null);
for(MyDraggableSeat mds : draggableSeats) {
draggableSeatsPanel.add(mds);
initMouseListenerForMDS(mds);
repaint();
}
}
private void initFrame() {
setTitle("Piantina " + nomeSala);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent windowEvent) {
setVisible(false);
}
});
setLayout(new GridLayout(1,1));
add(draggableSeatsPanel);
setSize(700,500);
setLocationRelativeTo(null);
setVisible(true);
}
private int screenX = 0;
private int screenY = 0;
private int myX = 0;
private int myY = 0;
private void initMouseListenerForMDS(MyDraggableSeat mds) {
mds.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
screenX = e.getXOnScreen();
screenY = e.getYOnScreen();
myX = mds.getX();
myY = mds.getY();
}
});
mds.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int deltaX = e.getXOnScreen() - screenX;
int deltaY = e.getYOnScreen() - screenY;
mds.setLocation(myX + deltaX, myY + deltaY);
}
});
}
private int xbegin;
private int ybegin;
private int xend;
private int yend;
private int width;
private int height;
private int x;
private int y;
private boolean isNewRect = false;
private List<MyDraggableSeat> selectedMDSList = new ArrayList<>();
private MouseListener mouseHandler = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
for(MyDraggableSeat mds : selectedMDSList) {
mds.setBorder(new LineBorder(Color.BLUE, 3));
}
selectedMDSList.clear();
xbegin = e.getX();
ybegin = e.getY();
isNewRect = true;
}
#Override
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
isNewRect = true;
repaint();
Rectangle rectangle = new Rectangle(x,y,width,height);
for(MyDraggableSeat mds : draggableSeats) {
if(rectangle.intersects(new Rectangle(mds.getX(), mds.getY(), mds.getWidth(), mds.getHeight()))) {
selectedMDSList.add(mds);
}
}
for(MyDraggableSeat mds : selectedMDSList) {
mds.setBorder(new LineBorder(Color.CYAN, 3));
}
}
};
private MouseMotionListener mouseMotionHandler = new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
xend = e.getX();
yend = e.getY();
isNewRect = false;
repaint();
}
};
#Override
public void paint(Graphics g) {
super.paint(g);
if((xbegin-xend)<0) {
width = Math.abs(xbegin-xend);
x = xbegin;
} else {
width = Math.abs(xend-xbegin);
x = xend;
}
if((ybegin-yend)<0) {
height = Math.abs(ybegin-yend);
y = ybegin;
} else {
height = Math.abs(yend-ybegin);
y = yend;
}
Graphics2D g2D = (Graphics2D) g;
AlphaComposite transparency = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
g2D.setComposite(transparency);
g2D.setColor(new Color(0x0073b5e9));
if(!isNewRect) {
g2D.fill(new Rectangle2D.Float(x,y,width,height));
}
}
public static class Main {
public static void main(String[] argv){ new HallViewer("Example"); }
}
}
Code of MyDraggableSeat JLabel
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
public class MyDraggableSeat extends JLabel {
public MyDraggableSeat(int x, int y) {
setBorder(new LineBorder(Color.BLUE, 3));
setBackground(Color.WHITE);
setBounds(x, y, 30, 25);
setOpaque(true);
setHorizontalAlignment(JLabel.CENTER);
setVerticalAlignment(JLabel.CENTER);
}
}
The plan is to be able to select multiple JLabels like you select multiple files on your desktop (blue selection box) and to drag them around in the JFrame. I still want to be able to drag a single one if I choose to
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 am working on a simple panting project that allow the user to select a shape from ComboBox then draw it on the panel. Problem is when user choose any type of shapes and try to draw it on panel no shape appears.
here is my panel class
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class Shapes extends JPanel {
private MyLine[] lines = new MyLine[100];
private MyRectangle[] recs;
private MyOval[] ovals;
int ShapeType = 0;
int LC = 0;// conter for number of lines
int RC = 0;// conter for number of rectable
int OC = 0;// conter for number of ovals
int x1;
int y1;
int x2;
int y2;
Shapes() {
this.setBackground(Color.WHITE);
this.setBounds(0, 100, 300, 300);
MouseHandler handler = new MouseHandler();
this.addMouseListener(handler);
this.addMouseMotionListener(handler);
}
public int getShapeType() {
return ShapeType;
}
public void setShapeType(int ShapeType) {
this.ShapeType = ShapeType;
}
private class MouseHandler extends MouseAdapter implements
MouseMotionListener {
#Override
public void mouseClicked(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getX();
repaint();
System.out.println(x1 + " " + y1);
}
#Override
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getX();
lines[LC] = new MyLine(x1, y1, x2, y2);
LC++;
System.out.println(x2 + " " + y2);
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
x2 = e.getX();
y2 = e.getX();
System.out.println(x2 + " dragged " + y2);
repaint();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
if (ShapeType == 0) {
for (int i = 0; i < LC; i++) {
lines[i].draw(g);
}
}
if (ShapeType == 1) {
for (int i = 0; i < LC; i++) {
lines[i].draw(g);
}
}
if (ShapeType == 1) {
for (int i = 0; i < LC; i++) {
lines[i].draw(g);
}
}
}
}
MyLine Class
package painter;
import java.awt.Graphics;
import java.awt.Color;
public class MyLine extends MyShape {
MyLine(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.c = c;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.RED);
g.drawLine(500, 200, 300, 400);
}
}
Your panel is way too small: it's 300 by 300 pixels, but when you draw the line, you start it at (500,200) which is out of the bounds of your panel:
g.drawLine(500, 200, 300, 400);
Try drawing it closer to the upper-left corner:
g.drawLine(0, 0, 300, 400);
How to draw circle on mouse dragged event, and then how to move that circle on mouse dragged event in Java?
My code is below.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class r extends JPanel {
public int x1, x2, y1, y2, r, w, h,xDist,yDist;
public static boolean flag = false, pressFlag = false;
public r() {
setBackground(Color.WHITE);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent m) {
// pressFlag = true;
if (r > (int) Math.sqrt(Math.abs(m.getX() - x1) * Math.abs(m.getX() - x1) + Math.abs(m.getY() - y1) * Math.abs(m.getY() - y1))) {
flag = true;
yDist=xDist=x2 = y2 = 0;
} else {
x1 = y1 = 0;
r=x2 = y2 = 0;
x1 = m.getX();
y1 = m.getY();
}
repaint();
}
public void mouseReleased(MouseEvent m) {
w = x2 - x1;
h = y2 - y1;
r = (int) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
flag = false;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent m) {
if (flag && (x2!=0 && y2!=0)) {
xDist=(m.getX()-x2);
yDist=(m.getY()-y2);
}
x2 = m.getX();
y2 = m.getY();
repaint();
}
});
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (flag) {
x1=x1+xDist;
y1=y1+yDist;
g.drawOval(x1, y1, w, h);
} else {
g.drawOval(x1, y1, x2 - x1, y2 - y1);
}
}
}
public class q extends JFrame {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(300, 300);
jFrame.add(new r());
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Something along those lines works nicely for me:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
class DragCircle extends JPanel {
private final class MouseDrag extends MouseAdapter {
private boolean dragging = false;
private Point last;
#Override
public void mousePressed(MouseEvent m) {
last = m.getPoint();
dragging = isInsideEllipse(last);
if (!dragging) {
x = last.x;
y = last.y;
width = 0;
height = 0;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent m) {
last = null;
dragging = false;
repaint();
}
#Override
public void mouseDragged(MouseEvent m) {
int dx = m.getX() - last.x;
int dy = m.getY() - last.y;
if (dragging) {
x += dx;
y += dy;
} else {
width += dx;
height += dy;
}
last = m.getPoint();
repaint();
}
}
private int x;
private int y;
private int width;
private int height;
private MouseDrag mouseDrag;
public DragCircle() {
setBackground(Color.WHITE);
mouseDrag = new MouseDrag();
addMouseListener(mouseDrag);
addMouseMotionListener(mouseDrag);
}
public boolean isInsideEllipse(Point point) {
return new Ellipse2D.Float(x, y, width, height).contains(point);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, width, height);
}
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(300, 300);
jFrame.add(new DragCircle());
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}