How to retain previous changes using paint() and run() or other - java

how can I keep the previous changes using repaint() and run() or is there another solution for this.
I have this code running well. This code paints 3 ovals. When I put an input for the x-coordinate at the text box, it paints/draws the new oval. However, everytime I input and change the x-coordinate at the text box, the oval just relocates. What I want to do is to retain the previous changes that I have made. For example, I get 3 ovals at start when you hit the see coordinates button then you get 4 and so on after you input and click the add coordinate button.
Here's my code:
/deleted/
Any help would be much appreciated.
[EDIT]
I'm implementing K-nearest neighbors. So far what I have made are:
1.created a gray panel of size 500x500 from (0,0)
2.gets file using browse button.
3.gets string and tokenize
4.token[0]= k-nearest, token[1]= total neighbors
5.token[2]= x-coordinate, token[3]= y-coordinate, token[4]= type of cluster and so on.
6.input x-coord and y-coord
7.compute distance between coordinates from txt file and input
8.draw shape according to minimum distance
Here's my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.*;
import java.lang.Math;
public class Knn extends JFrame implements ActionListener{
JPanel grid,panel;
JLabel xlab,ylab;
JTextArea xtex,ytex,temp;
JButton cbut,fbut;
String text;
int k, ktotal, x, y,xcori,ycori;
String[] token;
int[] itoken;
boolean paint=false, paintclass=false;
double ans,xcord,ycord;
double[] dtoken,ansarray,xarray,yarray;
Map<Double, Double> anshash;
public Knn(){
super("K-Nearest Neighbor");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(600,500);
//this.pack();
this.setVisible(true);
this.setResizable(true);
this.setLayout(null);
grid= new JPanel();
grid.setBackground(Color.GRAY);
grid.setBounds(0,0,500,500);
panel= new JPanel();
//panel.setLayout(null);
panel.setBounds(500,0,100,100);
temp= new JTextArea();
xlab= new JLabel("X");
xtex= new JTextArea("",1,7);
ylab= new JLabel("Y");
ytex= new JTextArea("",1,7);
cbut= new JButton("classify");
fbut= new JButton("Browse");
panel.add(xlab);
panel.add(xtex);
panel.add(ylab);
panel.add(ytex);
panel.add(cbut);
panel.add(fbut);
this.add(grid);
this.add(panel);
fbut.addActionListener(this);
cbut.addActionListener(this);
}
public double formula(double x1, double y1, double x2, double y2){
double tmpans= Math.pow((x2-x1),2.0) + Math.pow((y2-y1),2.0);
ans= Math.sqrt(tmpans);
return ans;
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==fbut){ //choose file input coordinates
JFileChooser fileChooser= new JFileChooser();
int returnVal = fileChooser.showOpenDialog(this);
if(returnVal == JFileChooser.APPROVE_OPTION){
File file = fileChooser.getSelectedFile();
try {
//output file content to text box, copy to a string
temp.read( new FileReader(file.getAbsolutePath()),null);
text= temp.getText();
}catch(IOException ex){
ex.printStackTrace();
}
}
token = text.split("\\W+");
itoken=new int[token.length];
int i=0;
for (String str : token){
itoken[i++] = Integer.parseInt(str); //convert from string to integer
}
for (i = 4; i < itoken.length; i += 3) { //x50
itoken[i-2]= itoken[i-2] * 50;
itoken[i-1]= itoken[i-1] * 50;
}
paint=true;
repaint();
}
if(e.getSource()==cbut){
solveClass();
}
}
public void paint(Graphics g){
super.paint(g);
if (paint) {
for (int i = 4; i < itoken.length; i += 3) {
x = itoken[i-2];
y = itoken[i-1];
if(itoken[i]==1)
g.fillRect(x - 5, y - 5, 10, 10);
if(itoken[i]==2)
g.fillOval(x - 5, y - 5, 10, 10);
if(itoken[i]==3)
g.drawOval(x - 5, y - 5, 10, 10);
}
}
if(paintclass){
if(anshash.get(ansarray[0])==1)
g.fillRect(xcori - 5, ycori - 5, 10, 10);
if(anshash.get(ansarray[0])==2)
g.fillOval(xcori - 5, ycori - 5, 10, 10);
if(anshash.get(ansarray[0])==3)
g.drawOval(xcori - 5, ycori - 5, 10, 10);
}
}
public void solveClass(){
String xcors= xtex.getText();
String ycors= ytex.getText();
dtoken=new double[itoken.length];
xarray=new double[itoken[1]];
yarray=new double[itoken[1]];
ansarray=new double[itoken[1]];
int j=0;
for (String str : token)
dtoken[j++] = Double.parseDouble(str); //convert from string to double
//convert to int
xcori= Integer.parseInt(xcors);
ycori= Integer.parseInt(ycors);
//convert to double
xcord= Double.parseDouble(xcors);
ycord= Double.parseDouble(ycors);
int q=0;
for (int i = 3; i < itoken.length; i += 3) {
xarray[q]= dtoken[i-1];
yarray[q]= dtoken[i];
q++;
}
for (int i = 0; i < xarray.length; i ++)
ansarray[i]= formula(xcord,ycord,xarray[i]*50,yarray[i]*50); //x50
anshash= new HashMap<Double,Double>();
int r=0;
for(int i = 4; i < itoken.length; i += 3){
anshash.put(ansarray[r], dtoken[i]);
r++;
}
Arrays.sort(ansarray); //sort
paintclass=true;
repaint();
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Knn knn= new Knn();
}
});
}
}
Here's the text file:
3 5
1 2 1
4 3 2
7 5 2
6 9 3
5 5 1

