Whenever I draw, then turn on reflection then draw everything seems fine but then I turn off reflection and the points I draw now don't appear under my mouse cursor. The strange thing is that sometimes it works fine and after I turn on and off reflection a couple of times and draw, the bug occurs. I have no idea what the reason behind it is. Here is the code, I would be extremely grateful if you could help me.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
//3 inner classes because if this code is part of a bigger problem, these classes will not be used anywhere else and need to be encapsulated
public class CWTEST extends JFrame{
public CWTEST(String title){
super(title);
}
public void initialiseGUI(){
Container mainPanel = this.getContentPane();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
//make the window as big as the screen without covering the windows taskbar
this.setBounds( 0, 0, screenSize.width, screenSize.height-40);
//set up the displayPanel where the drawing is done
mainPanel.setLayout(new BorderLayout());
DrawingPanel displayPanel = new DrawingPanel();
mainPanel.add(displayPanel, BorderLayout.CENTER);
//set up the controlPanel where the user changes the drawing options
JPanel controlPanel = new JPanel();
mainPanel.add(controlPanel, BorderLayout.SOUTH);
controlPanel.setLayout(new FlowLayout());
controlPanel.setBorder(BorderFactory.createLineBorder(new java.awt.Color(0, 255, 0)));
JLabel reflectPointsLabel = new JLabel("reflect points");
controlPanel.add(reflectPointsLabel);
JCheckBox reflectPointsBox = new JCheckBox();
reflectPointsBox.addItemListener(new ItemListener(){
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED){
displayPanel.reflectPoints = true;
}else{
displayPanel.reflectPoints = false;
}
}
});
controlPanel.add(reflectPointsBox);
reflectPointsBox.setSelected(false);
this.setVisible(true);
//once the frame is visible we can get the real size of the drawing panel and create a buffered image that matches it
displayPanel.buffImage = new BufferedImage(displayPanel.getWidth(), displayPanel.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
}
public class DrawingPanel extends JPanel{
//default drawing options
private double circleDiameter = 5;
private Color color = Color.BLUE;
private boolean showSectors;
private boolean reflectPoints;
private int numOfSectors = 12;
//list of points to be drawn
private ArrayList<MyPoint> pointsList;
//buffered image on which the drawing is done and then copied to the JPanel
private BufferedImage buffImage;
public DrawingPanel(){
this.setBackground(Color.BLACK);
DrawingListener listener = new DrawingListener(this);
this.addMouseListener(listener);
this.addMouseMotionListener(listener);
this.addComponentListener(listener);
pointsList = new ArrayList<MyPoint>();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.drawBuffImage();
//copy what's drawn on the buffered image to the JPanel
g.drawImage(buffImage, 0,0, null);
}
public void drawBuffImage(){
Graphics2D g2d = buffImage.createGraphics();
g2d.setColor(Color.WHITE);
//if there are more tan 1 sectors - draw lines to separate them
if(showSectors && numOfSectors > 1){
Line2D line = new Line2D.Double(this.getWidth()/2,0,this.getWidth()/2,this.getHeight()/2);
//draw half a line every time and rotate the next according to the number of sectors
for(int w = 0; w < numOfSectors; w++){
g2d.draw(line);
g2d.rotate(Math.toRadians((double) 360/numOfSectors), this.getWidth()/2, this.getHeight()/2);
}
}
//draw each point in the list
for(int i = 0; i < pointsList.size(); i++){
MyPoint point = pointsList.get(i);
g2d.setColor(point.getPointColor());
Ellipse2D circle = new Ellipse2D.Double(point.getX(), point.getY(), point.getPointDiameter(), point.getPointDiameter());
//draw the point once in each sector
for(int j = 0; j < numOfSectors; j++){
g2d.fill(circle);
g2d.rotate(Math.toRadians(((double) 360/numOfSectors)), this.getWidth()/2, this.getHeight()/2);
}
//if point should be reflected, draw its reflection in each sector
if(point.isReflected()){
g2d.rotate(Math.toRadians((double) 360/(numOfSectors*2)), this.getWidth()/2, this.getHeight()/2);
g2d.fill(circle);
for(int t = 1; t < numOfSectors; t++){
g2d.rotate(Math.toRadians((double) 360/numOfSectors), this.getWidth()/2, this.getHeight()/2);
g2d.fill(circle);
}
}
}
g2d.dispose();
}
public void wipeScreen(){
//wipe everything by covering it with black
Graphics g = buffImage.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0,buffImage.getWidth(),buffImage.getHeight());
g.dispose();
}
public void addPoint(MyPoint p){
pointsList.add(p);
}
public void setColor(Color color){
this.color = color;
}
public void setCircleDiameter(double circleDiameter){
this.circleDiameter = circleDiameter;
}
}
public class DrawingListener extends MouseAdapter implements ComponentListener{
//the panel on which the user draws
private DrawingPanel dPanel;
public DrawingListener(DrawingPanel dPanel){
this.dPanel = dPanel;
}
//add a point to the arraylist every time the user draws, and draw
public void mousePressed(MouseEvent e) {
dPanel.addPoint(new MyPoint(e.getX(), e.getY(), dPanel.color, dPanel.circleDiameter, dPanel.reflectPoints));
dPanel.repaint();
}
public void mouseDragged(MouseEvent e) {
dPanel.addPoint(new MyPoint(e.getX(), e.getY(), dPanel.color, dPanel.circleDiameter, dPanel.reflectPoints));
dPanel.repaint();
}
@Override
public void componentResized(ComponentEvent e) {
//whenever component is resized, wipe the screen
//then the system-triggered repaint occurs and the result is that by making the window smaller, the user zooms in
dPanel.wipeScreen();
}
public void componentHidden(ComponentEvent arg0) {}
public void componentMoved(ComponentEvent arg0) {}
public void componentShown(ComponentEvent arg0) {}
}
//each point drawn is an object of the class
public class MyPoint extends Point{
private Color pointColor;
private double pointDiameter;
private boolean reflected;
public MyPoint(int x, int y, Color c, double pointDiameter, boolean reflected){
super(x,y);
this.pointColor = c;
this.pointDiameter = pointDiameter;
this.reflected = reflected;
}
public Color getPointColor(){
return this.pointColor;
}
public double getPointDiameter(){
return this.pointDiameter;
}
public boolean isReflected(){
return this.reflected;
}
}
}
public class MainTest {
public static void main(String[] args){
CWTEST frame = new CWTEST("Digital Doily");
frame.initialiseGUI();
}
}
EDIT
When box is not ticked I get 12 points - inner most circle. Then I tick box and I get 24 points (12 original and 12 reflected) - second circle (with reflection). Then I untick box and I get outer most circle - 12 points but they are drawn in the place of the 12 reflected points from the previous circle eventhough my mouse is in the same place like for the 1st circle. The green point is an example of a reflected point - its between 2 normal points. Red dots are where my mouse cursor was at every drawing. Notice that when I make the third circle, reflection is turned off and there is no point drawn under the cursor.