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();
}
}
Related
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());
}
}
I am working on a project, develop a game called
Don't get mad bro.
I have a JPanel with shapes (circles) draw on it and JLabel components that contains images.I need that whenever I click "Throw dice" (which in background return a number between 1 and 6) I should wait for current player to click on one of his pawns, and that pawn should move after n positions, where n is equal with number that dice returned.
My question is, should I create a new thread in which I wait for mouseClick event? And how to get coordinates of mouseClick?
Here is my class that inherits panel and draw circles and add labels.
public class ImagePanel extends JPanel{
private static final long serialVersionUID = 1L;
ImageMatrix imageMatrix;
BufferedImage[] images;
public static JLabel[][] labels;
DrawGameBoard board = new DrawGameBoard();
List<GameFigure> gameCircles;
List<FinishFigure> finishCircles;
int initialHeight = 528;
int initialWidth = 596;
ThreadForPawnsClick labelsClick;
public ImagePanel(){
labels = new JLabel[4][4];
images = new BufferedImage[4];
setBackground(new Color(255,255,153));
gameCircles = new ArrayList<GameFigure>();
finishCircles = new ArrayList<FinishFigure>();
imageMatrix = new ImageMatrix(initialWidth,initialHeight);
try {
images[0] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\red.png"));
images[1] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\green.png"));
images[2] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\blue.png"));
images[3] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\yellow.png"));
} catch (IOException e) {
e.printStackTrace();
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
labels[i][j] = new JLabel(new ImageIcon(images[i]));
}
setLayout(null);
board.DrawHomeBoard(imageMatrix, labels);
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
add(labels[i][j]);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
int width = this.getWidth();
int height = this.getHeight();
imageMatrix.update(width, height);
setLayout(null);
gameCircles = board.DrawMainBoard(g, imageMatrix);
//labels = board.DrawHomeBoard(g, imageMatrix, labels);
//board.DrawHomeBoard(imageMatrix, labels);
finishCircles = board.DrawFinishBoard(g, imageMatrix);
/*for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
add(labels[i][j]);
*/
}
}
Also, why my imageMatrix doesn't extend on whole screen, even if I call update matrix in paintComponent()?
My question is, should I create a new thread in which I wait for mouseClick event?
No, absolutely not. You need instead to change the state of the GUI somehow to wait-for-mouse-click mode, and then alter the behavior of the GUI's response to mouse clicks depending on its state. Usually state is represented by instance fields of the class. So when you need to wait, you change one of these state fields, and on mouse click, you check the state of the field and vary what happens depending on that. For instance in a turn based game of chess, one state field could be private boolean blackTurn, and then base what mouse does based on its state.
And how to get coordinates of mouseClick?
In the MouseListener the MouseEvent parameter gives you the x and y position of the mouse relative to the listened to component and to the screen. If your MouseListener is attached to the JLabels, then you can get a reference to the clicked JLabel via the MouseEvent's getSource() method, and then can get the location of the JLabel relative to its container JPanel (if needed) by calling getLocation() on it.
Side note: in a Swing GUI where you're moving around sprites, it's usually better not to put the sprites into JLabels but rather to simply draw them directly in the paintComponent method of a drawing JPanel.
As an example of what I mean, here is a program that draws 4 colored circles, circles that are draggable, but only draggable when the corresponding JRadioButton has been selected with the JRadioButton setting the "state" of the GUI. Here the state is represented by an enum called ColorState that holds 4 colors and corresponding text. Here is this enum:
import java.awt.Color;
public enum ColorState {
RED("Red", Color.RED),
GREEN("Green", Color.GREEN),
BLUE("Blue", Color.BLUE),
ORANGE("Orange", Color.ORANGE);
private String text;
private Color color;
private ColorState(String text, Color color) {
this.text = text;
this.color = color;
}
public String getText() {
return text;
}
public Color getColor() {
return color;
}
}
Then we create a drawing JPanel, one that holds four Ellipse2D Shape objects in a Map,
private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);
Within a for loop, we create the JRadioButtons, give them ActionListeners that set the object's state, and populate the Map with Ellipse2D Shape objects
for (final ColorState state : ColorState.values()) {
// create the JRadioButton
JRadioButton radioButton = new JRadioButton(state.getText());
add(radioButton); // add to GUI
buttonGroup.add(radioButton); // add to ButtonGroup
// give it an ActionListener that changes the object's state
radioButton.addActionListener(e -> {
colorState = state;
});
// create a randomly placed Ellipse2D and place into Map:
double x = Math.random() * (W - CIRCLE_WIDTH);
double y = Math.random() * (H - CIRCLE_WIDTH);
Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
colorStateMap.put(state, ellipse);
}
We draw the ellipses within paintComponent:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// make for smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the enum, extracting the ellipse and drawing it
for (ColorState state : ColorState.values()) {
Shape shape = colorStateMap.get(state);
if (shape != null) {
g2.setColor(state.getColor());
g2.fill(shape); // draw the ellipse
}
}
}
Finally in a MouseAdapter (both MouseListener and MouseMotionListener), we listen for mouse presses and register success if the left mouse is clicked and if it is clicked within the appropriate Shape:
private class MyMouse extends MouseAdapter {
private Shape selectedShape = null;
private Point2D offset = null;
#Override
public void mousePressed(MouseEvent e) {
// check that correct button pressed
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// has our colorState been set yet? If not, exit
if (colorState == null) {
return;
}
// is an appropriate Shape held by the Map? If so, get it
Shape shape = colorStateMap.get(colorState);
if (shape == null) {
return;
}
// does this shape contain the point where the mouse was pressed?
if (!shape.contains(e.getPoint())) {
return;
}
// Get the selected shape, get the mouse point location relative to this shape
selectedShape = shape;
double x = e.getX() - shape.getBounds2D().getX();
double y = e.getY() - shape.getBounds2D().getY();
offset = new Point2D.Double(x, y);
}
#Override
public void mouseDragged(MouseEvent e) {
// drag shape to new location
if (selectedShape != null) {
double x = e.getX() - offset.getX();
double y = e.getY() - offset.getY();
Rectangle2D bounds = selectedShape.getBounds2D();
bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));
((Ellipse2D) selectedShape).setFrame(bounds);
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
}
Note that the mouse dragging code is thanks to MadProgrammer's answer here. Please up-vote this answer.
The entire class looks like so:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class StateDependentMouseListener extends JPanel {
private static final int W = 800;
private static final int H = 650;
private static final double CIRCLE_WIDTH = 60.0;
private ButtonGroup buttonGroup = new ButtonGroup();
private ColorState colorState = null;
private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);
public StateDependentMouseListener() {
setPreferredSize(new Dimension(W, H));
for (final ColorState state : ColorState.values()) {
// create the JRadioButton
JRadioButton radioButton = new JRadioButton(state.getText());
add(radioButton); // add to GUI
buttonGroup.add(radioButton); // add to ButtonGroup
// give it an ActionListener that changes the object's state
radioButton.addActionListener(e -> {
colorState = state;
});
// create a randomly placed Ellipse2D and place into Map:
double x = Math.random() * (W - CIRCLE_WIDTH);
double y = Math.random() * (H - CIRCLE_WIDTH);
Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
colorStateMap.put(state, ellipse);
}
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// make for smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the enum, extracting the ellipse and drawing it
for (ColorState state : ColorState.values()) {
Shape shape = colorStateMap.get(state);
if (shape != null) {
g2.setColor(state.getColor());
g2.fill(shape); // draw the ellipse
}
}
}
private class MyMouse extends MouseAdapter {
private Shape selectedShape = null;
private Point2D offset = null;
#Override
public void mousePressed(MouseEvent e) {
// check that correct button pressed
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// has our colorState been set yet? If not, exit
if (colorState == null) {
return;
}
// is an appropriate Shape held by the Map? If so, get it
Shape shape = colorStateMap.get(colorState);
if (shape == null) {
return;
}
// does this shape contain the point where the mouse was pressed?
if (!shape.contains(e.getPoint())) {
return;
}
// Get the selected shape, get the mouse point location relative to this shape
selectedShape = shape;
double x = e.getX() - shape.getBounds2D().getX();
double y = e.getY() - shape.getBounds2D().getY();
offset = new Point2D.Double(x, y);
}
#Override
public void mouseDragged(MouseEvent e) {
// drag shape to new location
if (selectedShape != null) {
double x = e.getX() - offset.getX();
double y = e.getY() - offset.getY();
Rectangle2D bounds = selectedShape.getBounds2D();
bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));
((Ellipse2D) selectedShape).setFrame(bounds);
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
}
private static void createAndShowGui() {
StateDependentMouseListener mainPanel = new StateDependentMouseListener();
JFrame frame = new JFrame("StateDependentMouseListener");
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());
}
}
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);
}
});
}
}
edit 2: I decided that it would be easier to understand if I just put the entire code up, so that you can test it.
edit: I realize that what I said was unclear, so I will explain this as best as I can. Basically, I am drawing rectangles on a Graphics page using the fillRect method. The problem is that when I change the size of one, they all change, as they are all being redrawn everytime a new one is drawn. To correct this, I added an array that stores all of the sizes which are input via the scrollwheel in another part of the problem. Anyways, I know that the problem is isolated to the loop that supposedly draws them all a certain size, so I added a loop that in theory should give me a temporary variable each time to use that redraws all of the rectangle's sizes starting at 0 each time the main loop is run. The problem is that this does not in fact redraw the rectangles to their individual sizes, and instead draws them to the current size. I have updated the code part as well.
I am having trouble with a project in Java. What it is supposed to do is change the size of each individual rectangle object by storing it in an array, and then recreating the rectangles based off the length from the array. I (at least I think) do this by creating a variable that should be equal to the SIZE that is changed in another part of the program, and then set that equal to the particular element in the array at i. Anyhow, when I do this, I change all of the lengths to whatever the current length is when I draw a rectangle. I know that the problem is by me using i in the size part, but what would I use? Thanks in advance for any help!
Here is the code:
public class Dots
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Array Rectangles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DotsPanel dotsPanel = new DotsPanel();
frame.getContentPane().add(dotsPanel);
//buttons
JButton btnNewButton = new JButton("RED");
btnNewButton.setHorizontalAlignment(SwingConstants.LEFT);
btnNewButton.setVerticalAlignment(SwingConstants.BOTTOM);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnNewButton.setForeground(Color.RED);
dotsPanel.add(btnNewButton);
JButton btnNewButton_1 = new JButton("GREEN");
btnNewButton_1.setForeground(Color.GREEN);
btnNewButton_1.setVerticalAlignment(SwingConstants.BOTTOM);
dotsPanel.add(btnNewButton_1);
JButton btnNewButton_2 = new JButton("BLUE");
btnNewButton_2.setForeground(Color.BLUE);
dotsPanel.add(btnNewButton_2);
JButton btnNewButton_3 = new JButton("BLACK");
btnNewButton_3.setForeground(new Color(0, 0, 0));
dotsPanel.add(btnNewButton_3);
frame.pack();
frame.setVisible(true);
}
}
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class DotsPanel extends JPanel
{
// radius of each dot
private int SIZE = 25;
private int SIZEAccess;
private static final Random generator = new Random();
//used to count amount of dots
private ArrayList<Point> pointList;
int[] sizes = new int [10000];
//Sets up this std. sized panel to listen for mouse events.
public DotsPanel()
{
pointList = new ArrayList<Point>();
addMouseListener (new DotsListener());
addMouseMotionListener(new DotsListener());
addMouseWheelListener(new DotsListener());
setBackground(Color.white);
setPreferredSize(new Dimension(1024, 768));
}
//used to generate a random color
public static Color randomColor() {
return new Color(generator.nextInt(256), generator.nextInt(256), generator.nextInt(256));
}
// Draws all of the dots stored in the list.
public void paintComponent(Graphics page)
{
super.paintComponent(page);
//draws a centered dot of random color
int i = 0;
for (Point spot : pointList)
{
sizes[i] = SIZE;
//SIZEAccess = SIZE;
//sizes[i] = SIZEAccess;
//page.fillRect(spot.x-SIZE, spot.y-SIZE, SIZE*2, SIZE*2);
for (int temp = 0; temp <= i; temp++)
page.fillRect(spot.x-sizes[temp], spot.y-sizes[temp], sizes[temp]*2, sizes[temp]*2);
//page.fillRect(spot.x-SIZE, spot.y-SIZE, SIZE*2, SIZE*2);
//page.setColor(randomColor());
//page.setColor(c)
i++;
}
//displays the amount of rectangles drawn at the top left of screen
page.drawString("Count: " + pointList.size(), 5, 15);
page.drawString("To change the size of the squares, use mouse scroll wheel.", 350, 15);
page.drawString("Size: " + SIZE, 950, 15);
}
// Represents the listener for mouse events.
private class DotsListener implements MouseListener, MouseMotionListener, MouseWheelListener
{
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is pressed.
public void mousePressed(MouseEvent event)
{
pointList.add(event.getPoint());
repaint();
}
// Provide empty definitions for unused event methods.
public void mouseClicked(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {
}
public void mouseExited(MouseEvent event) {}
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is dragged.
public void mouseDragged(MouseEvent event) {
pointList.add(event.getPoint());
repaint();
}
public void mouseMoved(MouseEvent event) {
}
public void mouseWheelMoved(MouseWheelEvent event)
{
int notches = 0;
notches = event.getWheelRotation();
//int
if (notches > 0)
{
SIZE = SIZE + notches;
notches = 0;
}
else if (notches < 0)
{
int tempSIZE = SIZE;
tempSIZE = tempSIZE + notches;
//prevents the program from having dots that increase due to multiplying negatives by negatives
//by making anything less than 1 equal 1
if(tempSIZE < 1)
tempSIZE = 1;
SIZE = tempSIZE;
notches = 0;
}
}
}
//SIZE = SIZE + notches;
}
You appear to have ArrayList's interacting with arrays in a confusing mix that makes it hard for us to follow your logic. This suggests that your logic may be too complex for your own good and that your code might benefit from simplification. Why not instead create a List<Rectangle> such as an ArrayList<Rectangle>, and then simply loop through this list in your paintComponent method, and draw each Rectangle using the Graphics2D object's draw(...) or fill(...) method:
private List<Rectangle> rectangleList = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle rectangle : rectangleList) {
g2.fill(rectangle);
}
}
For example:
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 java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Color BACKGROUND = Color.black;
private static final Color FILL_COLOR = Color.pink;
private static final Color DRAW_COLOR = Color.red;
private static final Stroke STROKE = new BasicStroke(3);
private List<Rectangle> rectangleList = new ArrayList<>();
private Point pressPoint = null;
private Point dragPoint = null;
public Foo() {
setBackground(BACKGROUND);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Stroke oldStroke = g2.getStroke();
g2.setStroke(STROKE);
for (Rectangle rectangle : rectangleList) {
g2.setColor(FILL_COLOR);
g2.fill(rectangle);
g2.setColor(DRAW_COLOR);
g2.draw(rectangle);
}
g2.setStroke(oldStroke);
if (pressPoint != null && dragPoint != null) {
g2.setColor(FILL_COLOR.darker());
int x = Math.min(pressPoint.x, dragPoint.x);
int y = Math.min(pressPoint.y, dragPoint.y);
int width = Math.abs(pressPoint.x - dragPoint.x);
int height = Math.abs(pressPoint.y - dragPoint.y);
g2.drawRect(x, y, width, height);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
pressPoint = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
dragPoint = e.getPoint();
int x = Math.min(pressPoint.x, dragPoint.x);
int y = Math.min(pressPoint.y, dragPoint.y);
int width = Math.abs(pressPoint.x - dragPoint.x);
int height = Math.abs(pressPoint.y - dragPoint.y);
Rectangle rect = new Rectangle(x, y, width, height);
rectangleList.add(rect);
pressPoint = null;
dragPoint = null;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Foo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}