"However, everytime I input and change the x-coordinate at the text box, the oval just relocates. What I want to do is to retain the previous changes that I have made"
Use a List of ball objects. Here is the Ball class
public class Ball {
int x;
int y;
public Ball(int x, int y) {
this.x = x;
this.y = y;
}
public void drawball(Graphics g) {
g.fillOval(x, y, 20, 20);
}
}
Here is the JPanel class
public class BallPanel extends JPanel {
private List<Ball> balls;
#Override
protected void paintComponent(Graphics g) {
super.paintCompoent(g);
for (Ball ball: balls) {
ball.drawBall(g);
}
}
}
The basic point is to keep a data structure of the ball locations. You may also want to have getters and setters for the x and y so you can manipulate their locations.
To add more balls, all you need to do is add to the List a new Ball(...) and call repaint();
Here's a running example. Just type in an x and a y less than 500 and click the button. You will see more balls being added. You can see in the actionPerformed where I add a new Ball and the in the paintCompoent where I loop though the ball List
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TestBall extends Frame implements ActionListener {
private JTextField enterX;
private JTextField enterY;
private JLabel labelX;
private JLabel labelY;
private JButton addBall;
private List<Ball> balls;
private BallPanel ballPanel;
public TestBall() {
balls = new ArrayList<>();
ballPanel = new BallPanel();
JPanel p1 = new JPanel();
labelX = new JLabel("Enter X");
enterX = new JTextField(6);
labelY = new JLabel("Enter Y");
enterY = new JTextField(6);
addBall = new JButton("Add Ball");
addBall.addActionListener(TestBall.this);
p1.add(labelX);
p1.add(enterX);
p1.add(labelY);
p1.add(enterY);
p1.add(addBall);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(ballPanel, BorderLayout.CENTER);
frame.add(p1, BorderLayout.PAGE_START);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
int x = Integer.parseInt(enterX.getText());
int y = Integer.parseInt(enterY.getText());
balls.add(new Ball(x, y));
ballPanel.repaint();
}
public class BallPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Ball ball : balls) {
ball.drawBall(g);
}
}
}
public class Ball {
int x;
int y;
public Ball(int x, int y) {
this.x = x;
this.y = y;
}
public void drawBall(Graphics g) {
g.fillOval(x, y, 20, 20);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestBall();
}
});
}
}

Related

Trying to draw on a canvas with sliders

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;
}
}

Calling the methods in a class in Java

