public void mouseEntered(MouseEvent e) {
int x = e.getX();
int y = e.getY();
m_View = new View(m_Mod);
int maxY = m_Mod.y1 + m_Mod.oheight;
int maxX = m_Mod.x1 + m_Mod.owidth;
if (x > m_Mod.x1 & x < maxX & y > m_Mod.y1 & x < maxY) {
Graphics g = m_Mod.frame.getGraphics();
m_View.draw(g);
System.out.print("IM KREIS");
}
}
Somehow my math does not work here. I want to redraw my oval as soon as the mouse enters it. So my graphics object "g" is my oval here. m_Mod.x1 / M_Mod.y1 is x and y of my oval and m_Mod.width / m_Mod.heigth are width and heigth of my oval.
As mentioned in comments, the key to a solution is to:
Do all drawing, all graphics and mouse listening within a single drawing JPanel
To specifically draw within the JPanel's paintComponent method override
To give your GUI a boolean field that is set to true
To use an Ellipse2D object to define your oval
To add a MouseMotionListener to the drawing JPanel
Within this MouseMotionListener, check if the mouse point is within the ellipse
Then set the boolean field with this result and call repaint()
The paintComponent method will then determine what to draw based on the state of the boolean
For example, in the code below I have an Ellise2D field,
private Ellipse2D myOval = new Ellipse2D.Double(OVAL_X, OVAL_Y, OVAL_W, OVAL_H);
Then there is a boolean field, private boolean insideOval = false; that is set to false and that is changed within a MouseMotionListener to true if the mouse point is within the ellpise (here called myOval):
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
// true if the mouse point is within the oval. Otherwise false
insideOval = myOval.contains(e.getPoint());
// redraw the JPanel to draw the state of insideOval
repaint();
}
});
Then the paintComponent method will use the state of insideOval to determine what color to fill the oval with, an "active color" if the boolean is true and a clear color if not:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // does house-keeping drawing
Graphics2D g2 = (Graphics2D)g;
// allow for smooth curves
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// vary the oval fill color depending on the state of the insideOval field
Color c = insideOval ? ACTIVE_COLOR : INACTIVE_COLOR;
g2.setColor(c);
// fill the oval
g2.fill(myOval);
// then draw the oval's border
g2.setColor(OVAL_BORDER);
g2.setStroke(BORDER_STROKE);
g2.draw(myOval);
}
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.RenderingHints;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class DrawingPanel extends JPanel {
// main JPanel dimensions
private static final int PREF_W = 600;
private static final int PREF_H = 600;
// oval dimensions
private static final double OVAL_X = 100;
private static final double OVAL_Y = OVAL_X;
private static final double OVAL_W = 400;
private static final double OVAL_H = OVAL_W;
// oval colors
private static final Color INACTIVE_COLOR = new Color(0, 0, 0, 0); // clear
private static final Color ACTIVE_COLOR = Color.PINK;
private static final Color OVAL_BORDER = Color.LIGHT_GRAY;
// thickness of mouse border
private static final Stroke BORDER_STROKE = new BasicStroke(4f);
// Oval to draw and boolean to tell if mouse within the oval
private Ellipse2D myOval = new Ellipse2D.Double(OVAL_X, OVAL_Y, OVAL_W, OVAL_H);
private boolean insideOval = false;
public DrawingPanel() {
// add a mouse motion listener to this same drawing JPanel
// and inside of it, check if the mouse point is inside or outside
// of the oval.
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
// true if the mouse point is within the oval. Otherwise false
insideOval = myOval.contains(e.getPoint());
// redraw the JPanel to draw the state of insideOval
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // does house-keeping drawing
Graphics2D g2 = (Graphics2D)g;
// allow for smooth curves
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// vary the oval fill color depending on the state of the insideOval field
Color c = insideOval ? ACTIVE_COLOR : INACTIVE_COLOR;
g2.setColor(c);
// fill the oval
g2.fill(myOval);
// then draw the oval's border
g2.setColor(OVAL_BORDER);
g2.setStroke(BORDER_STROKE);
g2.draw(myOval);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
DrawingPanel mainPanel = new DrawingPanel();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Related
package com.company;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayDeque;
import java.util.Random;
public class REcom {
REcom() {
JFrame jfm = new JFrame("Paint");
jfm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
BorderLayout border = new BorderLayout();
border.setVgap(10);
jfm.setLayout(border);
DrawPanel dw = new DrawPanel();
dw.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
dw.setXY(e.getX() , e.getY());
dw.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
dw.previosPosition = new Position(e.getX() , e.getY());
}
});
jfm.add(dw ,BorderLayout.CENTER);
jfm.setBackground(Color.white);
jfm.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
jfm.setSize(500 ,500);
JPanel color = new JPanel(new FlowLayout(FlowLayout.LEFT));
//that Jpanel background is doubled
// color.setBounds(new Rectangle(0 ,0 , 100 , jfm.getHeight()));
Button blue = new Button();
blue.setBackground(Color.blue);
blue.setSize(500 ,200);
blue.addActionListener(e -> {
dw.color = Color.blue;
});
color.add(blue);
Button white = new Button();
white.setBackground(Color.white);
white.setSize(200 ,200);
white.addActionListener(e -> {
dw.color = Color.white;
});
color.add(white);
jfm.add(color , BorderLayout.NORTH);
jfm.setPreferredSize(new Dimension(500 ,500));
jfm.pack();
color.setBackground(Color.blue);
jfm.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(REcom::new);
}
}
class DrawPanel extends JPanel {
ArrayDeque<Position> ad = new ArrayDeque<>();
Position previosPosition = null;
Color color = Color.yellow;
void setXY(int x , int y) {
ad.push(new Position(x , y));
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(color);
g2.setStroke(new BasicStroke(12f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
Position d = ad.pollLast();
if(d != null) {
if(previosPosition == null)
g2.fillOval(d.x, d.y -10 , d.x , d.y-10);
else{
g2.drawLine(previosPosition.x -5 , previosPosition.y -10 , d.x-5 , d.y-10);
}
previosPosition = d;
}
}
}
class Position {
int x, y;
Position(int x, int y) {
this.x= x;
this.y = y;
}
void setXY(int x , int y) {
this.x = x;
this.y = y;
}
}
about code: two panels, one intended for drawing, another for the switch between colors. I decided to add the switcher to the top in frame. But its background move to the bottom and I can draw on it.(therefore its background out of border). and if I will set a border for central JPanel its panel (for drawing), top of the border is doubled
I wanted to add Jpanel to the top for switch between colors (background is doubled after drawing anything )for drawing. But the top Jpanel background is doubled. But if I will replace Jpanel (color) by the common panel, the program work normally. I don't know why? Please help! if you don't understand please try run code (this question I wrote with translater)
JPanel background is doubled
When you do custom painting, the first statement in your method should be:
super.paintComponent(g);
to clear the background otherwise you can have painting artifacts, which is why you see the two blue lines.
Of course when you do add the super.paintComponent(g) the painting disappears because the background is cleared.
The are two solutions to the problem:
keep an ArrayList of object to paint and the iterate through the ArrayList in the paintComponent() method to paint all the objects
paint to a BufferedImage, then just draw the entire image.
I would suggest that option 2 might be the best in this case.
Check out Custom Painting Approaches for more information and examples of each approach.
I had an assignment about making painting circles on a JComponent when I click on it and that if you click on an existing circle, it will print a message. Everything works fine, except that the first circle that I draw will have a black border when the following ones wont.
I think it has to do with the repaint method but I cant seems to find what is going on.
import javax.swing.*;
import java.awt.*;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
public class GraphComponent extends JComponent {
private int defaultWidth = 500;
private int defaultHeight = 500;
protected Point spot;
protected int width = 50;
protected int height = 50;
private ArrayList<Ellipse2D> shapeList = new ArrayList();
public GraphComponent() {
super();
this.setPreferredSize(new Dimension(defaultWidth,defaultHeight));
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
boolean contains = false;
spot = e.getPoint();
for (Shape shape : shapeList) {
if (shape.contains(spot)) {
System.out.println("WIN");
System.out.println();
contains = true;
break;
}
}
System.out.println();
System.out.println(shapeList.contains(spot));
if(contains == false){
shapeList.add(new Ellipse2D.Double(spot.x - width / 2,
spot.y - width / 2, width, height));
}
repaint();
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
//moveSquare(e.getX(),e.getY());
}
});
}
public void paintComponent(Graphics gfx) {
super.paintComponents(gfx);
for (Ellipse2D shape : shapeList) {
gfx.drawOval((int)shape.getX(), (int)shape.getY(),width,height);
gfx.setColor(Color.YELLOW);
gfx.fillOval((int)shape.getX(), (int)shape.getY(),width,height);
}
}
}
I expect all the circles to look the same, yet the first created has black borders
You are using a unique Graphics object, so the first call (from the first iteration) to drawOval will paint with the default Graphics 's color, which is black .
Next iterations will all paint in yellow .
for (Ellipse2D shape : shapeList) {
gfx.drawOval((int)shape.getX(), (int)shape.getY(),width,height);// BLACK (at first iteration, YELLOW for next ones)
gfx.setColor(Color.YELLOW);// YELLOW (from now on)
gfx.fillOval((int)shape.getX(), (int)shape.getY(),width,height);
}
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());
}
}
The code is meant to draw a rectangle, which moves in a circle around the center of the canvas one time. The code I currently have is
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.Timer;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Q3_Circular extends JComponent {
protected int degree = 0;
protected double xStart;
protected double yStart;
protected Timer timer;
public Q3_Circular() {
timer = new Timer(1000, new TimerCallback()); //creates new times that refreshes every 100 ms, and called the TimerCallback class
timer.start();
}
protected class TimerCallback implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (degree < (2 * Math.PI)){
xStart = getWidth()/2 * Math.cos(degree+1);
yStart = getHeight()/2 * Math.sin(degree+1);
degree+= 1;
repaint();
}
else {
degree += 0;
repaint();
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("AnimatedSquare");
Q3_Circular canvas = new Q3_Circular();
frame.add(canvas);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void paintComponent(Graphics g){
xStart = (double)(getWidth())/2.0 * Math.cos(degree);
yStart = (double)(getHeight())/2.0 * Math.sin(degree);
Graphics2D g2 = (Graphics2D) g;
g2.draw(new Rectangle2D.Double(xStart,yStart, 25,25));
repaint();
}
}
This code appears to draw the rectangle very quickly around the point (0,0). I'm not sure where the code is wrong.
Your code was confusing. Here's the GUI I created.
When creating a Swing GUI, use the model / view / controller pattern. Create a GUI model, and GUI view, and one or more controllers to modify the model and repaint the view.
Here are the changes I made to your code.
I created a DrawingRectangle class to hold the information about the drawing rectangle. This class is a plain old Java object with getters and setters. This class is the GUI model.
I moved everything out of the main method except for the call to the SwingUtilities invokeLater method. The invokeLater method puts the creation and use of the Swing components on the Event Dispatch thread. Oracle and I insist that all Swing applications start on the Event Dispatch thread.
I create the drawing rectangle in the constructor of the Q3_Circular class. Generally, you create the GUI model, then the GUI view.
I rearranged the JFrame code in the run method to be in the proper order. I removed the setSize method and replaced it with the pack method. We don't care how big the JFrame is. We care how big the drawing panel is.
I created a drawing panel from a JPanel. Here, we set the preferred size of the drawing panel. We extend a JPanel so we can override the paintComponent method.
The paintComponent method does nothing but paint the drawing rectangle. No calculations or anything but painting is done in the paintComponent method. I added a call to the super paintComponent method to maintain the Swing paint chain and clear the drawing panel before I paint the drawing rectangle. I draw the rectangle using the x and y coordinates as the center of the rectangle, rather than the upper left corner. This is the one transformation I do in the drawing code.
I created a drawing animation from a Runnable. You can use a Swing Timer if you want. I find it easier to create my own animation code. This is the GUI controller. Here is where we do the calculations, update the model, and repaint the drawing panel. In the repaint method, I use the SwingUtilities invokeLater method to do the painting on the Event Dispatch thread. I do this because the animation thread is a separate thread.
Here's the code. I put all the classes together so I could paste the code easier. You should separate the classes into different files.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Q3_Circular implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Q3_Circular());
}
private static final int DRAWING_WIDTH = 300;
private static final int DRAWING_HEIGHT = DRAWING_WIDTH;
private DrawingRectangle drawingRectangle;
public Q3_Circular() {
int center = DRAWING_WIDTH / 2;
Rectangle2D rectangle = new Rectangle2D.Double(center, center, 32D, 32D);
drawingRectangle = new DrawingRectangle(Color.RED, rectangle);
}
#Override
public void run() {
JFrame frame = new JFrame("Animated Square");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = new DrawingPanel(DRAWING_WIDTH,
DRAWING_HEIGHT, drawingRectangle);
frame.add(drawingPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
new Thread(new DrawingAnimation(drawingPanel, drawingRectangle))
.start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 8226587438110549806L;
private DrawingRectangle drawingRectangle;
public DrawingPanel(int width, int height,
DrawingRectangle drawingRectangle) {
this.setPreferredSize(new Dimension(width, height));
this.drawingRectangle = drawingRectangle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(drawingRectangle.getColor());
Rectangle2D rectangle = drawingRectangle.getRectangle();
int x = (int) Math.round(rectangle.getX());
int y = (int) Math.round(rectangle.getY());
int width = (int) Math.round(rectangle.getWidth());
int height = (int) Math.round(rectangle.getHeight());
g.fillRect(x - width / 2, y - height / 2, width, height);
}
}
public class DrawingAnimation implements Runnable {
private DrawingPanel drawingPanel;
private DrawingRectangle drawingRectangle;
public DrawingAnimation(DrawingPanel drawingPanel,
DrawingRectangle drawingRectangle) {
this.drawingPanel = drawingPanel;
this.drawingRectangle = drawingRectangle;
}
#Override
public void run() {
int xCenter = drawingPanel.getWidth() / 2;
int yCenter = drawingPanel.getHeight() / 2;
double radius = drawingPanel.getWidth() / 3;
for (int degree = 0; degree < 360; degree++) {
double radians = Math.toRadians((double) degree);
double x = radius * Math.cos(radians) + xCenter;
double y = radius * Math.sin(radians) + yCenter;
drawingRectangle.setRectangleOrigin(x, y);
repaint();
sleep(100L);
}
}
private void sleep(long interval) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
}
public class DrawingRectangle {
private final Color color;
private Rectangle2D rectangle;
public DrawingRectangle(Color color, Rectangle2D rectangle) {
this.color = color;
this.rectangle = rectangle;
}
public void setRectangleOrigin(double x, double y) {
rectangle
.setRect(x, y, rectangle.getWidth(), rectangle.getHeight());
}
public Color getColor() {
return color;
}
public Rectangle2D getRectangle() {
return rectangle;
}
}
}
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());
}
}