I want to accomplish something very similar to the image a Rectangle whit a Selector Line.
Basically, I have a Rectangle and I want to have a selector line all around it.
For that, I wanted to create an additional JComponent.
At the moment I can only draw the Rectangle. How could I get the parentPanel JPanel inside the Rectangle class, so that I could add the selector?
public class TestPanel extends JFrame {
public class Rectangle extends JComponent {
public Rectangle(){
setBounds(x1, y1, x2, y2);
JPanel Selector = new JPanel();
//Adds Selector to parentPanel within Rectangle
//setBounds(x1-1, y1-1, x2+1, y2+1)
//!Problem parent is initially null! cant even a use property
//Life hacks?
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, getWidth(), getHeight());
}
}
public TestPanel() {
Rectangle Rectangle = new Rectangle();
JPanel parentFrame = new JPanel();
parentFrame.add(Rectangle);
setSize(200, 200);
setVisible(true);
}
public static void main(String[] args) {
new TestPanel();
}
}
If I try to add the selector inside the rectangle, it will get out of the drawing area. If I resize the drawing area, it won't be scalable for later development.
If possible I would avoid dual binding like:
public TestPanel() {
Rectangle Rectangle = new Rectangle();
JPanel parentPanel = new JPanel();
parentPanel.add(Rectangle);
Rectangle.addParent(parentPanel)
...
}
Again, I'm not 100% clear on what you're trying to achieve. If what you wish to create is a user-created dashed line, one that can change with mouse press/drag/release, then you don't need to create a new component but rather use a MouseAdapter as a MouseListener and MouseMotionListener, all to help you create the Rectangle, and then simply draw the Rectangle with a dashed line using an appropriate Stroke, as per this answer.
For example, something like would create a dashed line that is user-selectable:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class SelectorPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Stroke DASHED_STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 5 }, 0);
private static final Color DASHED_COLOR = Color.LIGHT_GRAY;
private Rectangle rectangle = null;
public SelectorPanel() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
private class MyMouse extends MouseAdapter {
private Point p1 = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
rectangle = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (p1 != null) {
createRectangle(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p1 != null) {
createRectangle(e);
p1 = null;
}
}
private void createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int width = Math.abs(p1.x - p2.x);
int height = Math.abs(p1.y - p2.y);
rectangle = new Rectangle(x, y, width, height);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rectangle != null) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(DASHED_COLOR);
g2.setStroke(DASHED_STROKE);
g2.draw(rectangle);
g2.dispose();
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
SelectorPanel mainPanel = new SelectorPanel();
JFrame frame = new JFrame("SelectorPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Related
I am attempting to use jsliders to allow a user to pinpoint the origin of a circle to be drawn on a canvas. I am using a button to show and hide the circle. I am using paint on an inner jpanel so that paint will not write over components. However, the coordinates inside the jpanel are different than the coordinates for the entire frame. So, it is very difficult for me to get the coordinates of the jslider and then translate it to the jpanel to draw the circle. Is there an easy way to figure this out without a ton of guess and check? I am also using the custom layout miglayout. I have included the code for my GUI class as well as my custom JPanel I made so I could mess with the paint method.
public class CircleGUI extends JFrame implements ActionListener {
private MigLayout layout = new MigLayout();
private CustomPanel innerpanel;
private JSlider x,y;
private JColorChooser colorpick;
private JButton state;
private boolean bstate;
CircleGUI() {
initialize();
}
private void initialize() {
Border blackline = BorderFactory.createLineBorder(Color.black);
bstate = false;
x = new JSlider(JSlider.HORIZONTAL,650,325);
x.setPaintTicks(true);
x.setPaintLabels(true);
x.setPreferredSize(new Dimension(650,0));
y = new JSlider(JSlider.HORIZONTAL,650,325);
y.setPaintTicks(true);
y.setPaintLabels(true);
y.setInverted(true);
y.setOrientation(JSlider.VERTICAL);
y.setPreferredSize(new Dimension (0,600));
colorpick = new JColorChooser();
state = new JButton("Show");
state.addActionListener(e -> {
if(!bstate) {
int positionx = x.getValue() - 80;
int positiony = y.getValue();
Color c = colorpick.getColor();
innerpanel.setColor(c);
innerpanel.setX(positionx);
innerpanel.setY(positiony);
innerpanel.repaint();
state.setText("Hide");
bstate = true;
} else {
Color transparent = new Color(0,0,0,0);
innerpanel.setColor(transparent);
innerpanel.repaint();
state.setText("Show");
bstate = false;
}
});
JPanel outerpanel = new JPanel(layout);
innerpanel = new CustomPanel();
innerpanel.setPreferredSize(new Dimension(600,600));
innerpanel.setBorder(blackline);
outerpanel.add(x,"wrap");
outerpanel.add(y,"split 2");
outerpanel.add(innerpanel);
outerpanel.add(state,"wrap");
outerpanel.add(colorpick);
this.setSize(1000, 1000);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(outerpanel);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
public class CustomPanel extends JPanel implements ActionListener {
private Color c;
private int x;
private int y;
public CustomPanel() {
c = null;
}
#Override
public void actionPerformed (ActionEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(c);
g2.fill(new Ellipse2D.Double(x, y, 100, 100));
}
public void setColor(Color c) {
this.c = c;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
Your problem is you are trying to make a one-to-one mapping between the value of the JSlider and the coordinate in your CustomPanel. You should use the JSlider value as a percentage, i.e. minimum value zero and maximum value 100. If you want the circle to appear in the middle of the CustomPanel so you place both JSliders in their mid-points, i.e. both at 50%. Then you calculate 50% of the corresponding dimension to get the coordinate. If the width of CustomPanel is 600, then 50% of 600 is 300 so positionx needs to be 300.
The only thing I changed in your code is the calculation of positionx and positiony.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.border.Border;
import net.miginfocom.swing.MigLayout;
public class CircleGUI extends JFrame implements ActionListener {
private MigLayout layout = new MigLayout();
private CustomPanel innerpanel;
private JSlider x,y;
private JColorChooser colorpick;
private JButton state;
private boolean bstate;
CircleGUI() {
initialize();
}
private void initialize() {
Border blackline = BorderFactory.createLineBorder(Color.black);
bstate = false;
// x = new JSlider(JSlider.HORIZONTAL, 650, 325);
x = new JSlider(0, 100, 10);
x.setPaintTicks(true);
x.setPaintLabels(true);
x.setPreferredSize(new Dimension(650, 0));
// y = new JSlider(JSlider.HORIZONTAL, 650, 325);
y = new JSlider(0, 100, 10);
y.setPaintTicks(true);
y.setPaintLabels(true);
y.setInverted(true);
y.setOrientation(JSlider.VERTICAL);
y.setPreferredSize(new Dimension(0, 600));
colorpick = new JColorChooser();
state = new JButton("Show");
state.addActionListener(e -> {
if (!bstate) {
int positionx = Math.round(x.getValue() / 100.0f * innerpanel.getSize().width) - 50;
int positiony = Math.round(y.getValue() / 100.0f * innerpanel.getSize().height) - 50;
Color c = colorpick.getColor();
innerpanel.setColor(c);
innerpanel.setX(positionx);
innerpanel.setY(positiony);
innerpanel.repaint();
state.setText("Hide");
bstate = true;
}
else {
Color transparent = new Color(0, 0, 0, 0);
innerpanel.setColor(transparent);
innerpanel.repaint();
state.setText("Show");
bstate = false;
}
});
JPanel outerpanel = new JPanel(layout);
innerpanel = new CustomPanel();
innerpanel.setPreferredSize(new Dimension(600, 600));
innerpanel.setBorder(blackline);
outerpanel.add(x, "wrap");
outerpanel.add(y, "split 2");
outerpanel.add(innerpanel);
outerpanel.add(state, "wrap");
outerpanel.add(colorpick);
this.setSize(1000, 1000);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(outerpanel);
}
#Override
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
CircleGUI cg = new CircleGUI();
cg.setVisible(true);
});
}
}
class CustomPanel extends JPanel implements ActionListener {
private Color c;
private int x;
private int y;
public CustomPanel() {
c = null;
}
#Override
public void actionPerformed(ActionEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(c);
g2.fill(new Ellipse2D.Double(x, y, 100, 100));
}
public void setColor(Color c) {
this.c = c;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
I want to add a Panel (which is on other panel) on mouse position. When I add now, panel's location is next to previous panel.
jPanel1.setLayout(new FlowLayout());
JPanel newPanel = new JPanel();
newPanel.setBackground(Color.red);
jPanel1.add(newPanel);
newPanel.setLocation(300,300);
jPanel1.revalidate();
jPanel1.repaint();
Point point = newPanel.getLocation();
int x = point.x;
int y = point.y;
newPanel.setLocation(x+5,y+5);
If you need to place a Swing component in a random position, then you will need a layout manager that would allow this, and FlowLayout, along with most standard managers, won't. The most common one to use is the simplest -- a null layout, e.g., someJPanel.setLayout(null); -- that is complete absence of a layout manager, but this comes with its own host of troubles, and so I try to avoid use of these as much as possible.
If your goal however is to move a red square, then best to keep things as simple as possible, and instead of creating and moving a JPanel, create and move something much lighter in weight, a Rectangle.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class MovingRect extends JPanel {
private static final long serialVersionUID = 1L;
private static final Color RECT_COLOR = Color.RED;
private static final int RECT_W = 300;
private Rectangle rect = new Rectangle(0, 0, RECT_W, RECT_W);
public MovingRect() {
setPreferredSize(new Dimension(800, 650));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
((Graphics2D) g).fill(rect);
}
private class MyMouse extends MouseAdapter {
private Point p0;
private Point pRect;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
if (rect.contains(e.getPoint())) {
p0 = e.getPoint();
pRect = rect.getLocation();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
drag(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
drag(e);
p0 = null;
}
}
private void drag(MouseEvent e) {
// use simple geometry to move the rectangle
Point p1 = e.getPoint();
int x = p1.x - p0.x + pRect.x;
int y = p1.y - p0.y + pRect.y;
rect = new Rectangle(x, y, RECT_W, RECT_W);
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
MovingRect mainPanel = new MovingRect();
JFrame frame = new JFrame("Moving Rectangle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Code explanation
The rectangle to draw, initially placed at 0, 0:
private Rectangle rect = new Rectangle(0, 0, RECT_W, RECT_W);
In the constructor, set the drawing JPanel's preferred size, and create our mouse listener (actually a MouseAdapter) that will move the rectangle, and add the MouseAdapter as a MouseListener and MouseMotionListener to our drawing (main) JPanel:
public MovingRect() {
setPreferredSize(new Dimension(800, 650));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
Draw the rectangle within this JPanel's paintComponent method after doing clean-up painting by calling the super's method:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
((Graphics2D) g).fill(rect);
}
The mouse adapater that does the moving. It uses simple geometry of vector addition to calculate where to move
private class MyMouse extends MouseAdapter {
private Point p0;
private Point pRect;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
// if not button 1, then get out of here
return;
}
if (rect.contains(e.getPoint())) {
// get the first point of the mouse press and the rectangle's first position
p0 = e.getPoint();
pRect = rect.getLocation();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
drag(e);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
drag(e);
p0 = null; // set the first pressed point to null -- stop the listener
}
}
private void drag(MouseEvent e) {
// use simple geometry to move the rectangle
Point p1 = e.getPoint();
int x = p1.x - p0.x + pRect.x;
int y = p1.y - p0.y + pRect.y;
// create a new Rectangle with the position calculated above
rect = new Rectangle(x, y, RECT_W, RECT_W);
// ask Java to repaint the main JPanel
repaint();
}
}
This illustrates my problem
Im trying to copy a paint like program but whenever I click on the screen the menu bar is displayed in the panel area. It doesn't do it unless I click on the screen (to draw). The menu bar is added before the panel, any help would be much appreciated.
public class Main {
public static Frame frame;
public static Panel panel;
public static MenuBar menubar;
public static void main(String[] args) {
frame = new Frame();
panel = new Panel();
menubar = new MenuBar();
frame.setJMenuBar(menubar);
frame.addMouseMotionListener(panel);
frame.add(panel);
frame.setVisible(true);
}
}
public class Frame extends JFrame {
public Frame() {
setTitle("Paint");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
public class Panel extends JPanel implements MouseMotionListener {
public boolean isMouseDown = false;
public int x1,y1, x2, y2;
public Color colour = Color.BLACK;
public int size = 3;
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(colour);
g2.setStroke(new BasicStroke(size));
g2.drawLine(x1 - 10, y1 - 80, x2 - 10, y2 - 80);
}
public void mouseDragged(MouseEvent arg0) {
x1 = x2;
y1 = y2;
x2 = arg0.getX();
y2 = arg0.getY();
repaint();
}
public void mouseMoved(MouseEvent arg0) {
x1 = x2;
y1 = y2;
x2 = arg0.getX();
y2 = arg0.getY();
}
public void mouseClicked(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
}
public class MenuBar extends JMenuBar {
JMenu file = new JMenu("File");
JMenu brush = new JMenu("Pen");
JMenu colour = new JMenu("Colour");
Font font = new Font("Times New Romans", Font.PLAIN, 18);
public MenuBar() {
//JMenuBar Code here, left black as very long
}
}
One problems: You need to call super.paintComponent(g); within your paintComponent method. Else the JPanel cannot do its house-keeping painting of its own self.
If you want the drawings to persist, then either create an ArrayList of lines that are then drawn within paintComponent in a for loop, or better, paint onto a BufferedImage which is then displayed within the paintComponent method.
e.g.,
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyMain {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
MyPainting mainPanel = new MyPainting();
MenuCreator menuCreator = new MenuCreator(mainPanel);
JFrame frame = new JFrame("MyPainting");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.setJMenuBar(menuCreator.getMenubar());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
#SuppressWarnings("serial")
class MyPainting extends JPanel {
private static final int IMG_W = 600;
private static final int IMG_H = 450;
private static final int STROKE_W = 3;
private static final Stroke STROKE = new BasicStroke(STROKE_W);
private BufferedImage img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
private Color drawColor = Color.BLACK;
public MyPainting() {
setPreferredSize(new Dimension(IMG_W, IMG_H));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
private class MyMouse extends MouseAdapter {
private Graphics2D g2 = null;
private Point p0;
#Override
public void mousePressed(MouseEvent e) {
if (img == null) {
return;
}
g2 = img.createGraphics();
g2.setStroke(STROKE);
g2.setColor(drawColor);
p0 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 == null) {
return;
}
drawLine(e);
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 == null) {
return;
}
drawLine(e);
g2.dispose();
p0 = null;
}
private void drawLine(MouseEvent e) {
Point p1 = e.getPoint();
g2.drawLine(p0.x, p0.y, p1.x, p1.y);
repaint();
p0 = p1;
}
}
public void setDrawColor(Color drawColor) {
this.drawColor = drawColor;
}
public void clear() {
img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
repaint();
}
}
class MenuCreator {
private JMenuBar menubar = new JMenuBar();
private MyPainting myPainting;
public MenuCreator(MyPainting myPainting) {
JMenuItem clearDrawing = new JMenuItem(new AbstractAction("Clear Drawing") {
#Override
public void actionPerformed(ActionEvent arg0) {
if (myPainting != null) {
myPainting.clear();
}
}
});
JMenu fileMenu = new JMenu("File");
fileMenu.add(clearDrawing);
JMenu colourMenu = new JMenu("Colour");
for (MyColor myColor : MyColor.values()) {
colourMenu.add(new JMenuItem(new ColorAction(myColor)));
}
menubar.add(fileMenu);
menubar.add(new JMenu("Pen"));
menubar.add(colourMenu);
this.myPainting = myPainting;
}
public JMenuBar getMenubar() {
return menubar;
}
private class ColorAction extends AbstractAction {
private MyColor myColor;
public ColorAction(MyColor myColor) {
super(myColor.getText());
this.myColor = myColor;
}
#Override
public void actionPerformed(ActionEvent e) {
if (myPainting != null) {
myPainting.setDrawColor(myColor.getColor());
}
}
}
}
enum MyColor {
BLACK("Black", Color.BLACK), RED("Red", Color.RED), ORANGE("Orange", Color.ORANGE), BLUE("Blue", Color.BLUE);
private String text;
private Color color;
private MyColor(String text, Color color) {
this.text = text;
this.color = color;
}
public String getText() {
return text;
}
public Color getColor() {
return color;
}
}
You failed to honour the requirements of the paint chain...
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(colour);
g2.setStroke(new BasicStroke(size));
g2.drawLine(x1 - 10, y1 - 80, x2 - 10, y2 - 80);
}
Apart from not needing to be public, one of the jobs of paintComponent is to prepare the Graphics context for painting. So, one of the first things you should do is call super.paintComponent before you do any custom painting.
protected void paintComponent(Graphics g) {
super. paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(colour);
g2.setStroke(new BasicStroke(size));
g2.drawLine(x1 - 10, y1 - 80, x2 - 10, y2 - 80);
}
Graphics is a shared context, it is shared amongst the other components which need to be painted, so it is very important that you ensure that it's properly prepared before you paint to it.
It's also important that any significant modifications you make to the context (like transformations or rendering hints) are reversed before the method exists
I would recommend taking a look at Performing Custom Painting and Painting in Swing to gain a better understanding into how the painting system actually works
I'm trying to draw multiple rectangles on a panel. I created an ArrayList<Shape> and initialized in my constructor. In my paintComponent method, I draw a rectangle and then add it to the ArrayList. But when I do that, the drawing outcome on my panel turns out weird. As I drag to draw my first rectangle, I get this:
Here's part of my code:
public class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(final MouseEvent theEvent) {
myStartPoint = theEvent.getPoint();
repaint();
}
#Override
public void mouseReleased(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
public class MyMouseMotionHandler extends MouseMotionAdapter {
#Override
public void mouseDragged(final MouseEvent theEvent) {
myEndPoint = theEvent.getPoint();
repaint();
}
}
/**
* Paints some rectangles.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
// for better graphics display
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(new Color(51, 0, 111));
g2d.setStroke(new BasicStroke(3));
final double x = myStartPoint.getX();
final double y = myStartPoint.getY();
final double xEnd = myEndPoint.getX();
final double yEnd = myEndPoint.getY();
if (xEnd> x && yEnd > y) {
final Shape rectangle = new Rectangle2D.
Double(x, y, xEnd - x, yEnd - y);
g2d.draw(rectangle);
myDrawings.add(rectangle);
}
for (Shape s : myDrawings) {
g2d.draw(s);
}
}
Don't do any code logic within paintComponent -- that method is for drawing and drawing only, and that is the source of your bug. Add the rectangle to the ArrayList in the mouse listener, on mouse release.
When I have done a similar project, I usually have one Rectangle field that I use to draw with the mouse listener on mouse drag, and which is draw within paintComponent. Then on mouse release I place that rectangle into the ArrayList, and set the class field as null.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class RectangleDraw extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color TEMP_RECT_COLOR = Color.LIGHT_GRAY;
private static final Color SHAPE_COLOR = Color.RED;
private Rectangle tempRect = null;
private List<Shape> shapes = new ArrayList<>();
public RectangleDraw() {
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw the temporary rectangle if not null
if (tempRect != null) {
g2.setColor(TEMP_RECT_COLOR);
g2.draw(tempRect);
}
// draw all the rectangles in the list
g2.setColor(SHAPE_COLOR);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
// size the GUI to my specification
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
// My mouse listener and mouse motion listener
private class MyMouse extends MouseAdapter {
private Point p1; // start point
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
// create temporary rectangle
tempRect = createRectangle(e);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempRect = null; // null temp rectangle and
// add rectangle to List
shapes.add(createRectangle(e));
repaint();
}
// create a rectangle from start point and current point
private Rectangle createRectangle(MouseEvent e) {
Point p2 = e.getPoint();
int x = Math.min(p1.x, p2.x);
int y = Math.min(p1.y, p2.y);
int w = Math.abs(p1.x - p2.x);
int h = Math.abs(p1.y - p2.y);
Rectangle rect = new Rectangle(x, y, w, h);
return rect;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Rectangle Draw");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RectangleDraw());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This code is for drawing on a JPanel. In the paintComponent(Graphics) I am trying to draw curves via repeated Graphics2D#fillOval(x, y, with, height).
The app is working OK, and when I drag the mouse cursor slowly; it draws a continuous curve as I need. But when I speed up dragging the mouse cursor, the result is separated dots and not a continuous curve.
So how to make it draw a continuous curve even if I speed up dragging?
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Painter extends JPanel {
int x, y;
ArrayList<Point> points;
public Painter() {
setBackground(Color.white);
points = new ArrayList<>();
MouseHandler listener = new MouseHandler();
this.addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
points.add(point);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Point point : points) {
g2d.fillOval(point.x, point.y, 15, 15);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
As mentioned in comment to your previous similar question:
Don't draw discrete ovals in your paintComponent method.
Instead connect the points hold in the List in the paintComponent by drawing lines between adjacent points.
If you need to make the line thicker, change the Stroke property of the Graphics2D object, using one that has a wider thickness.
Be careful with Strokes however since often you don't want the property change to propagate down the paint chain. This means that sometimes you will want to copy the Graphics object and set the Stroke on the new Graphics object and paint with that, then dispose of it.
The simplest way to create a Stroke is to use the BasicStroke class, e.g., new BasicStroke(6f) will get you a nice thick curve.
For example:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Painter2 extends JPanel {
private static final float STROKE_WIDTH = 15f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
int x, y;
ArrayList<Point> points;
public Painter2() {
setBackground(Color.white);
points = new ArrayList<>();
MouseHandler listener = new MouseHandler();
this.addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
Point point = new Point(e.getX(), e.getY());
points.add(point);
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(STROKE);
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);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter2());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
Or better still:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Painter2 extends JPanel {
private static final float STROKE_WIDTH = 15f;
private static final Stroke STROKE = new BasicStroke(STROKE_WIDTH, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
private static final Color CURVES_COLOR = Color.BLUE;
private static final Color TEMP_CURVE_COLOR = Color.PINK;
private List<List<Point>> curvesList = new ArrayList<>();
private List<Point> tempCurve = null;
public Painter2() {
setBackground(Color.white);
MouseHandler listener = new MouseHandler();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mousePressed(MouseEvent e) {
tempCurve = new ArrayList<>();
tempCurve.add(e.getPoint());
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
tempCurve.add(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
tempCurve.add(e.getPoint());
curvesList.add(tempCurve);
tempCurve = null;
repaint();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(STROKE);
g2.setColor(CURVES_COLOR);
for (List<Point> curve : curvesList) {
drawCurve(g2, curve);
}
if (tempCurve != null) {
g2.setColor(TEMP_CURVE_COLOR);
drawCurve(g2, tempCurve);
}
g2.dispose();
}
private void drawCurve(Graphics2D g2, List<Point> ptList) {
for (int i = 1; i < ptList.size(); i++) {
int x1 = ptList.get(i - 1).x;
int y1 = ptList.get(i - 1).y;
int x2 = ptList.get(i).x;
int y2 = ptList.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setContentPane(new Painter2());
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}