I have a very basic question: my MainDriver class wishes to run the Line class when a button Line is pressed; however, I know we cannot run a whole class, so if there's another way to implement this, please let me know.
The following is the MainDriver class; I've highlighted the relevant bit in astericks.
package javafx.scene;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
//import java.awt.*;
class MainDriver extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
// create a frame
static JFrame frame;
// main function
public static void main(String args[])
{
// create a frame
frame = new JFrame("DrawShapes");
try {
// set look and feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
System.err.println(e.getMessage());
}
// create a object of class
Line line = new Line();
// create number buttons and some operators
JButton b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bs, bd, bm, be, beq;
// create number buttons
b0 = new JButton("line");
b1 = new JButton("circle");
b2 = new JButton("triangle");
b3 = new JButton("rectangle");
b4 = new JButton("quadrilateral");
b5 = new JButton("move");
b6 = new JButton("copy");
b7 = new JButton("delete");
b8 = new JButton("random");
b9 = new JButton("import");
ba = new JButton("export");
bs = new JButton("");
bd = new JButton("/");
bm = new JButton("*");
beq = new JButton("C");
// create . button
be = new JButton(".");
// create a panel
JPanel p = new JPanel();
// add action listeners
b0.addActionListener(line);
//add more later
// add elements to panel
p.add(b0);
p.add(ba);
p.add(b1);
p.add(b2);
p.add(b3);
p.add(bs);
p.add(b4);
p.add(b5);
p.add(b6);
p.add(bm);
p.add(b7);
p.add(b8);
p.add(b9);
p.add(bd);
p.add(be);
p.add(b0);
p.add(beq);
// set Background of panel
p.setBackground(Color.blue);
// add panel to frame
frame.add(p);
frame.setSize(450, 400);
}
public void actionPerformed(ActionEvent e)
{
String s = e.getActionCommand();
*************************
if (s.equals("line")) {
//Im not sure how to implement the object here
}
***************************
}
}
And here's the Line class
package javafx.scene;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class Line extends JPanel implements MouseListener,ActionListener{
private int x,y,x2,y2,a=1;
public Line(){
super();
addMouseListener(this);
}
public void paint(Graphics g){
int w = x2 - x ;
int h = y2 - y ;
int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0 ;
if (w<0) dx1 = -1 ; else if (w>0) dx1 = 1 ;
if (h<0) dy1 = -1 ; else if (h>0) dy1 = 1 ;
if (w<0) dx2 = -1 ; else if (w>0) dx2 = 1 ;
int longest = Math.abs(w) ;
int shortest = Math.abs(h) ;
if (!(longest>shortest)) {
longest = Math.abs(h) ;
shortest = Math.abs(w) ;
if (h<0) dy2 = -1 ; else if (h>0) dy2 = 1 ;
dx2 = 0 ;
}
int numerator = longest >> 1 ;
for (int i=0;i<=longest;i++) {
g.fillRect(x,y,1,1);
numerator += shortest ;
if (!(numerator<longest)) {
numerator -= longest ;
x += dx1 ;
y += dy1 ;
} else {
x += dx2 ;
y += dy2 ;
}
}
}
public void mouseClicked(MouseEvent mouse) {
if (a == 1) {
a = 0;
x = x2 = mouse.getX();
y = y2 = mouse.getY();
} else {
a = 1;
x = x2;
y = y2;
x2 = mouse.getX();
y2 = mouse.getY();
repaint();
}
}
public void mouseEntered(MouseEvent mouse){ }
public void mouseExited(MouseEvent mouse){ }
public void mousePressed(MouseEvent mouse){ }
public void mouseReleased(MouseEvent mouse){ }
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
Here is an example on how to go about it:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
public class Main {
private static void drawPoint(final Graphics g, final Point p) {
g.drawLine(p.x - 10, p.y, p.x + 10, p.y);
g.drawLine(p.x, p.y - 10, p.x, p.y + 10);
}
private static void drawLine(final Graphics g, final Point p1, final Point p2) {
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
public static interface ShapeByPoints {
int getPointCount();
void draw(final Graphics g, final Point... points);
}
public static class DrawPanel extends JPanel {
private final ArrayList<Point> points;
private ShapeByPoints s;
public DrawPanel() {
points = new ArrayList<>();
s = null;
}
public void setShape(final ShapeByPoints s) {
this.s = s;
points.clear();
repaint();
}
public void modifyLastPoint(final Point p) {
points.get(points.size() - 1).setLocation(p);
repaint();
}
public void addPoint(final Point p) {
if (s != null && points.size() == s.getPointCount())
points.clear();
points.add(p);
repaint();
}
#Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (s != null && s.getPointCount() == points.size())
s.draw(g, points.toArray(new Point[s.getPointCount()]));
else {
points.forEach(p -> drawPoint(g, p));
for (int i = 1; i < points.size(); ++i)
drawLine(g, points.get(i - 1), points.get(i));
}
}
}
public static class EllipseByPoints implements ShapeByPoints {
#Override
public int getPointCount() {
return 2;
}
#Override
public void draw(final Graphics g, final Point... points) {
g.drawOval(Math.min(points[0].x, points[1].x), Math.min(points[0].y, points[1].y), Math.abs(points[1].x - points[0].x), Math.abs(points[1].y - points[0].y));
}
}
public static class PolygonByPoints implements ShapeByPoints {
private final int points;
public PolygonByPoints(final int points) {
this.points = points;
}
#Override
public int getPointCount() {
return points;
}
#Override
public void draw(final Graphics g, final Point... points) {
for (int i = 1; i < this.points; ++i)
drawLine(g, points[i - 1], points[i]);
drawLine(g, points[this.points - 1], points[0]);
}
}
public static class LineByPoints extends PolygonByPoints {
public LineByPoints() {
super(2);
}
}
public static class RectangleByPoints implements ShapeByPoints {
#Override
public int getPointCount() {
return 2;
}
#Override
public void draw(final Graphics g, final Point... points) {
g.drawRect(Math.min(points[0].x, points[1].x), Math.min(points[0].y, points[1].y), Math.abs(points[1].x - points[0].x), Math.abs(points[1].y - points[0].y));
}
}
private static JRadioButton createButton(final String buttonText, final ButtonGroup bg, final DrawPanel dp, final ShapeByPoints s) {
final JRadioButton btn = new JRadioButton(buttonText);
btn.addActionListener(e -> dp.setShape(s));
bg.add(btn);
return btn;
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final DrawPanel dp = new DrawPanel();
final MouseAdapter ma = new MouseAdapter() {
#Override
public void mousePressed(final MouseEvent mevt) {
dp.addPoint(mevt.getPoint());
}
#Override
public void mouseDragged(final MouseEvent mevt) {
dp.modifyLastPoint(mevt.getPoint());
}
#Override
public void mouseReleased(final MouseEvent mevt) {
dp.modifyLastPoint(mevt.getPoint());
}
};
dp.setPreferredSize(new Dimension(500, 350));
dp.addMouseListener(ma);
dp.addMouseMotionListener(ma);
final ButtonGroup bg = new ButtonGroup();
final JPanel buttons = new JPanel();
buttons.add(createButton("Line", bg, dp, new LineByPoints()));
buttons.add(createButton("Ellipse", bg, dp, new EllipseByPoints()));
buttons.add(createButton("Rectangle", bg, dp, new RectangleByPoints()));
buttons.add(createButton("Triangle", bg, dp, new PolygonByPoints(3)));
buttons.add(createButton("Pentagon", bg, dp, new PolygonByPoints(5)));
//... keep creating buttons here ...
final JPanel contents = new JPanel(new BorderLayout());
contents.add(dp, BorderLayout.CENTER);
contents.add(buttons, BorderLayout.PAGE_START);
final JFrame frame = new JFrame("Clicking shapes.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Notes:
Don't use paint unless there is good reason, which usually isn't. In most cases you want to draw the panel, in which case paintComponent should be enough.
Dont' forget to firstly call super.paintComponent inside paintComponent override. This should be the first call, because it will clear the panel for you from previous drawings.
Decide if you want to add JComponents which will draw the shapes, or draw the shapes yourself in a sub-classed panel. In this case, it seems like you are trying both (because Line extends JPanel and you also override paint). In my opinion, in this case, using an abstraction of a shape to be drawn between some points will do the job. That's why I created ShapeByPoints interface.
Swing is not thread safe, which means there can be conditions between competing accesses of the same variable. To avoid such scenarios, you can run every Swing related operation at the Event Dispatch Thread (or EDT for short). To explicitly make a call in the EDT, invoke a method like SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, EventQueue.invokeLater and so on... There is enough material on the Internet about this topic. For example here.
Basically everything is redesigned from scratch in my approach (ie I did not modify your example code, because I guessed it would take a little bit more time, but that's just a guess).
I just created the ShapeByPoints interface which specifies how a shape is supposedly drawn (ie number of points it needs, and a draw method to do the drawing).
Then I created a DrawPanel extends JPanel which contains the state of each operation. For example if the user selects a pentagon to be drawn, he needs 5 points, but what happens when he/she has clicked only twice?... The DrawPanel is responsible for such scenarios and also for drawing the given shape when all the points are completed/clicked.
I added an instance of a DrawPanel in the frame, a MouseAdapter for user interaction and a couple of buttons to demonstrate this logic.
All you need to do now, is to implement ShapeByPoints as you like and supply an instance of it to the DrawPanel depending of the button pressed. I already did some examples on how to do it in the code (like an EllipseByPoints, LineByPoints, RectangleByPoints and PolygonByPoints).
Finally, as a bonus, I added the ability to drag the clicked points (ie not only click them, but click-and-drag them).
Hope it helps.

Causing balls to collide in a simple ball bounce program

I have a simple ball bounce program in which the balls bounce of the sides of my frame fine. I tried to add a way for the balls to bounce off each other by checking if two balls were touching by creating a rectangle around each ball and checking if any other ball intersects that rectangle, and if they do switch their velocities. It works fine when I add the code that has ** around it and there is only one ball but as soon as I add more than one they start moving together until they get stuck out of the frame. I have no idea what is wrong.
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
public class BallBounceFrame
{
public static void main(String[] args)
{
new BallBounceFrame();
}
JFrame frame;
JPanel controlPanel;
JButton stop, start;
JSpinner ballNum;
Timer t;
BallCanvas c;
static int WIDTH = 500;
static int HEIGHT = 500;
public BallBounceFrame()
{
frame = new JFrame("Bouncing Balls");
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
c = new BallCanvas(0, 20);
frame.add(c, BorderLayout.CENTER);
addPanels();
frame.setVisible(true);
t = new Timer(10, new animator());
t.start();
}
public void addPanels()
{
controlPanel = new JPanel();
start = new JButton("Start");
start.addActionListener(new buttonControlListener());
controlPanel.add(start);
stop = new JButton("Stop");
stop.addActionListener(new buttonControlListener());
controlPanel.add(stop);
ballNum = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1));
ballNum.addChangeListener(new spinnerControlListener());
controlPanel.add(ballNum);
frame.add(controlPanel, BorderLayout.NORTH);
}
class BallCanvas extends JPanel
{
private static final long serialVersionUID = 1L;
ArrayList<Ball> balls = new ArrayList<Ball>();
public BallCanvas(int ballNum, int ballSize)
{
setBalls(ballNum, ballSize);
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
for(Ball b : balls)
{
b.move(this.getSize());
g2.fill(b);
}
}
public void animate()
{
while(true)
{
try
{
frame.repaint();
Thread.sleep(10);
}
catch(Exception e)
{
System.out.println(e);
}
}
}
public void setBalls(int ballNum, int ballSize)
{
balls.clear();
for(int i = 0; i < ballNum; i++)
{
balls.add(new Ball(ballSize, balls));
}
}
}
class Ball extends Ellipse2D.Float
{
private int xVel, yVel;
private int size;
private ArrayList<Ball> balls;
public Ball(int size, ArrayList<Ball> balls)
{
super((int) (Math.random() * (BallBounceFrame.WIDTH /(1.1)) + 1), (int) (Math.random() * (BallBounceFrame.WIDTH /(1.3)) + 7), size, size);
this.size = size;
this.xVel = (int) (Math.random() * 7 + 2);
this.yVel = (int) (Math.random() * 7 + 2);
this.balls = balls;
}
public void move(Dimension panelSize)
{
**Rectangle2D r = new Rectangle2D.Float(super.x, super.y, size, size);
for(Ball b : balls)
{
if(b != this && b.intersects(r));
{
int tempx = xVel;
int tempy = yVel;
xVel = b.xVel;
yVel = b.yVel;
b.xVel = tempx;
b.yVel = tempy;
break;
}
}**
if(super.x < 0 || super.x > panelSize.getWidth() - size) xVel *= -1;
if(super.y < 5 || super.y > panelSize.getHeight() - size) yVel *= -1;
super.x += xVel;
super.y += yVel;
}
}
class animator implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
frame.repaint();
}
}
class buttonControlListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == stop) t.stop();
if(e.getSource() == start) t.start();
}
}
class spinnerControlListener implements ChangeListener
{
public void stateChanged(ChangeEvent e) {
if(e.getSource() == ballNum)
{
int balls = (int) ballNum.getValue();
c.setBalls(balls, 20);
frame.revalidate();
frame.repaint();
}
}
}
}
Your code has a single ArrayList<Ball> inside BallCanvas - the 'master' list - and then each Ball has its own ArrayList<Ball> representing the list of balls the were created up until that time. Ball then only uses its own ArrayList<Ball> inside the move() method.
May I suggest that you only have one, master ArrayList<Ball> inside BallCanvas? Instead of passing it in to the Ball constructor, pass it in to the move() call.

