JLabel array for a checkerboard design - user-interface

I simply cannot get my checkerboard graphic to appear using JLabels. I am not sure why it is not working. I did get it to work when I created it without using arrays, but the code was extremely long. What am I doing wrong?
import javax.swing.*;
import java.awt.*;
public class GuiProgramTwo_1 extends JFrame {
public GuiProgramTwo_1() {
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(6, 6));
JLabel[] array = new JLabel[69];
JLabel a1 = new JLabel();
a1.setBackground(Color.BLACK);
a1.setOpaque(true);
JLabel a2 = new JLabel();
a2.setBackground(Color.WHITE);
a2.setOpaque(true);
array[0] = new JLabel();
array[0] = a1;
p1.add(array[0]);
for(int i = 1; i < 69; i++) {
int x = i - 1;
array[i] = new JLabel();
if(array[x] == a1) {
array[i] = a2;
}
else {
array[i] = a1;
}
p1.add(array[i]);
}
add(p1, BorderLayout.CENTER);
}
public static void main(String[] args) {
GuiProgramTwo_1 frame = new GuiProgramTwo_1();
frame.setTitle("ShowFlowLayout");
frame.setSize(575, 400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

You need a unique JLabel for each position in your layout, you cannot reuse components and have them displayed in different areas of the application at the same time.
Also, your construction of your GridLayout may be wrong, you are specifying 6 rows and 6 columns which specifies room for 36 components, but it looks like you want to add a total of 69 JLabels.
p1.setLayout(new GridLayout(6, 6));

Related

Exception occurred when iterating though for loop that includes mouseEvent action

the following exception message appears when I iterate using NORMAL for-loop that includes mouseEvent action through radioButtons.
Message:
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException
But when I iterate using for-each loop, there is no problem!
please help me, thank you
Concerned code part:
HBox p1 = new HBox();
RadioButton Red = new RadioButton("RED");
RadioButton Blue = new RadioButton("Blue");
RadioButton Black = new RadioButton("Black");
ToggleGroup tg = new ToggleGroup();
Red.setToggleGroup(tg);
Blue.setToggleGroup(tg);
Black.setToggleGroup(tg);
RadioButton [] array = {Red,Blue,Black};
p1.getChildren().addAll(Red,Blue,Black);
i = 0;
for(i = 0; i< array.length; i++){
array[i].setOnAction(e->{
System.out.println(array[i].getText());
});
}
I'm guessing, because your question is incomplete, that you made the loop index i an instance variable, for some reason. I.e. you have something like:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Demo extends Application {
// Guessing:
private int i ;
#Override
public void start(Stage primaryStage) throws Exception {
HBox p1 = new HBox();
RadioButton red = new RadioButton("RED");
RadioButton blue = new RadioButton("Blue");
RadioButton black = new RadioButton("Black");
ToggleGroup tg = new ToggleGroup();
red.setToggleGroup(tg);
blue.setToggleGroup(tg);
black.setToggleGroup(tg);
RadioButton[] array = { red, blue, black };
p1.getChildren().addAll(red, blue, black);
i = 0;
for (i = 0; i < array.length; i++) {
array[i].setOnAction(e -> {
System.out.println(array[i].getText());
});
}
Scene scene = new Scene(p1, 400, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Here i is a property of the Demo instance (i.e. the application instance on which start() is invoked). In the start() method, i is initialized to 0 and then incremented each time you iterate the for loop. The for loop exits when i is no longer less than array.length (which is 3), so when the for loop exits, i==3.
Consequently, when you press one of the buttons, the code
System.out.println(array[i].getText());
is executed. The value of i hasn't changed since the completion of the for loop, so this is equivalent to
System.out.println(array[3].getText());
and this throws an IndexOutOfBoundsException, because the value indexes in the array are 0, 1, and 2. Indeed, the complete error message is
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
Instead, you need to use a local variable for the index in the loop:
for (int i = 0; i < array.length; i++) {
array[i].setOnAction(e -> { /* ... */ });
}
The problem now is that the lambda expression in the event handler cannot access the local variable i because it is not final (or "effectively final"). The solution to this is to "capture" the value of i on each iteration of the loop in a final variable:
for (int i = 0; i < array.length; i++) {
final int index = i ;
array[i].setOnAction(e -> {
System.out.println(array[index].getText());
});
}
Of course, you don't actually need the index; you just need the element of the array, so you could capture that instead:
for (int i = 0; i < array.length; i++) {
final RadioButton button = array[i] ;
button.setOnAction(e -> {
System.out.println(button.getText());
});
}
This code is completely identical (in the sense that the compiler converts the following to the same thing) to:
for (RadioButton button : array) {
button.setOnAction(e -> {
System.out.println(button.getText());
});
}
which is by far the preferred form for a for loop.
Here's a fully-cleaned and working version of the code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Demo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
HBox p1 = new HBox();
RadioButton red = new RadioButton("RED");
RadioButton blue = new RadioButton("Blue");
RadioButton black = new RadioButton("Black");
ToggleGroup tg = new ToggleGroup();
RadioButton[] buttons = { red, blue, black };
tg.getToggles().setAll(buttons);
p1.getChildren().addAll(buttons);
for (RadioButton button : buttons) {
button.setOnAction(e -> {
System.out.println(button.getText());
});
}
Scene scene = new Scene(p1, 400, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}

Whenever I use the Text object in JavaFX, all object overlap the text, even subsequent text objects

Update: I am using JavaFX 13
This problem happens across all my JavaFX programs, but this is one example. A user is supposed to be able to select options for a custom milkshake then get a receipt when they checkout. All of the object referencing and MVC works as it is supposed to, but when displaying the information using Text objects (javafx.scene.text.Text), they are overlapped by other objects around them. In the second and third images, I have the occurrences circled.
First launch of the program. The first image
Here is the code for the text pane in the second image:
After adding a few selections. The second Image
import Controllers.Controller;
import Entities.Milkshake;
import Interfaces.Observer;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import java.util.ArrayList;;
public class TextSummaryView extends AnchorPane implements Observer<Milkshake> {
private Milkshake model;
private Controller controller;
private VBox iceCreamOptions;
private VBox toppingOptions;
private Text totalCost;
private final double minHeight = 100.0;
private final double minWidth = 50.0;
public TextSummaryView() {
super();
iceCreamOptions = new VBox();
toppingOptions = new VBox();
totalCost = new Text("$0.00");
Button checkout = new Button("Checkout");
checkout.setOnAction(e -> controller.checkout());
Text iceCreamText = new Text("Click '-' to remove\nCurrent Ice Cream Selections:");
Text toppingText = new Text("Current Topping Selections");
iceCreamOptions.getChildren().add(iceCreamText);
toppingOptions.getChildren().add(toppingText);
this.getChildren().addAll(checkout, iceCreamOptions, toppingOptions, totalCost);
// Setting position of elements
setBottomAnchor(checkout, this.getHeight()-5.0);
setRightAnchor(checkout, this.getWidth()-5.0);
setLeftAnchor(totalCost, 5.0);
setBottomAnchor(totalCost, this.getHeight()-5.0);
setTopAnchor(iceCreamOptions, 5.0);
setLeftAnchor(iceCreamOptions, 5.0);
setTopAnchor(toppingOptions, Math.max(40.0, iceCreamOptions.getHeight() + 10.0));
setLeftAnchor(toppingOptions, 5.0);
this.setMinHeight(minHeight);
this.setMinWidth(minWidth);
}
/**
* Sets what the observer will watch
* #param obs An object that extends the Observable interface
*/
public void setTarget(Milkshake obs){
this.model = obs;
}
/**
* Removes the object from target
*/
public void removeTarget(){
this.model = null;
}
/**
* Called by observables to update the observer's data
*/
public void update(){
this.iceCreamOptions.getChildren().remove(1, this.iceCreamOptions.getChildren().size());
this.toppingOptions.getChildren().remove(1, this.toppingOptions.getChildren().size());
// Get Data
ArrayList<String> iceCreams = model.getIceCreams();
ArrayList<String> toppings = model.getToppings();
// Update the ice cream selections
int iceCreamIndex = 0;
for (String ic: iceCreams) {
AnchorPane selection = new AnchorPane();
Button removeButton = new Button("-");
Text iceCream = new Text(ic + ":");
Text cost = new Text("$1.00");
final int iceIndexFin = iceCreamIndex;
removeButton.setOnAction(e -> controller.removeIceCream(iceIndexFin));
selection.getChildren().addAll(removeButton, iceCream, cost);
setLeftAnchor(removeButton, 5.0);
setLeftAnchor(iceCream, 50.0);
setTopAnchor(iceCream, selection.getHeight()/3);
setLeftAnchor(cost, selection.getWidth()-5.0);
setTopAnchor(cost, selection.getHeight()/3);
this.iceCreamOptions.getChildren().add(selection);
iceCreamIndex ++;
}
// Update the topping selections
int toppingIndex = 0;
for (String top: toppings) {
AnchorPane selection = new AnchorPane();
Button removeButton = new Button("-");
Text topping = new Text(top + ":");
Text cost = new Text("$0.50");
final int topIndexFin = toppingIndex;
removeButton.setOnAction(e -> controller.removeTopping(topIndexFin));
selection.getChildren().addAll(removeButton, topping, cost);
setLeftAnchor(removeButton, 5.0);
setLeftAnchor(topping, 50.0);
setTopAnchor(topping, selection.getHeight()/3);
setLeftAnchor(cost, selection.getWidth()-5.0);
setTopAnchor(cost, selection.getHeight()/3);
this.toppingOptions.getChildren().add(selection);
toppingIndex ++;
}
setTopAnchor(iceCreamOptions, 5.0);
setLeftAnchor(iceCreamOptions, 5.0);
setTopAnchor(toppingOptions, Math.max(40.0, iceCreamOptions.getHeight() + 10.0));
setLeftAnchor(toppingOptions, 5.0);
this.totalCost.setText( "$" + this.model.getCost() + "0");
}
public void setController(Controller controller){
this.controller = controller;
}
}
Here is the code for the checkout screen. Pressing the checkout button. All are different text objects in a VBox. The third image
import Entities.Milkshake;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.util.ArrayList;
public class CheckoutView extends Stage {
VBox root = new VBox();
public CheckoutView(Milkshake ms) {
super();
// Get Data
ArrayList<String> iceCreams = ms.getIceCreams();
ArrayList<String> toppings = ms.getToppings();
// Update the ice cream selections
int iceCreamIndex = 0;
for (String ic: iceCreams) {
AnchorPane selection = new AnchorPane();
Text iceCream = new Text(ic + ":");
Text cost = new Text("$1.00");
final int iceIndexFin = iceCreamIndex;
selection.getChildren().addAll(iceCream, cost);
AnchorPane.setLeftAnchor(iceCream, 50.0);
AnchorPane.setLeftAnchor(cost, this.getWidth()-5.0);
this.root.getChildren().add(selection);
iceCreamIndex ++;
}
// Update the topping selections
int toppingIndex = 0;
for (String top: toppings) {
AnchorPane selection = new AnchorPane();
Text topping = new Text(top + ":");
Text cost = new Text("$0.50");
selection.getChildren().addAll(topping, cost);
AnchorPane.setLeftAnchor(topping, 50.0);
AnchorPane.setLeftAnchor(cost, this.getWidth()-5.0);
this.root.getChildren().add(selection);
toppingIndex ++;
}
AnchorPane total = new AnchorPane();
Text costTotal = new Text("$" +ms.getCost() + "0");
total.getChildren().add(costTotal);
AnchorPane.setLeftAnchor(total, this.getMaxWidth()-costTotal.getX());
BorderPane exitOptions = new BorderPane();
Button pay = new Button("Finish and Pay");
Button ret = new Button("Return to Order");
pay.setOnAction(e -> Platform.exit());
ret.setOnAction(e -> this.close());
exitOptions.setLeft(ret);
exitOptions.setRight(pay);
root.getChildren().add(exitOptions);
this.setTitle("Checkout");
this.setScene(new Scene(root));
}
public static void checkout(Milkshake ms) {
CheckoutView check = new CheckoutView(ms);
check.show();
}
}
Thank you in advance for all your help! :)

How to move a JButton around using a timer

so I wanna have a button move around using absolute positioning via x,y coordinates and I have a white block moving with no image and isn't clickable
The image does work with the paint method using an image, but I wanna use a button
//********************************************************************
// ReboundPanel.java Java Foundations
//
// Represents the primary panel for the Rebound program.
//********************************************************************
package ch0;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ReboundPanel extends JPanel
{
private final int WIDTH = 300, HEIGHT = 100;
private final int DELAY = 20, IMAGE_SIZE = 35;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY;
JButton button;
//-----------------------------------------------------------------
// Sets up the panel, including the timer for the animation.
//-----------------------------------------------------------------
public ReboundPanel()
{
this.setLayout(null); //Worked before I put this stuff but
super.setLayout(null);// I'm just trying stuff
timer = new Timer(DELAY, new ReboundListener());
image = new ImageIcon("smile.jpg");
button = new JButton(image);
button.setIcon(new ImageIcon("smile.jpg"));
x = 0;
y = 40;
moveX = moveY = 3;
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.black);
timer.start();
//button.setBounds(x, y, 10, 10);
//add(button);
}
//*****************************************************************
// Represents the action listener for the timer.
//*****************************************************************
private class ReboundListener implements ActionListener
{
//-----------------------------------------------------------------
// Updates the position of the image and possibly the direction
// of movement whenever the timer fires an action event.
//-----------------------------------------------------------------
public void actionPerformed(ActionEvent event)
{
x += moveX;
y += moveY;
if (x <= 0 || x >= WIDTH-IMAGE_SIZE)
moveX = moveX * -1;
if (y <= 0 || y >= HEIGHT-IMAGE_SIZE)
moveY = moveY * -1;
button.setBounds(x, y, 100, 100);
add(button);
}
}
}
//********************************************************************
// Rebound.java Java Foundations
//
// Demonstrates an animation and the use of the Timer class.
//********************************************************************
package ch0;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Rebound
{
//-----------------------------------------------------------------
// Displays the main frame of the program.
//-----------------------------------------------------------------
public static void main(String[] args)
{
JFrame frame = new JFrame("Rebound");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ReboundPanel());
frame.pack();
frame.setVisible(true);
}
}

Nodes only go one direction instead of back and forth when animating

Learning how to use javafx and I am having problems with my nodes or "targets" bouncing from edge to edge. After the first trip across the pane they stop. This code that I have so far...
public class game extends Application implements EventHandler<ActionEvent>{
target1 target1 = new target1();
target2 target2 = new target2();
shooter shooter = new shooter();
Button fireButton = new Button("Fire!");
Pane pane = new Pane();
/**
*
* #param primaryStage
*/
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(pane, 800, 600);
primaryStage.setTitle("GAME");
primaryStage.setScene(scene);
pane.getChildren().add(fireButton);
fireButton.setLayoutX(700);
fireButton.setLayoutY(500);
pane.getChildren().add(shooter);
shooter.setX(380);
shooter.setY(540);
shooter.setWidth(40);
shooter.setHeight(20);
shooter.setArcWidth(20);
shooter.setArcHeight(20);
pane.getChildren().add(target1);
target1.setX(0);
target1.setY(250);
target1.setWidth(30);
target1.setHeight(20);
target1.setArcWidth(20);
target1.setArcHeight(20);
pane.getChildren().add(target2);
target2.setX(0);
target2.setY(150);
target2.setWidth(15);
target2.setHeight(10);
target2.setArcWidth(20);
target2.setArcHeight(20);
primaryStage.show();
ShooterButtonPressHandler shooterButton = new ShooterButtonPressHandler();
fireButton.setOnAction(shooterButton);
KeyFrame keyFrame = new KeyFrame(Duration.millis(1), this);
Timeline animation = new Timeline(keyFrame);
animation.setCycleCount(Timeline.INDEFINITE);
animation.play();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
#Override
public void handle(ActionEvent event) {
if (target1.isColliding(pane) ) {
target1.processCollision();
}
target1.animate(pane);
if (target2.isColliding(pane) ) {
target2.processCollision();
}
target2.animate(pane);
}
/**
*
*/
public class ShooterButtonPressHandler implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent event) {
if (target1.getX() >= 370 && target1.getX()<= 400){
System.out.println("hit");
}
if (target2.getX() >= 370 && target2.getX()<= 400){
System.out.println("hit");
}
else {
System.out.println("miss");
}
}
}
this is a class for target 1... target 2 is the exact same.
public class target1 extends Rectangle{
int velocity = 1;
public void animate (Pane pane) {
Double x = this.getX();
x = velocity + x;
setX(x);
} // end method animate
public Boolean isColliding (Pane pane) {
Double side = pane.getWidth();
Boolean collision = (this.getX() + this.getWidth() >= side);
if (collision) {
this.setX(side);
}
return collision;
} // end method isColliding
public void processCollision () {
if(velocity == 1){
this.velocity = -1;
}
else{
this.velocity = 1;
}
} // end method processCollision
Issue
The problem you are facing is because of the statement
this.setX(side);
Lets us consider a scenario where your target reaches the boundary. At this stage, for target1 :
X = 790
width = 30
side = 800
X + width = 790 + 30 = 820, which is greater than 800
So,
collision = true
X = side = 800
Now we have,
X = 800
width = 30
side = 800
X + width = 800 + 30 = 830, which is greater than 800
Again, we have collision = true and this goes on forever.
Solution
You can set your X to a value which is less than side+width. There are various ways to achieve this, one of which is
this.setX(this.getX() - this.getWidth());
But, this will destroy the sync between the two targets, since their width are unequal. Finding a better solution is left to the reader
There is one more issue which I would like to point out, the collision takes care of the collision on the right end and not the left end. To take care of both the ends, you can edit the code as
public Boolean isColliding(Pane pane) {
Double side = pane.getWidth();
Boolean collision = false;
if(this.getX() + this.getWidth() >= side) {
this.setX(this.getX() - this.getWidth());
collision = true;
} else if (this.getX() - this.getWidth() <= 0) {
this.setX(this.getX() + this.getWidth());
collision = true;
}
return collision;
}

Animation flashing

I continuously have this problem with all my most recent animation projects. Every time I run my animations, they never seem to be completely visible and full, but rather they blink and flash similar to a light bulb that is not fully screwed in ( i know, strange comparison but I can't think of what else it resembles). I feel like it must have something to do with my placement of repaint(); but I'm just not sure at this point. On a previous animation I made, the problem was that my "private BufferedImage offScr" variable wasn't set correctly, but viewing other programs similar to the one I am working on now, I don't see why that variable would be necessary. Thanks for all your help folks, and I apologize for my lack of knowledge in programming vocabulary.
Here is my program so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class DoveAnimator extends JFrame implements ActionListener {
private int DELAY = 40; // the delay for the animation
private final int WIDTH = 400; // the window width
private final int HEIGHT = 180; // the window height
private final int IMAGEAMT = 8;
private Image [] doveLeft = new Image[IMAGEAMT];
private Image [] doveRight = new Image[IMAGEAMT];
private int doveIndex = 0;
private boolean isRight = true;
private JPanel dovePanel;
private Image dove;
private JButton slowerButton = new JButton ("Slower");
private JButton fasterButton = new JButton ("Faster");
private JButton reverseButton = new JButton ("Reverse");
private JButton pauseResumeButton = new JButton (" pause ");
private Timer timer;
private int clicks = 2;
private boolean pause = false;
/** The constructor */
public DoveAnimator() {
MediaTracker track = new MediaTracker(this);
for (int i = 0; i < IMAGEAMT; ++i) {
doveLeft[i] = new ImageIcon("doves/ldove" + (i+1) + ".gif").getImage();
doveRight[i] = new ImageIcon("doves/rdove" + (i+1) + ".gif").getImage();
track.addImage(doveLeft[i],0);
track.addImage(doveRight[i],0);
}
// dove = doveRight[0];
//track.addImage(bkgImage,0);
// track.addImage(dove,0);
try {
track.waitForAll();
} catch ( InterruptedException e ) { }
dove = doveRight[0];
JPanel mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
setTitle ("Dove Animator");
dovePanel = new JPanel();
dovePanel.setPreferredSize(new Dimension(100, 125));
dovePanel.setBackground(Color.WHITE);
mainPanel.add(dovePanel);
JPanel buttonPanel = new JPanel();
buttonPanel.setPreferredSize(new Dimension(WIDTH, 40));
// button 1
slowerButton.addActionListener (this);
buttonPanel.add (slowerButton);
// button 2
fasterButton.addActionListener (this);
buttonPanel.add (fasterButton);
// button 3
reverseButton.addActionListener (this);
buttonPanel.add (reverseButton);
// button 4
pauseResumeButton.addActionListener (this);
buttonPanel.add (pauseResumeButton);
mainPanel.add(buttonPanel);
add(mainPanel);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setVisible (true);
pack();
timer = new Timer(DELAY,this); // setting timer delay
timer.start(); // start the timer
}
public void switchDove() {
++doveIndex;
if (doveIndex >= IMAGEAMT)
doveIndex = 0;
if (isRight)
dove = doveRight[doveIndex];
else
dove = doveLeft[doveIndex];
dove = (isRight) ? doveRight[doveIndex] : doveLeft[doveIndex];
}
/** Handler for button clicks and timer events */
public void actionPerformed (ActionEvent evt) {
if (evt.getSource() == slowerButton)
{
DELAY += 10;
}
else if (evt.getSource() == reverseButton)
{
if(evt.getSource() == reverseButton && isRight == true){
isRight = false;
}
else if(evt.getSource() == reverseButton && !isRight){
isRight = true;
}
}
else if (evt.getSource() == fasterButton)
{
DELAY -= 10;
if (DELAY <= 10 ){
DELAY = 10;
}
}
else if (evt.getSource() == pauseResumeButton)
{
if(evt.getSource() == pauseResumeButton && !pause){
pauseResumeButton.setText(" Resume ");
timer.stop();
pause = true;
}
else if(evt.getSource() == pauseResumeButton && pause == true){
pauseResumeButton.setText(" Pause ");
timer.start();
pause = false;
}
}
else if (evt.getSource() == timer)
{
drawAnimation();
switchDove();
repaint();
}
}
/** Draws the dove in the dovePanel */
public void drawAnimation() {
Graphics page = dovePanel.getGraphics();
page.drawImage(dove,0,0,Color.WHITE,null);
}
/** The main method */
public static void main (String [] args) {
new DoveAnimator();
}
}
Yep it seems to be one of your repaint() calls. Take out your repaint() method call here:
else if (evt.getSource() == timer)
{
drawAnimation();
switchDove();
repaint();
It's confusing the program because you are already switching the doves. That's my best guess. I ran it and it seems to work though. Cheers!
Also I just noticed that the way you are adjusting your timer will yeild you no results. You need to use the command: timer.setDelay(newDelay); you can also put arguments in the parenthesis like timer.setDelay(DELAY -= 10);

Resources