Java - Removing my 'worm' from an arraylist and JFrame

My program creates randomly colored and sized worms that expand on a JFrame/JPanel. As time progresses the worms are constantly expanding in random directions. When new worm is clicked a new worm is born somewhere on the screen.
Where my issue arises:
I having trouble understanding how I would then kill worms. When I click the kill worm button I want the worm to disappear (OR stop growing) on screen and it to be removed from the arraylist. I have no idea how to even begin doing this. I personally think removing an instance of the arraylist would be the best way, but how would I go about actually removing the worm from the screen.
Below is my code:
Main Class:
package Main;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
ThreadFrame myFrame = new ThreadFrame();
myFrame.setSize(new Dimension(640, 480));
myFrame.setLocationRelativeTo(null);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setTitle("Worms! - Jonathan Perron");
myFrame.setVisible(true);
myFrame.setResizable(false);
}
}
ThreadFrame Class:
package Main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThreadFrame extends JFrame implements ActionListener {
int index = 0;
JButton btnNewWorm, btnKillWorm;
JPanel myPanel2 = new JPanel();
ArrayList<DrawThread> worms = new ArrayList<DrawThread>();
public JPanel getMyPanel2(){
return this.myPanel2;
}
public ThreadFrame() {
JPanel myPanel = new JPanel();
btnNewWorm = new JButton("New Worm");
btnKillWorm = new JButton("Kill Worm");
myPanel.setBounds(0, 400, 640, 80);
myPanel.setLayout(new FlowLayout());
myPanel2.setSize(new Dimension(640, 400));
myPanel2.setLayout(null);
myPanel2.setBackground(Color.WHITE);
btnNewWorm.setBounds(100, 410, 200, 30);
btnKillWorm.setBounds(340, 410, 200, 30);
add(btnNewWorm);
add(btnKillWorm);
add(myPanel2);
add(myPanel);
btnNewWorm.addActionListener(this);
btnKillWorm.addActionListener(this);
}
public void actionPerformed(ActionEvent AE) {
if(AE.getSource() == btnNewWorm){
DrawThread dw = new DrawThread(myPanel2);
worms.add(dw);
System.out.println("New worm!");
}
if(AE.getSource() == btnKillWorm){
//stop worms from growing or complete disappear from JFrame
System.out.println("Kill worm!");
}
}
}
DrawThread Class:
package Main;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import javax.swing.JPanel;
public class DrawThread extends Thread implements Runnable{
Random rand = new Random();
JPanel panel2 = new JPanel();
Graphics2D g, graph;
private int sleepTime, wormDiameter, hue, saturation, brightness, randomWidth, randomHeight;
public DrawThread(int sleepTime, int wormDiameter, int hue, int saturation, int brightness, int randomWidth, int randomHeight, JPanel myPanel2) {
this.sleepTime = sleepTime;
this.wormDiameter = wormDiameter;
this.brightness = brightness;
this.hue = hue;
this.saturation = saturation;
this.randomWidth = randomWidth;
this.randomHeight = randomHeight;
g = (Graphics2D) myPanel2.getGraphics();
}
public void setColor(int hue){
this.hue = hue;
}
public int getSleepTime(){
return sleepTime;
}
public void setSleepTime(int sleepTime){
this.sleepTime = sleepTime;
}
public DrawThread(JPanel myPanel2){
//get panel dimensions
int panelWidth = myPanel2.getWidth();
int panelHeight = myPanel2.getHeight();
//worm location
randomWidth = rand.nextInt(panelWidth);
randomHeight = rand.nextInt(panelHeight);
//worm size
wormDiameter = rand.nextInt(7)+3;
//worm color
hue = rand.nextInt(255);
saturation = rand.nextInt(255);
brightness = rand.nextInt(255);
Color color = new Color(hue, saturation, brightness);
//sleep
sleepTime = rand.nextInt(80) + 20;
//Graphics
g = (Graphics2D) myPanel2.getGraphics();
g.setColor(color);
Ellipse2D.Double ellipse2D = new Ellipse2D.Double(randomWidth, randomHeight, wormDiameter, wormDiameter);
g.fill(ellipse2D);
Thread thread1 = new Thread(new DrawThread(sleepTime, wormDiameter, hue, saturation, brightness, randomWidth, randomHeight, myPanel2));
thread1.start();
}
public void run(){
try {
while(true) {
Thread.sleep(sleepTime);
Color color = new Color(hue, saturation, brightness);
g.setColor(color);
int addedHeight = 0, addedWidth = 0;
int random = rand.nextInt(8);
//determining the worms next move location
if(random == 0){ addedWidth = 0; addedHeight = 1; } //North
if(random == 1){ addedWidth = 1; addedHeight = 1; } //North-East
if(random == 2){ addedWidth = 1; addedHeight = 0; } //East
if(random == 3){ addedWidth = 1; addedHeight = -1; } //South-East
if(random == 4){ addedWidth = 0; addedHeight = -1; } //South
if(random == 5){ addedWidth = -1; addedHeight = -1; } //South-West
if(random == 6){ addedWidth = -1; addedHeight = 0; } //West
if(random == 7){ addedWidth = -1; addedHeight = 1; } //North-West
//Prevent worms from getting off the screen
if(randomHeight >= 480){ addedHeight = -1; }
if(randomHeight <= 0){ addedHeight = 1; }
if(randomWidth >= 640){ addedWidth = -1; }
if(randomWidth <= 0){ addedWidth = 1; }
randomWidth += addedWidth;
randomHeight += addedHeight;
Ellipse2D.Double e = new Ellipse2D.Double(randomWidth, randomHeight, wormDiameter, wormDiameter);
g.fill(e);
}
}
catch (InterruptedException e) {
System.out.println("ERROR!");
}
}
public String toString() {
String result = "SleepTime: " + sleepTime + "\nWorm Diameter: " + wormDiameter
+ "\nHue: " + hue + "\nSaturation: " + saturation + "\nBrightness: "
+ brightness + "\nWidth: " + randomWidth + "\nHeight: " + randomHeight;
return result;
}
}
Any help is greatly appreciated! :)
EDIT: This is the assignment that my teacher has given to write this program.
===========================================================================
In this assignment, we’re going to write a program that draws images of “worms” in a window. The
worms will grow with time, moving in random directions. Each worm will be a different color and will
grow at a different rate. A separate Thread object will manage the drawing of each worm. Here’s an
example of what the window will look like after two worms have grown for a while.
Write a class called ThreadFrame that extends JFrame. This class should include a main method that
creates one instance of this class. This should produce a GUI with an appearance similar to what you see
above. Make the window 640 by 480 pixels, and do not allow the user to resize it. Add two JPanels to
the content pane, a white one in the center region on which the threads will be drawn, and a gray one in
the south region to hold the JButtons marked “New Worm” and “Kill Worm”.
Add an action listener to the “New Worm” button, so that when you click on it, it creates a new instance
of a class called DrawThread (to be described shortly), adds it to an ArrayList, and starts it. Add an action
listener to the “Kill Worm” button, so that when you click on it, it removes the first DrawThread from
the ArrayList and interrupts it.
The class DrawThread extends Thread, and does most of the work of the program. This class will draw
on the upper panel of the ThreadFrame, so a reference to this panel must be passed to the constructor
of DrawThread, when this constructor is called from ThreadFrame. The constructor should perform the
following tasks:
Assign the JPanel reference (received as an argument) to an instance variable of this object.
Get the graphics context for the JPanel (use the getGraphics method), cast it to type Graphics2D, and
assign it to an instance variable.
Determine the width and height of this JPanel, and save these values.
Create a Color object, with randomly-chosen values for the three arguments to set the red, green, and
blue intensities, and assign this object to an instance variable.
Randomly choose a sleep time for this thread, between 20 and 100 milliseconds. This will determine
how rapidly the image grows.
Regarding your instructions
Write a class called ThreadFrame that extends JFrame. This class should include a main method that creates one instance of this class. This should produce a GUI with an appearance similar to what you see above. Make the window 640 by 480 pixels, and do not allow the user to resize it. Add two JPanels to the content pane, a white one in the center region on which the threads will be drawn, and a gray one in the south region to hold the JButtons marked “New Worm” and “Kill Worm”.
OK, you've got this.
Add an action listener to the “New Worm” button, so that when you click on it, it creates a new instance of a class called DrawThread (to be described shortly), adds it to an ArrayList, and starts it.
Again, you've done this.
Add an action listener to the “Kill Worm” button, so that when you click on it, it removes the first DrawThread from the ArrayList and interrupts it.
Break it down:
Get the most recent worm from the ArrayList -- you would use two ArrayList methods, size() and get(...) to achieve this. Give it a try.
Then interrupt the thread. Once you get the object from the array list, you will need to call a Thread method on it, and I'm guessing that you'll be able figure out which method, right (read the instructions for this, i.e, "and interrupts it")? ;)
Edit
Note, that his recommendations are not good, and I would not hire your instructor or course director as a Swing programmer if I needed one.
Edit
Just for grins, here is another way to code this sort of thing. Note that it does not satisfy your assignment requirements (which is one reason I don't hesitate to post it), but it shows what I believe are better Swing behaviors:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class MyWormMain {
private static void createAndShowGui() {
MyWormDrawPanel drawPanel = new MyWormDrawPanel();
MyWormButtonPanel btnPanel = new MyWormButtonPanel(drawPanel);
JFrame frame = new JFrame("Worms");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
frame.getContentPane().add(btnPanel.getMainPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyWormDrawPanel extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = 480;
private static final Color BACKGROUND = Color.WHITE;
private static final int TIMER_DELAY = 50;
private List<MyWorm> wormList = new ArrayList<>();
private Timer wormTimer;
private Random random = new Random();
public MyWormDrawPanel() {
setBackground(BACKGROUND);
wormTimer = new Timer(TIMER_DELAY, new WormTimerListener());
wormTimer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (MyWorm worm : wormList) {
worm.draw(g2);
}
}
public void addWorm() {
int r = random.nextInt(128) + 128;
int g = random.nextInt(128) + 128;
int b = random.nextInt(128) + 128;
int rand = random.nextInt(3);
switch (rand) {
case 0:
r /= 3;
break;
case 1:
g /= 3;
break;
case 2:
b /= 3;
default:
break;
}
Color color = new Color(r, g, b);
int x = random.nextInt(PREF_W);
int y = random.nextInt(PREF_H);
Point head = new Point(x, y);
wormList.add(new MyWorm(color, head, PREF_W, PREF_H));
}
public void killWorm() {
if (wormList.size() > 0) {
wormList.remove(wormList.size() - 1);
}
}
private class WormTimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (MyWorm worm : wormList) {
worm.grow();
}
repaint();
};
}
}
#SuppressWarnings("serial")
class MyWormButtonPanel {
private static final int GAP = 15;
private JPanel mainPanel = new JPanel();
private MyWormDrawPanel drawPanel;
public MyWormButtonPanel(MyWormDrawPanel drawPanel) {
this.drawPanel = drawPanel;
mainPanel.setLayout(new GridLayout(1, 0, GAP, GAP));
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(new JButton(new AddWormAction("Add Worm", KeyEvent.VK_A)));
mainPanel.add(new JButton(new KillWormAction("Kill Worm", KeyEvent.VK_K)));
}
public JComponent getMainPanel() {
return mainPanel;
}
private class AddWormAction extends AbstractAction {
public AddWormAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.addWorm();
}
}
private class KillWormAction extends AbstractAction {
public KillWormAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.killWorm();
}
}
}
class MyWorm {
private static final int MAX_DIR = 360;
private static final int SEG_WIDTH = 20;
private static final int MAX_RAND_DIR = 60;
private Color color;
private List<Point> body = new ArrayList<>();
private Random random = new Random();
private int direction;
private int maxX;
private int maxY;
public MyWorm(Color color, Point head, int maxX, int maxY) {
this.color = color;
body.add(head);
direction = random.nextInt(MAX_DIR);
this.maxX = maxX;
this.maxY = maxY;
}
public void grow() {
Point lastPt = body.get(body.size() - 1);
int x = lastPt.x
+ (int) (SEG_WIDTH * 3 * Math.cos(Math.toRadians(direction)) / 4.0);
int y = lastPt.y
+ (int) (SEG_WIDTH * 3 * Math.sin(Math.toRadians(direction)) / 4.0);
if (x < 0) {
x = maxX - 1;
}
if (x > maxX) {
x = 0;
}
if (y < 0) {
y = maxY - 1;
}
if (y > maxY) {
y = 0;
}
Point nextPoint = new Point(x, y);
direction += random.nextInt(MAX_RAND_DIR) - MAX_RAND_DIR / 2;
body.add(nextPoint);
}
public void draw(Graphics2D g2) {
Graphics2D g2b = (Graphics2D) g2.create();
g2b.setColor(color);
for (Point p : body) {
int x = p.x - SEG_WIDTH / 2;
int y = p.y - SEG_WIDTH / 2;
int width = SEG_WIDTH;
int height = SEG_WIDTH;
g2b.fillOval(x, y, width, height);
}
g2b.dispose();
}
}

Repaint in Panel method not updated

I am trying to make a program that work like this:
In Window class every time I click on the button, the method panel2 of Panel is called: first it is drawing a first circle, then a second one (after the time defined in the timer). Then, I click again on the button, and it is drawing a fist circle, then a second one then a third one. etc.
The problem is that it when I click to obtain 3 circles appearing one after the other, the two first circles drawn at the previous step (before I pressed a second time the button) stay on the screen and only the third circle is drawn when i press the button (instead of having : first circle drawn, second circle drawn, third circle drawn). I hope I am clear.
Here is a simple code:
Window
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Window extends JFrame implements ActionListener{
int h = 2;
Panel b = new Panel();
JPanel container = new JPanel();
JButton btn = new JButton("Start");
JButton bouton = new JButton();
Panel boutonPane = new Panel();
public Window(){
this.setTitle("Animation");
this.setSize(300, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
JPanel top = new JPanel();
btn.addActionListener(this);
top.add(btn);
container.add(top);
this.setContentPane(container);
this.setVisible(true);
}
public void window2(){
this.setTitle("ADHD");
this.setSize(1000,700);
this.setLocationRelativeTo(null);
if (h < 11){
boutonPane.panel2(h);
bouton.addActionListener(this);
boutonPane.add(bouton);
this.add(boutonPane);
this.setContentPane(boutonPane);
updateWindow2();
}
this.setVisible(true);
}
public void updateWindow2(){
boutonPane.panel2(h);
this.revalidate();
this.repaint();
}
public void actionPerformed(ActionEvent e){
if ((JButton) e.getSource() == btn){
System.out.println("pressed0");
window2();
}
if ((JButton) e.getSource() == bouton){
h++;
System.out.println("pressed" + h);
updateWindow2();
}
}
public static void main(String[] args){
Window w = new Window();
}
}
Panel
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Panel extends JPanel implements ActionListener{
int m;
int u=0;
int lgi, lrgi;
int [] ta;
Timer timer1 = new Timer(300, this);
Panel(){
}
public void panel2(int n){
m=n;
ta = new int [n];
for(int it=0; it<m;it++){
ta[it]=100*it;
}
timer1.start();
}
public void paintComponent(Graphics gr){
super.paintComponent(gr);
gr.setColor(Color.red);
for(int i=0;i<m;i++){
gr.fillOval(ta[i],ta[i], 150, 150);
}
}
#Override
public void actionPerformed(ActionEvent arg0) {
if(u<m){
u++;
revalidate();
repaint();
}
}
}
Your code needs use two int values to decide how many circles to draw and when:
The first int should be the count of current circles to draw, say called, currentCirclesToDraw.
The second int will be the number of circles to draw total.
If you use a List<Ellipse2D> like I suggest, then this number will be the size of the list. So if the List is called ellipseList, then the 2nd number will be ellipseList.size().
The first variable will be incremented in the timer up to the size of the list, but no larger, and will be used by paintComponent method to decide how many circles to draw.
Key point here: the first number, the currentCirclesToDraw, must be re-set to 0 when the button is pressed. This way your paintComponent method will start out drawing 0 circles, then 1, then 2, ...
For example, the paintComponent method could look like so:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(CIRCLE_COLOR);
for (int i = 0; i < currentCirclesToDraw && i < ellipseList.size(); i++) {
g2.fill(ellipseList.get(i));
}
}
I use the second term in the for loop conditional statement, i < currentCirclesToDraw && i < ellipseList.size() as an additional fail-safe to be sure that we don't try to draw more circles then we have in our list.
My Timer's ActionListener would increment the currentCirclesToDraw variable and call repaint. It would stop the Timer once currentCirclesToDraw reaches the size of the ellipseList:
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (currentCirclesToDraw < ellipseList.size()) {
currentCirclesToDraw++;
repaint();
} else {
// stop the Timer
((Timer)e.getSource()).stop();
}
}
}
And my button's actionPerformed method would reset currentCirclesToDraw to 0, would add a new Ellipse2D to my ellipseList (if we've not yet reached the MAX_CIRCLE_INDEX), would call repaint() to clear the JPanel, and would construct and start the Timer:
public void actionPerformed(java.awt.event.ActionEvent arg0) {
currentCirclesToDraw = 0; // this is key -- reset the index used to control how many circles to draw
if (ellipseList.size() < MAX_CIRCLE_INDEX) {
double x = (ellipseList.size()) * CIRCLE_WIDTH / Math.pow(2, 0.5);
double y = x;
double w = CIRCLE_WIDTH;
double h = CIRCLE_WIDTH;
ellipseList.add(new Ellipse2D.Double(x, y, w, h));
}
repaint(); // clear image
new Timer(TIMER_DELAY, new TimerListener()).start();
};
Edit 3/30/14
Note it all can be put together like this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
/**
* http://stackoverflow.com/a/22714405/522444
* http://stackoverflow.com/questions/22712655/repaint-in-panel-method-not-updated
* #author Pete
*
*/
#SuppressWarnings("serial")
public class TimerCircles extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 700;
private static final Color CIRCLE_COLOR = Color.RED;
public static final int MAX_CIRCLE_INDEX = 11;
public static final int TIMER_DELAY = 300;
public static final int CIRCLE_WIDTH = 100;
private final List<Ellipse2D> ellipseList = new ArrayList<>();
private int currentCirclesToDraw = 0;
public TimerCircles() {
add(new JButton(new ButtonAction("New Circle", KeyEvent.VK_C)));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(CIRCLE_COLOR);
for (int i = 0; i < currentCirclesToDraw && i < ellipseList.size(); i++) {
g2.fill(ellipseList.get(i));
}
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
public void actionPerformed(java.awt.event.ActionEvent arg0) {
currentCirclesToDraw = 0; // this is key -- reset the index used to control how many circles to draw
if (ellipseList.size() < MAX_CIRCLE_INDEX) {
double x = (ellipseList.size()) * CIRCLE_WIDTH / Math.pow(2, 0.5);
double y = x;
double w = CIRCLE_WIDTH;
double h = CIRCLE_WIDTH;
ellipseList.add(new Ellipse2D.Double(x, y, w, h));
}
repaint(); // clear image
new Timer(TIMER_DELAY, new TimerListener()).start();
};
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (currentCirclesToDraw < ellipseList.size()) {
currentCirclesToDraw++;
repaint();
} else {
// stop the Timer
((Timer)e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
TimerCircles mainPanel = new TimerCircles();
JFrame frame = new JFrame("TimerCircles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories

Resources