Swing draws 3 JLabels instead of one - java

I don't really understand why this program draws three pawns instead of one and two of which seem to have a random(probably not so random) positions. enter image description here
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GamePanel extends JPanel implements MouseListener {
static final int SCREEN_EDGE = 800;
static final int GAME_UNITS = 64;
static final int UNIT_SIZE = 100;
final int[] x = new int[GAME_UNITS];
final int[] y = new int[GAME_UNITS];
boolean running = false;
public GamePanel() {
this.setPreferredSize(new Dimension(SCREEN_EDGE, SCREEN_EDGE));
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
int[] position = {0,0};
int[] position1 = {1, 0};
new Pawn(position,-1);
}
private void startGame() {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g){
int counter = 1;
for (int y = 0; y < SCREEN_EDGE/UNIT_SIZE; y++) {
// 1 == "white" 2 == "black"
int color = (y % 2 == 0) ? 1 : 2;
for (int x = 0; x < SCREEN_EDGE/UNIT_SIZE; x++) {
g.setColor(color == 1 ? new Color(239,217, 181) : new Color(180, 136,98));
g.fillRect(x*UNIT_SIZE, y*UNIT_SIZE, UNIT_SIZE, UNIT_SIZE);
color = color == 1 ? 2 : 1;
}
}
for (int i = 0; i < Figure.figures.length; i++) {
JLabel figureSprite = new JLabel(Figure.figures[i].image, JLabel.CENTER);
figureSprite.setSize(90,90);
figureSprite.setLocation(Figure.figures[i].position[0] + 5,Figure.figures[i].position[1] + 5);
this.add(figureSprite);
}
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
public class MyKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
}
}
}
import javax.swing.*;
public abstract class Figure{
protected int value;
protected ImageIcon image;
protected int[][] possibleMoves;
public int[] position;
// white = -1 black = 1
protected int whiteOrBlack;
protected static int figureCount = 1;
// int[figureCount][0 = x][1 = y][2 = color]
public static Figure[] figures = new Figure[figureCount];
public Figure(int value, int[] position, int[][] possibleMoves , int whiteOrBlack) {
this.value = value;
this.position = position;
this.possibleMoves = possibleMoves;
this.whiteOrBlack = whiteOrBlack;
Figure[] oldFigures = figures;
figures = new Figure[figureCount];
for (int i = 0; i < oldFigures.length; i++) {
figures[i] = oldFigures[i];
}
figures[figureCount - 1] = this;
figureCount++;
}
public abstract void move(int[] coordinates);
}
import javax.swing.*;
import java.awt.*;
import java.io.*;
public class Pawn extends Figure{
public Pawn(int[] position, int whiteOrBlack) {
super(1, position, new int[3][2], whiteOrBlack);
super.image = new ImageIcon(getClass().getClassLoader().getResource("graphics/" + (whiteOrBlack == -1 ? "whitePawn.png" : "blackPawn.png")));
Image newImage = super.image.getImage().getScaledInstance(90,90, Image.SCALE_AREA_AVERAGING);
super.image = new ImageIcon(newImage);
}
public void checkMoves(){
for (int i = 0; i < figures.length; i++) {
if((position[0] - 1) == figures[i].position[0] && (position[1] + this.whiteOrBlack) == figures[i].position[1] && figures[i].whiteOrBlack != this.whiteOrBlack) {
possibleMoves[0][0] = position[0] - 1;
possibleMoves[0][1] = position[1] + this.whiteOrBlack;
}else possibleMoves[0] = new int[2];
if((position[0]) != figures[i].position[0] && (position[1]) != figures[i].position[1]){
possibleMoves[1][0] = position[0];
possibleMoves[1][1] = position[1] + 1;
}else possibleMoves[1] = new int[2];
if((position[0] + 1) == figures[i].position[0] && (position[1] + this.whiteOrBlack) == figures[i].position[1] && figures[i].whiteOrBlack != this.whiteOrBlack) {
possibleMoves[2][0] = position[0] + 1;
possibleMoves[2][1] = position[1] + this.whiteOrBlack;
}else possibleMoves[2] = new int[2];
}
}
#Override
public void move(int[] coordinates) {
}
}
import javax.swing.*;
public class GameFrame extends JFrame {
public GameFrame(){
this.add(new GamePanel());
this.setTitle("Chess");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setResizable(false);
this.setVisible(true);
this.setLocationRelativeTo(null);
}
}
public class ChessGame {
public static void main(String[] args) {
new GameFrame();
}
}
I tried few thing like changing JLabel to BufferedImage but it would've generate other problems down the line like not being able to use MouseListener so i feel stuck. I would love to know why this code generates 3 textures too.

It looks like you are adding FigureSprites from within the drawComponent() method. The more often you draw the window, the more figures you have to draw.
Instead within drawComponent() just draw the current state but do not modify it. Adding figures has to come from somewhere else. For example, you could create the necessary pawns in the constructor. Or in extra methods that might get triggered based on user input.
In case you modify the GamePanel's state enough so that it should get painted freshly, just invoke repaint(). Swing will mark this component for repainting and decide on it's own when to run the paint() method, which in turn will run paintComponent().

Related

How to update Sorting Algorithm Visualization?

I have been making a sorting algorithm visualizer in Java using Java Swing and AWT and coded insertion sort to see if it would be able to work. The algorithm works in the sense that when this program is run you can shuffle and sort the algorithm using insertion short but you don't actually see the algorithm in action. It just happens instantly and have been looking for ways to add some sort of delay but I can't find any sources to help me.
I set it up with 4 java classes, the main which just init's the window, the window class, array visualizer class, and the insertion sort class.
Window.java:
public class Window implements ActionListener {
//Window width
protected static int WINDOW_WIDTH = 1980;
//Window height
protected static int WINDOW_HEIGHT = 1080;
private int delay = 100;
//This will draw all our rectangles
protected static ArrayVisualizer arrayVisualizer;
//Make a new JFrame
JFrame window = new JFrame();
JButton shuffleBut = new JButton("Shuffle");
JButton startSort = new JButton("Start Sorting");
public Window() {
initWindow();
}
private void addButtons() {
//Shuffle Button
shuffleBut.setBounds(100, 50, 100, 100);
shuffleBut.setBackground(Color.white);
shuffleBut.addActionListener(this);
startSort.setBounds(500, 50, 100, 100);;
startSort.setBackground(Color.white);
startSort.addActionListener(taskPerformer);
window.add(shuffleBut);
window.add(startSort);
}
private void initWindow() {
ImageIcon logo = new ImageIcon();
window = new JFrame();
window.setTitle("JAlgorithms");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
window.setResizable(false);
addButtons();
arrayVisualizer = new ArrayVisualizer();
window.add(arrayVisualizer);
arrayVisualizer.repaint(); //Will call paint component method
window.pack();
window.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == shuffleBut) {
arrayVisualizer.shuffle(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent event) {
if(event.getSource() == startSort) {
arrayVisualizer.sort(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
};
}
ArrayVisualizer.java:
public class ArrayVisualizer extends JPanel {
protected static int[] array;
private final int REC_WIDTH = 1; //1980 rectangles
private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
public ArrayVisualizer() {
array = new int[NUMBER_OF_RECS];
generateRandom(array);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g.create();
graphics.setColor(Color.orange);
for(int i = 0; i < NUMBER_OF_RECS; i++) {
int height = array[i] * 4; //Done for scaling
int recX = i + (REC_WIDTH - 1) * i; //Read fillRect documentation
int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
graphics.fillRect(recX, recY, REC_WIDTH, height);
}
}
//This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
#Override
public Dimension getPreferredSize() {
return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
}
//Creates a random unsorted array with numbers 1-200
protected void generateRandom(int[] array) {
Random number = new Random();
for(int i = 0; i < NUMBER_OF_RECS; i++) {
array[i] = number.nextInt(200);
}
}
protected void shuffle(int[] array) {
generateRandom(array);
}
protected void sort(int[] array) {
InsertionSort.insertionSort(array);
}
}
InsertionSort.java:
public class InsertionSort {
public static void insertionSort(int arr[])
{
int n = arr.length;
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
}
UPDATE (Here is the modified code, I added selection sort as well and heavily modified the suggestion I checkmarked):
Main.java:
public class Main {
public static void main(String[] args) {
//Opens window
Window window = new Window();
}
}
Window.java:
import java.awt.Color;
import java.awt.Image;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.EventQueue;
import javax.swing.ImageIcon;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Window implements ActionListener {
//Window width
protected static int WINDOW_WIDTH = 1440;
//Window height
protected static int WINDOW_HEIGHT = 1080;
//This will draw all our rectangles
protected static ArrayVisualizer arrayVisualizer;
//Make a new JFrame
JFrame window = new JFrame();
JButton shuffleBut = new JButton("Shuffle");
JButton startSort = new JButton("Start Sorting");
public Window() {
initWindow();
}
private void addButtons() {
//Shuffle Button
shuffleBut.setBounds(100, 50, 100, 100);
shuffleBut.setBackground(Color.white);
shuffleBut.addActionListener(this);
startSort.setBounds(500, 50, 100, 100);;
startSort.setBackground(Color.white);
window.add(shuffleBut);
window.add(startSort);
}
private void initWindow() {
ImageIcon logo = new ImageIcon();
window = new JFrame();
window.setTitle("JAlgorithms");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
window.setResizable(false);
addButtons();
startSort.addActionListener(taskPerformer);
arrayVisualizer = new ArrayVisualizer();
window.add(arrayVisualizer);
arrayVisualizer.repaint(); //Will call paint component method
window.pack();
window.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == shuffleBut) {
arrayVisualizer.shuffle(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
ActionListener taskPerformer = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if(event.getSource() == startSort) {
if(!timer.isRunning()) { //If timer is not running
timer.setInitialDelay(0); //Set initial delay
timer.start(); //Start the timer
}
}
}
};
ActionListener sortWithDelay = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(sorted(ArrayVisualizer.array)) { //If it is sorted
timer.stop(); //Stop the timer
return;
} else {
arrayVisualizer.sort(ArrayVisualizer.array); //If it is not sorted continue the sort
arrayVisualizer.repaint(); //Called after each swap
}
}
};
private int delay = 10; //Milliseconds
private Timer timer = new Timer(delay, sortWithDelay);
private boolean sorted(int[] array) {
for(int i = 0; i < array.length - 1; i++) {
if(array[i] > array[i+1]) {
return false;
}
}
return true;
}
}
ArrayVisualizer.java:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Array;
import javax.swing.*;
import java.util.*;
public class ArrayVisualizer extends JPanel {
private static final long serialVersionUID = 1L;
private InsertionSort insertionSort = new InsertionSort();
private SelectionSort selectionSort = new SelectionSort();
protected static int[] array;
private final int REC_WIDTH = 1; //1980 rectangles
private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
private final int[] barColors;
public ArrayVisualizer() {
setBackground(Color.black);
array = new int[NUMBER_OF_RECS];
barColors = new int[NUMBER_OF_RECS];
generateRandom(array);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g.create();
graphics.setColor(Color.white);
for(int i = 0; i < NUMBER_OF_RECS; i++) {
int height = array[i] * 4; //Done for scaling
int recX = i + (REC_WIDTH - 1) * i; //Read fillRect documentation
int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
graphics.fillRect(recX, recY, REC_WIDTH, height);
}
}
//This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
#Override
public Dimension getPreferredSize() {
return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
}
//Creates a random unsorted array with numbers 1-200
protected void generateRandom(int[] array) {
Random number = new Random();
for(int i = 0; i < NUMBER_OF_RECS; i++) {
array[i] = number.nextInt(200);
}
}
protected void shuffle(int[] array) {
generateRandom(array);
}
protected void sort(int[] array) {
selectionSort.sortWithDelay(array);
}
}
InsertionSort.java:
public class InsertionSort {
private int i = 1;
private int j = 0;
public void sortWithDelay(int arr[])
{
int n = arr.length;
if(i < n) {
int key = arr[i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while(j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
++i;
}
}
}
SelectionSort.java:
public class SelectionSort {
private int i = 1;
private int j = 0;
public void sortWithDelay(int arr[])
{
int n = arr.length - 1;
if(i < n) {
int min_index = i;
for(int j = i + 1; j < n; j++) {
if(arr[j] < arr[min_index]) {
min_index = j;
}
}
int temp = arr[min_index];
arr[min_index] = arr[i];
arr[i] = temp;
++i;
}
}
}
Call an action with a swing timer every second that will return an intermediate array. Then paint this intermediate array. Repeat until the array is sorted.
To obtain an intermediate array, modify the InsertionSort from a static method to a class method that will store the variable i so that we can resume sorting when called again.
public class Window implements ActionListener {
//Window width
protected static int WINDOW_WIDTH = 1980;
//Window height
protected static int WINDOW_HEIGHT = 1080;
//This will draw all our rectangles
protected static ArrayVisualizer arrayVisualizer;
//Make a new JFrame
JFrame window = new JFrame();
JButton shuffleBut = new JButton("Shuffle");
JButton startSort = new JButton("Start Sorting");
public Window() {
initWindow();
}
private void addButtons() {
//Shuffle Button
shuffleBut.setBounds(100, 50, 100, 100);
shuffleBut.setBackground(Color.white);
shuffleBut.addActionListener(this);
startSort.setBounds(500, 50, 100, 100);;
startSort.setBackground(Color.white);
startSort.addActionListener(taskPerformer);
window.add(shuffleBut);
window.add(startSort);
}
private void initWindow() {
ImageIcon logo = new ImageIcon();
window = new JFrame();
window.setTitle("JAlgorithms");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
window.setLocationRelativeTo(null);
window.setResizable(false);
addButtons();
arrayVisualizer = new ArrayVisualizer();
window.add(arrayVisualizer);
arrayVisualizer.repaint(); //Will call paint component method
window.pack();
window.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == shuffleBut) {
arrayVisualizer.shuffle(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
}
private int delay = 1000; // delay is 1s
private Timer timer = new Timer(delay, sortWithDelay);
ActionListener taskPerformer = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if(event.getSource() == startSort) {
// Start the timer that shows a swap every second
if(!timer.isRunning()) {
timer.setInitialDelay(0);
timer.start();
}
}
}
};
ActionListener sortWithDelay = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if(isSorted(ArrayVisualizer.array)) {
timer.stop();
return;
}
arrayVisualizer.sort(ArrayVisualizer.array);
arrayVisualizer.repaint();
}
};
private boolean isSorted(int[] arr) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
return false;
}
}
return true;
}
}
public class ArrayVisualizer extends JPanel {
private InsertionSort insertionSort = new InsertionSort();
protected static int[] array;
private final int REC_WIDTH = 1; //1980 rectangles
private final int NUMBER_OF_RECS = Window.WINDOW_WIDTH / REC_WIDTH;
public ArrayVisualizer() {
array = new int[NUMBER_OF_RECS];
generateRandom(array);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics = (Graphics2D) g.create();
graphics.setColor(Color.orange);
for(int i = 0; i < NUMBER_OF_RECS; i++) {
int height = array[i] * 4; //Done for scaling
int recX = i + (REC_WIDTH - 1) * i; //Read fillRect documentation
int recY = Window.WINDOW_HEIGHT - height; //Read fillRect documentation
graphics.fillRect(recX, recY, REC_WIDTH, height);
}
}
//This will return the Dimension of the actual rectangles. i.e the rectangles will only exist when this exists, almost like a canvas in javascript
#Override
public Dimension getPreferredSize() {
return new Dimension(Window.WINDOW_WIDTH, Window.WINDOW_HEIGHT);
}
//Creates a random unsorted array with numbers 1-200
protected void generateRandom(int[] array) {
Random number = new Random();
for(int i = 0; i < NUMBER_OF_RECS; i++) {
array[i] = number.nextInt(200);
}
}
protected void shuffle(int[] array) {
generateRandom(array);
}
protected void sort(int[] array) {
insertionSort.sortWithDelay(array);
}
}
public class InsertionSort {
private int i = 1;
public void sortWithDelay(int arr[])
{
int n = arr.length;
if(i < n) {
int key = arr[i];
int j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while(j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
++i;
}
}
}

Java Snake Game: Apple showing while snake is invisible

I am following a the following video to design a snake game:
https://www.youtube.com/watch?v=91a7ceECNTc
I am following it step by step, but when I run it, the snake does not show on my screen, just the apple. I think I have something wrong when implementing public void paint(Graphics g); Can someone help me?
This is the code my Main class
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame ();
GamePanel panel = new GamePanel();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Snake");
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
This is the Panel class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable, KeyListener{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1000, HEIGHT = 1000; //Dimensions of the panel (Will be set by user input later)
private Thread thread;
private boolean running;
private boolean right = true, left = false, up = false, down = false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 100, yCoor = 100, size = 10;
private int ticks = 0;
public GamePanel() {
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addKeyListener(this);
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
r = new Random();
start();
}
public void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void tick() {
if (snake.size() == 0) {
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++;
if (ticks > 250000) {
if (right) {
xCoor++;
}
if (left) {
xCoor--;
}
if (up) {
yCoor--;
}
if (down) {
yCoor++;
}
ticks = 0;
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
if (snake.size() > size) {
snake.remove(0);
}
}
if (apples.size() == 0) {
int xCoor = r.nextInt(99);
int yCoor = r.nextInt(99);
apple = new Apple(xCoor, yCoor, 10);
apples.add(apple);
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
for (int i = 0; i < WIDTH/10; i++) {
g.drawLine(i*10, 0, i*10, HEIGHT);
}
for (int i = 0; i < HEIGHT/10; i++) {
g.drawLine(0, i*10, HEIGHT, i*10);
}
for (int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
#Override
public void run() {
while (running) {
tick();
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_RIGHT && !left) {
right = true;
up = false;
down = false;
}
if (key == KeyEvent.VK_LEFT && !right) {
left = true;
up = false;
down = false;
}
if (key == KeyEvent.VK_UP && !down) {
up = true;
right = false;
left = false;
}
if (key == KeyEvent.VK_DOWN && !up) {
down = true;
right = false;
left = false;
}
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
The Snake's body parts class:
import java.awt.Color;
import java.awt.Graphics;
public class BodyPart {
public int xCoor, yCoor, width, height;
public BodyPart(int xCoor, int yCoor, int tileSize) {
this.xCoor = xCoor;
this.yCoor = yCoor;
width = tileSize;
height = tileSize;
}
public void tick() {
}
public void draw(Graphics g) {
g.setColor(Color.YELLOW);
g.fillRect(xCoor * width, yCoor * height, width, height);
}
public int getCoorX() {
return xCoor;
}
public void setCoorX (int xCoor) {
this.xCoor = xCoor;
}
public int getCoorY() {
return yCoor;
}
public void setCoorY(int yCoor) {
this.yCoor = yCoor;
}
}
And the Apple's Class:
import java.awt.Color;
import java.awt.Graphics;
public class Apple {
public int xCoor, yCoor, width, height;
public Apple(int xCoor, int yCoor, int tileSize) {
this.xCoor = xCoor;
this.yCoor = yCoor;
width = tileSize;
height = tileSize;
}
public void tick() {
}
public void draw(Graphics g) {
g.setColor(Color.RED);
g.fillRect(xCoor * width, yCoor * height, width, height);
}
public int getxCoor() {
return xCoor;
}
public void setxCoor(int xCoor) {
this.xCoor = xCoor;
}
public int getyCoor() {
return yCoor;
}
public void setyCoor(int yCoor) {
this.yCoor = yCoor;
}
}
Okay, so the issue comes down to some basic maths...
If we take a look at the draw method for BodyPart you will find...
g.fillRect(xCoor * width, yCoor * height, width, height);
Okay, pretty basic, but are all these values actually set too?
If we take a look at the tick method (where BodyParts are created), we can find...
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
Okay, so the width and height is 10, but what about xCoor and yCoor?
They're first initialised as instance fields along with the class...
private int xCoor = 100, yCoor = 100, size = 10;
So, a quick bit of maths tells us the initial location of the BodyPart is 100 * 10 which equals 1000x1000.
If we also take a look at ...
public static final int WIDTH = 1000, HEIGHT = 1000; //Dimensions of the panel (Will be set by user input later)
and
setPreferredSize(new Dimension(WIDTH, HEIGHT));
we can see that the BodyPart is actually been set off screen initially.
So, if we change the initial position to something more like...
private int xCoor = 10, yCoor = 10, size = 10;
you will find your missing snake.
General advice...
You should avoid overriding paint. It's to high in the paint chain and it's to easy to screw it up. Instead, prefer paintComponent instead (and make sure you're calling super.paintComponent). JPanel will then clear the Graphics context for you (with the background color of the component).
Swing is not thread safe. You should not be modify the UI or any state the UI relies on from outside the context of the Event Dispatching Thread.
The current "main" loop is in danger of introducing dirty updates which could cause issues later. See Concurrency in Swing. As a "general" preference, you should consider using a Swing Timer instead. It won't block the EDT, but's "ticks" are generated inside the EDT, making it safer to update the UI and/or its state from within.
You should avoid using "magic numbers" when performing your operations...
for (int i = 0; i < WIDTH/10; i++) {
g.drawLine(i*10, 0, i*10, HEIGHT);
}
Here, WIDTH and HEIGHT may not represent that actual size of the component. Instead make use of JPanel#getWidth and JPanel#getHeight instead.
As a general recommendation, you should avoid using setPreferred/Minimum/MaximumSize, it's to easy for someone else to change these to a state you don't want. Instead, override getPreferred/Minimum/MaximumSize instead, this way you maintain control.

How do I pass an object from another class into the paintComponent method?

My assignment is to create the game "FloodIt." You can play the game here if you need to understand it, but I don't think it's really necessary: http://unixpapa.com/floodit/
I have finished the actual game part of it, but now I need to make a graphical interface for it. I have three classes:
Board.java, which makes the board with random int values and contains several other methods to make the game work:
import java.awt.Color;
import java.util.Random;
/**The board class for the Flood-It game. This class implements a NxN board filled with numColors colors.
* The class implements several methods to allow the playing of the game.
*/
class Board {
//you will probably need to create some field variables
private int size;
private int numColors;
private int[][] board;
private int numOfMoves;
/**Constructs a new sizeXsize board filled where each element on the board is a random number between 0
* and numColors. Also initializes the number of moves to zero.
* #param size -- the size of the board
* #param numColors -- the number of possible entries on the board
*/
public Board(int size,int numColors) {
//TODO finish this constructor
this.size = size;
this.numColors = numColors;
numOfMoves = 0;
board = new int[size][size];
Random rand = new Random();
int randomNum = 0;
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
randomNum = rand.nextInt(this.numColors);
board[count][counter] = randomNum;
}
}
}
/**Updates the board to fill (from the top left corner) with a specified color.
* Filling stops when any other color is hit besides the one in the top left corner.
* Play the game at http://www.lemoda.net/javascript/flood-it/ or http://unixpapa.com/floodit/?sz=14&nc=4
* to get a better understanding of what this method should do.
* You will probably also want to take a look at the algorithm described
* at http://en.wikipedia.org/wiki/Flood_fill which describes what this method should do.
* I recommend the Stack-based recursive implementation. It is a recursive algorithm for
* flooding the board. It is one of the easier ones to implement.
* You are free to have this method call other methods. I would recommend creating a private method that
* this method calls and have that private method be the recursive method.
* A recursive method is one that calls itself.
* #param color -- the new color to flood the board with.
*/
public void move(int replacementColor) {
int targetColor = board[0][0];
recursiveMove(0,0,targetColor,replacementColor);
numOfMoves++;
}
private void recursiveMove(int xCoord, int yCoord, int targetColor, int replacementColor) {
if (targetColor == replacementColor) {
return;
}
if (board[xCoord][yCoord] != targetColor) {
return;
}
board[xCoord][yCoord] = replacementColor;
if (yCoord != size-1) {
recursiveMove(xCoord,yCoord+1,targetColor,replacementColor);
}
if (yCoord != 0) {
recursiveMove(xCoord,yCoord-1,targetColor,replacementColor);
}
if (xCoord != 0) {
recursiveMove(xCoord-1,yCoord,targetColor,replacementColor);
}
if (xCoord != size-1) {
recursiveMove(xCoord+1,yCoord,targetColor,replacementColor);
}
}
/**returns true if the board is not completely filled with a single color.
* Otherwise it returns false.
* #return true if board is all one color
*/
public boolean finished() {
//TODO finish this method
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
if (board[count][counter] != board[0][0]) {
return false;
}
}
}
return true;
}
/**returns how many times the move() method has been called.
* #return the number of times the move() method has been called.
*/
public int numMoves() {
//TODO finish this method
return numOfMoves;
}
/**Returns a string representation of the board. Use tabs between elements of the board.
* And have every row of the board be separated by a newline character.
* Example:
* "1\t0\t3\t\n2\t0\t2\t\n1\t0\t1\t\n"
* #return a String representation of the board
*/
public String toString() {
//TODO finish this method
String boardString = "";
for (int count = 0; count < board.length; count++) {
for (int counter = 0; counter < board.length; counter++) {
boardString += board[count][counter];
boardString += "\t";
}
boardString += "\n";
}
return boardString;
}
}
FloodIt.java, which contains the JFrame lines in order to load the graphical interface, as well as code to actually run the game (it's not entirely finished, as I got stuck):
import java.util.Scanner;
import javax.swing.JFrame;
/**This class is the main method for the Flood-It game as found on many web sites
* ( such as http://www.lemoda.net/javascript/flood-it/ or
http://unixpapa.com/floodit/?sz=14&nc=4 ).
* It prompts the user for the size of the board
* and the number of colors. The user is prompted for the next color until the board is flooded.
* After the game is over it prints how many turns the user took and then asks if they want to play again.
*/
class FloodIt {
private static final int FRAMESIZE = 1000;
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setSize(FRAMESIZE,FRAMESIZE);
frame.setTitle("Brennan's Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicalBoard component = new GraphicalBoard();
frame.add(component);
frame.setVisible(true);
String again="";
int size = 20;
int numColors = 7;
do {
Board board=new Board(size,numColors);
while(!board.finished()) {
//I will change the print statements below into graphical input boxes later
System.out.print("****************\n"+board+"\n****************\n");
System.out.print("What color do you choose? ");
int color=Integer.parseInt(scan.nextLine());
board.move(color);
}
System.out.println("Nice job, you finished in "+board.numMoves());
System.out.print("Would you like to play again (Y/N)? ");
again=scan.nextLine();
} while (again.equalsIgnoreCase("Y"));
scan.close();
}
}
And GraphicalBoard.java, which is supposed to take the values of the 2d array from Board.java and display the board in a graphical interface. Each number that could be in the 2d array corresponds with a color in the Colors array:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
public void paintComponent(Graphics g, int size, Board board) {
String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
Graphics2D g2 = (Graphics2D) g;
int xCoord = 0;
int yCoord = 0;
int colorNum = 0;
String colorOfSquare = "";
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
colorNum = board[count][counter];
colorOfSquare = colors[colorNum];
g2.setColor(Color.colorOfSquare);
Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
xCoord += 50;
}
yCoord += 50;
}
}
}
Two problems:
In GraphicalBoard.java, on the line "colorNum = board[count][counter];", I am getting the error: "The type of expression must be an array type but it resolved to Board."
I seem to be having a problem bring over the already initialized board from the Board.java class into the GraphicalBoard.java class.
In GraphicalBoard.java, on the line "g2.setColor(Color.colorOfSquare);", I am getting the error: "colorOfSquare cannot be resolved or it not a field."
I know the problem, it is supposed to be something like "g2.setColor(Color.BLACK);", but I am going to have the user input the color, so it kind of needs to be a variable and I was hoping to have something cleaner than just an if statement for every color.
Any suggestions? Thanks!
Your Board class contains a member variable int[][] board, but its scope is private. When you call the following:
colorNum = board[count][counter];
This is wrong because the board variable here is an object of Board class. It itself is not the two day array, but it encapsulates int[][] board inside it. So you need to provide a getter method in Board to expose its board member variable like this:
public int[][] getBoard() {
return board;
}
Then in the paintComponent method you can access it as: board.getBoard()[count][counter].
You already seem to have a user inputted color in the colorOfSquare variable. But Graphics2D's setColor method would only accept a variable of type java.awt.Color. Since you have the String representation of the color, you can get its corresponding java.awt.Color value using reflection as mentioned here. The following should work for you:
Color color;
try {
Field field = Color.class.getField(colorOfSquare);
color = (Color) field.get(null);
} catch (Exception e) {
color = null; // Not defined
}
Two answers:
paintComponent ONLY receives a Graphics object. See this link for a short tutorial. If you need to access other objects in this method, make them variables of GraphicalBoard and pass them om during construction.
1.5 You need to access the Board's board, as this is what you are using. So add a getBoard(int i, int j) in class Board. Something like the following (I also added a getSize() method) :
public int getBoard(int i, int j) {
return board[i][j] ;
}
public int getSize() {
return size;
}
Your color colorOfSquare is already defined as a color. The error arises because the Color class doesn't have such a constant. You should just pass the color directly.
Try this:
public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
private Board board;
private int size;
public GraphicalBoard() {
}
public void setBoard(Board board){
this.board = board;
}
public void paintComponent(Graphics g) {
super.paintComponent();
if(board == null) {
throw new RuntimeException("Board not set") ;
}
String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
Graphics2D g2 = (Graphics2D) g;
int xCoord = 0;
int yCoord = 0;
int colorNum = 0;
int size = board.getSize() ;
String colorOfSquare = "";
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
colorNum = board.getBoard(count, counter) ;
colorOfSquare = colors[colorNum];
g2.setColor(colorOfSquare);
Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
xCoord += 50;
}
yCoord += 50;
}
}
In very general terms,
your view, here the drawing JPanel, should contain a reference to the model object via a has-a or "composition" structure
The view should be notified of changes in the model, often via event listeners such as a PropertyChangeListener
The view then extracts the key information and uses that to help decide what to draw. So, if it has a reference to the current Board object, it can make getter method calls from within the paintComponent method.
Other issues in your code:
Make sure to call the super's paintComponent within your override, else you will not clean up "dirty" pixels
Don't mix linear code -- a Scanner based on System.in with GUI code. Make it all one or the other.
For example, in the code below, I use a model class, the class that holds the int[][] board variable and here called BoardModel, and I give it a SwingPropertyChangeSupport object.
class BoardModel {
// .....
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
This object will accept listeners, and will allow me to notify listeners of changes to the model.
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
Then when the model changes, I notify all listeners by calling the support object's firePropertyChange(...) method:
public void selectSquare(int x, int y) {
int replacementValue = board[y][x];
int targetValue = board[0][0];
if (targetValue == replacementValue) {
return;
} else {
recursiveMove(0, 0, targetValue, replacementValue);
numOfMoves++;
support.firePropertyChange(BOARD, null, board); // ***** here
setWin(checkForWin());
}
}
Then in the control, I can add listeners that notify the view of changes:
model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
view.repaint();
String moveCount = "" + model.getNumOfMoves();
controlPanel.setMoveCountFieldText(moveCount);
}
});
model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ((boolean) evt.getNewValue()) {
String message = "Move count: " + model.getNumOfMoves();
String title = "Game Over";
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(view, message, title, messageType);
}
}
});
A working example could look like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.SwingPropertyChangeSupport;
public class BoardFun {
private static final int NUM_COLORS = 6;
private static final int SIZE = 20;
#SuppressWarnings("serial")
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
int size = SIZE;
int numColors = NUM_COLORS;
final BoardModel model = new BoardModel(size , numColors );
final BoardPanel view = new BoardPanel();
final ControlPanel controlPanel = new ControlPanel();
view.setModel(model);
view.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mEvt) {
Point p = mEvt.getPoint();
int row = view.getRow(p);
int col = view.getColumn(p);
model.selectSquare(col, row);
}
});
model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
view.repaint();
String moveCount = "" + model.getNumOfMoves();
controlPanel.setMoveCountFieldText(moveCount);
}
});
model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ((boolean) evt.getNewValue()) {
String message = "Move count: " + model.getNumOfMoves();
String title = "Game Over";
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(view, message, title, messageType);
}
}
});
controlPanel.setResetAction(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
model.reset();
}
});
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(view);
frame.add(controlPanel, BorderLayout.PAGE_START);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class ControlPanel extends JPanel {
private JTextField moveCountField = new JTextField("0", 10);
private JButton resetButton = new JButton();
public ControlPanel() {
add(new JLabel("Move Count:"));
add(moveCountField);
add(resetButton);
}
public void setResetAction(Action action) {
resetButton.setAction(action);
}
public void setMoveCountFieldText(String text) {
moveCountField.setText(text);
}
}
#SuppressWarnings("serial")
class BoardPanel extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = PREF_W;
private BoardModel model;
private Color[] colors;
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
public void setModel(BoardModel model) {
this.model = model;
colors = new Color[model.getNumColors()];
// create colors.length Colors, all of different hue
for (int i = 0; i < colors.length; i++) {
float hue = (float) i / colors.length;
colors[i] = Color.getHSBColor(hue, 1f, 1f);
}
}
// translate point to logical square position
int getRow(Point p) {
return (p.y * model.getBoard().length) / getHeight();
}
int getColumn(Point p) {
return (p.x * model.getBoard()[0].length) / getWidth();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // always call the super's method
if (model == null) {
return;
}
int board[][] = model.getBoard();
int height = getHeight() / board.length;
int width = getWidth() / board[0].length;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
Color color = colors[board[i][j]];
g.setColor(color);
int x = (j * getWidth()) / board[0].length;
int y = (i * getHeight()) / board.length;
g.fillRect(x, y, width, height);
}
}
}
}
class BoardModel {
public static final String BOARD = "board";
public static final String WIN = "win";
private int[][] board;
private int numColors;
private Random random = new Random();
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
private int numOfMoves = 0;
private boolean win = false;
public BoardModel(int size, int numColors) {
board = new int[size][size];
this.numColors = numColors;
reset();
}
public void reset() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
board[i][j] = random.nextInt(numColors);
}
}
numOfMoves = 0;
support.firePropertyChange(BOARD, null, board);
setWin(false);
}
public int[][] getBoard() {
return board;
}
public int getNumOfMoves() {
return numOfMoves;
}
public int getNumColors() {
return numColors;
}
public void setWin(boolean win) {
boolean oldValue = this.win;
boolean newValue = win;
this.win = win;
support.firePropertyChange(WIN, oldValue, newValue);
}
public boolean isWin() {
return win;
}
public void selectSquare(int x, int y) {
int replacementValue = board[y][x];
int targetValue = board[0][0];
if (targetValue == replacementValue) {
return;
} else {
recursiveMove(0, 0, targetValue, replacementValue);
numOfMoves++;
support.firePropertyChange(BOARD, null, board);
setWin(checkForWin());
}
}
public boolean checkForWin() {
int value = board[0][0];
for (int[] row : board) {
for (int cell : row) {
if (cell != value) {
return false;
}
}
}
return true;
}
private void recursiveMove(int i, int j, int targetValue, int replacementValue) {
int currentValue = board[i][j];
if (currentValue != targetValue || currentValue == replacementValue) {
return;
}
board[i][j] = replacementValue;
int rowMin = Math.max(0, i - 1);
int rowMax = Math.min(board.length - 1, i + 1);
int colMin = Math.max(0, j - 1);
int colMax = Math.min(board[i].length - 1, j + 1);
for (int i2 = rowMin; i2 <= rowMax; i2++) {
if (i2 != i) {
recursiveMove(i2, j, targetValue, replacementValue);
}
}
for (int j2 = colMin; j2 <= colMax; j2++) {
if (j2 != j) {
recursiveMove(i, j2, targetValue, replacementValue);
}
}
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
}

KeyAdapter input in java not working

I just wrote some code to make my player move in my little maze game, but nothing happens. Also my maze is not drawn correct as in the matrix input. I don't figure out why is wrong this code...any help is well appeciated.
Thank you!
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.*;
public class Main extends JPanel {
private static Image white;
private static Image black;
private static Image finish;
private static Image player;
private static int x = 1;
private static int y = 1;
private String matrix[][];
public Main() {
addKeyListener(new Keys());
setFocusable(true);
}
public static String[][] load(String input) {
List<String[]> rows = new ArrayList<>();
try (Scanner scanner = new Scanner(input)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] cols = new String[line.length()];
for (int i = 0; i < cols.length; i++) {
cols[i] = line.substring(i, i + 1);
}
rows.add(cols);
}
}
return rows.toArray(new String[rows.size()][]);
}
public static JFrame buildFrame() {
JFrame frame = new JFrame("Labyrinth Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(900, 950);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
return frame;
}
public void moveUp() {
x += 0;
y += -1;
}
public void moveLeft() {
x += -1;
y += 0;
}
public void moveDown() {
x += 0;
y += 1;
}
public void moveRight() {
x += 1;
y += 0;
}
public class Keys extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
// repaint();
if (keycode == KeyEvent.VK_W) {
if (!matrix[getX()][getY() - 1].equals("1")) {
moveUp();
}
}
if (keycode == KeyEvent.VK_A) {
if (!matrix[getX() - 1][getY()].equals("1")) {
moveLeft();
}
}
if (keycode == KeyEvent.VK_S) {
if (!matrix[getX()][getY() + 1].equals("1")) {
moveDown();
}
}
if (keycode == KeyEvent.VK_D) {
if (!matrix[getX() + 1][getY()].equals("1")) {
moveRight();
}
}
}
#Override
public void keyReleased(KeyEvent event) {
}
}
public static void main(String[] args) {
String input = "1111111111111111111111111111111111111111111\n"
+ "1000000010001000001000000010000000100000001\n"
+ "1010111010101010101111101011111010111111101\n"
+ "1010001010100010100000001010000010000010001\n"
+ "1011101010111110101111111010111111111010111\n"
+ "1000101010100000101000001000100010000010001\n"
+ "1011101011101011111011101111111010111110101\n"
+ "1010001000001010000010100000001010000010101\n"
+ "1010111111111010111110111111101011111011101\n"
+ "1010100000100010100000000000101000000000101\n"
+ "1110101111101110111110111011101011111110101\n"
+ "1000100000000010000010100010001000100010001\n"
+ "1011111111111111111011101010111111101011101\n"
+ "1000000000000000100010001010000000001010001\n"
+ "1011111111111011101110111011111111111010111\n"
+ "1000100010001000001010001000100000001010101\n"
+ "1110101011101111111010101110111110111010101\n"
+ "1000101010001000100000101000100000100010001\n"
+ "1011101010111010101111101011101110101111111\n"
+ "1000001010000010000000101000001000100010001\n"
+ "1111111011111110111111101111111011111010101\n"
+ "1000001010000010100010001000000010000010101\n"
+ "1011111010111011101010111011111110101110101\n"
+ "1010000010001010001010001000100000101010101\n"
+ "1010111111101010111011101111101111101011101\n"
+ "1000100000001010101010001000100010101000101\n"
+ "1011111011111010101010111010111010101011101\n"
+ "1010000010001000101010000010001010001000001\n"
+ "1010101110101111101011101111101011111010101\n"
+ "1010101000101000001000101000001000000010101\n"
+ "1011101011111010111110111011101111111110111\n"
+ "1000001000000010000000000010000000000010021\n"
+ "1111111111111111111111111111111111111111111\n";
String[][] matrix = load(input);
JFrame frame = buildFrame();
ImageIcon img = new ImageIcon("C:/Users/Desktop/black20.png");
black = img.getImage();
img = new ImageIcon("C:/Users/Desktop/gri20.png");
white = img.getImage();
img = new ImageIcon("C:/Users/Desktop/finish20.png");
finish = img.getImage();
img = new ImageIcon("C:/Users/Desktop/smiley20.png");
player = img.getImage();
// frame.add(new Player());
JPanel pane = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j].equals("1")) {
g.drawImage(black, i * 20, j * 20, null);
}
if (matrix[i][j].equals("0")) {
g.drawImage(white, i * 20, j * 20, null);
}
if (matrix[i][j].equals("2")) {
g.drawImage(finish, i * 20, j * 20, null);
}
}
}
g.drawImage(player, x * 20, y * 20, null);
}
};
frame.add(pane);
frame.add(new Main());
}
}
It should look like:
Problems/Suggestions:
You're adding more than one component to the JFrame in a default fashion. Since the JFrame's contentPane uses BorderLayout, only one component will display, the last one added, and the other will be completely covered and will remain invisible.
Your Main JPanel is not being used as a true JPanel. Nothing is being added to it, and in fact it looks like it should be a logical class and not a component class.
Rather than using KeyListeners, which are very fidgety when it comes to focus problems, use Key Bindings which will allow you to get around focus issues in a clean and higher level way.
Don't override the JPanel's paint method but rather its paintComponent method as this will give you several advantages, including default use of double buffering for your animation.
Don't give component classes a public int getX() and public int getY() method without care since these override key methods that place the component within its container. Since the Main class shouldn't even extend JPanel, this will end up to be a non-issue for your code, but in the future, it would mess your program up.
When you run into similar problems, such as a KeyListener not working, remove the issue from your big program and try to reproduce it in a small separate program. This will give you a much cleaner environment for helping you to isolate and understand your problem and thereby help you fix it.
Your program is mis-using the static modifier. Your x and y fields should not be static and should not be accessed in a static way.
You've got way too much code within your main method, which is one of the reasons why you likely made x and y static, because you were forced to do so since you're trying to access them within main. The solution is not to make the fields static but to get all that code out of the static world and into the instance world.
Edit
For some reason the question intrigued me, and so I decided to try to M-V-C or Model-View-Controller it if possible and see what I could come up with. So here goes a bunch of classes that sort of work, beginning with a text file that holds the data.
The GUI looks like:
It must be in the same location as the class files since it is obtained as a resource and must have the file name "input.txt"
1111111111111111111111111111111111111111111
1000000010001000001000000010000000100000001
1010111010101010101111101011111010111111101
1010001010100010100000001010000010000010001
1011101010111110101111111010111111111010111
1000101010100000101000001000100010000010001
1011101011101011111011101111111010111110101
1010001000001010000010100000001010000010101
1010111111111010111110111111101011111011101
1010100000100010100000000000101000000000101
1110101111101110111110111011101011111110101
1000100000000010000010100010001000100010001
1011111111111111111011101010111111101011101
1000000000000000100010001010000000001010001
1011111111111011101110111011111111111010111
1000100010001000001010001000100000001010101
1110101011101111111010101110111110111010101
1000101010001000100000101000100000100010001
1011101010111010101111101011101110101111111
1000001010000010000000101000001000100010001
1111111011111110111111101111111011111010101
1000001010000010100010001000000010000010101
1011111010111011101010111011111110101110101
1010000010001010001010001000100000101010101
1010111111101010111011101111101111101011101
1000100000001010101010001000100010101000101
1011111011111010101010111010111010101011101
1010000010001000101010000010001010001000001
1010101110101111101011101111101011111010101
1010101000101000001000101000001000000010101
1011101011111010111110111011101111111110111
1000001000000010000000000010000000000010021
1111111111111111111111111111111111111111111
Next the main program, the one that creates the model, the view, and the controller, hooks them all together, and then displays the GUI:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
* link: http://stackoverflow.com/a/41418250/522444
*
* #author Pete
*
*/
#SuppressWarnings("serial")
public class Main2 extends JPanel {
private View mainPanel;
public Main2(MatrixModel matrixModel) {
mainPanel = new View(matrixModel);
new Controller(matrixModel, mainPanel);
setLayout(new BorderLayout());
add(mainPanel, BorderLayout.CENTER);
}
private static void createAndShowGui(MatrixModel model) {
Main2 mainPanel = new Main2(model);
JFrame frame = new JFrame("Main2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
final MatrixModel model = MatrixUtil.getInput(MatrixUtil.PATH_TO_RSC);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui(model);
}
});
}
}
Next a utility class with static methods for reading in the text file as a resource and converting it into a Model object:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MatrixUtil {
// again this text file must be in the jar file or the code base
// at the same location as the class / java files
public static final String PATH_TO_RSC = "input.txt";
public static MatrixModel getInput(String resourcePath) {
InputStream is = MatrixUtil.class.getResourceAsStream(resourcePath);
if (is == null) {
String text = "resourcePath is not found and not loading text: " + resourcePath;
throw new IllegalArgumentException(text);
}
return getInput(is);
}
public static MatrixModel getInput(InputStream is) {
MatrixModel model = null;
try (Scanner scan = new Scanner(is)) {
List<List<MatrixPosition>> listOfLists = new ArrayList<>();
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.trim().isEmpty()) {
continue;
}
List<MatrixPosition> list = new ArrayList<>();
for (char c : line.toCharArray()) {
list.add(MatrixPosition.getMatrixPosition(String.valueOf(c)));
}
listOfLists.add(list);
}
MatrixPosition[][] grid = new MatrixPosition[listOfLists.size()][];
for (int i = 0; i < grid.length; i++) {
List<MatrixPosition> list = listOfLists.get(i);
grid[i] = list.toArray(new MatrixPosition[] {});
}
model = new MatrixModel(grid, new SpritePosition(1, 1));
}
return model;
}
}
Basic enum to represent direction:
public enum Direction {
UP, DOWN, LEFT, RIGHT
}
Another enum to represent a location point in the grid, and whether it is a wall, a coridor or the end as well as static methods to convert from number to MatrixPosition:
public enum MatrixPosition {
WALL(1), CORRIDOR(0), END(2);
private int value;
private MatrixPosition(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static MatrixPosition getMatrixPosition(int value) {
for (MatrixPosition position : MatrixPosition.values()) {
if (value == position.getValue()) {
return position;
}
}
String text = "value of " + value;
throw new IllegalArgumentException(text);
}
public static MatrixPosition getMatrixPosition(String strValue) {
int value = -1;
try {
value = Integer.parseInt(strValue);
} catch (NumberFormatException e) {
String text = "NumberFormatException for strValue " + strValue;
throw new IllegalAccessError(text);
}
return getMatrixPosition(value);
}
}
A class to represent a position of our sprite, similar to the java.awt.Point class but with row and column fields instead of x and y:
public class SpritePosition {
int row;
int column;
public SpritePosition(int row, int column) {
this.row = row;
this.column = column;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getColumn() {
return column;
}
public void setColumn(int column) {
this.column = column;
}
public void setRowColumn(int row, int column) {
this.row = row;
this.column = column;
}
}
The model has property change support code so that it can notify any classes listening to it of any changes in its state. The controller will be the class listening to the model
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
public class MatrixModel {
public static final String SPRITE_POINT = "sprite point";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private MatrixPosition[][] grid;
private SpritePosition spritePosition;
public MatrixModel(MatrixPosition[][] grid, SpritePosition spritePosition) {
this.grid = grid;
this.spritePosition = spritePosition;
}
public int getRows() {
return grid.length;
}
public int getColumns() {
return grid[0].length;
}
public MatrixPosition getPosition(SpritePosition p) {
return getPosition(p.row, p.column);
}
public MatrixPosition getPosition(int row, int col) {
return grid[row][col];
}
public void setSpritePoint(SpritePosition spritePosition) {
SpritePosition oldValue = this.spritePosition;
SpritePosition newValue = spritePosition;
this.spritePosition = spritePosition;
pcSupport.firePropertyChange(SPRITE_POINT, oldValue, newValue);
}
public boolean isPointValid(SpritePosition p) {
if (p.column < 0 || p.row < 0) {
return false;
}
if (p.column >= grid[0].length || p.row >= grid.length) {
return false;
}
return grid[p.row][p.column] == MatrixPosition.CORRIDOR;
}
public boolean isMoveValid(Direction direction) {
int row = spritePosition.row;
int column = spritePosition.column;
switch (direction) {
case UP:
return isPointValid(new SpritePosition(row - 1, column));
case DOWN:
return isPointValid(new SpritePosition(row + 1, column));
case LEFT:
return isPointValid(new SpritePosition(row, column - 1));
case RIGHT:
return isPointValid(new SpritePosition(row, column + 1));
default:
return false;
}
}
public void move(Direction direction) {
if (!isMoveValid(direction)) {
String text = "For move to " + direction + "spritePosition: " + spritePosition;
throw new IllegalArgumentException(text);
}
int row = spritePosition.row;
int column = spritePosition.column;
switch (direction) {
case UP:
setSpritePoint(new SpritePosition(row - 1, column));
break;
case DOWN:
setSpritePoint(new SpritePosition(row + 1, column));
break;
case LEFT:
setSpritePoint(new SpritePosition(row, column - 1));
break;
case RIGHT:
setSpritePoint(new SpritePosition(row, column + 1));
break;
default:
break;
}
}
public SpritePosition getSpritePosition() {
return spritePosition;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
}
Controller class, one that sets up key bindings on the view so that it can listen for key presses, checks if they represent a valid move, and if so then tells the model to make the move. It also adds a listener to the model so that when its state changes, it will tell the view to move the sprite
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
public class Controller {
private MatrixModel model;
private View view;
private Map<Direction, KeyStroke> dirKeyMap = new EnumMap<>(Direction.class);
public Controller(MatrixModel model, View view) {
this.model = model;
this.view = view;
dirKeyMap.put(Direction.DOWN, KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
dirKeyMap.put(Direction.UP, KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
dirKeyMap.put(Direction.LEFT, KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
dirKeyMap.put(Direction.RIGHT, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
model.addPropertyChangeListener(new ModelListener());
setUpKeyBindings(view);
}
private void setUpKeyBindings(View view) {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = view.getInputMap(condition);
ActionMap actionMap = view.getActionMap();
for (Direction dir : Direction.values()) {
KeyStroke keyStroke = dirKeyMap.get(dir);
hookUp(inputMap, actionMap, dir, keyStroke);
}
}
private void hookUp(InputMap inputMap, ActionMap actionMap, Direction dir, KeyStroke key) {
inputMap.put(key, key.toString());
actionMap.put(key.toString(), new MoveAction(dir, model));
}
public MatrixModel getModel() {
return model;
}
public View getView() {
return view;
}
class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (MatrixModel.SPRITE_POINT.equals(evt.getPropertyName())) {
SpritePosition p = model.getSpritePosition();
view.setSpritePoint(p);
}
}
}
}
#SuppressWarnings("serial")
class MoveAction extends AbstractAction {
private Direction dir;
private MatrixModel model;
public MoveAction(Direction dir, MatrixModel model) {
super(dir.toString());
this.dir = dir;
this.model = model;
}
public void actionPerformed(ActionEvent e) {
if (model.isMoveValid(dir)) {
model.move(dir);
}
}
}
Finally the View class, that extends JPanel, that displays the maze and the sprite:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class View extends JPanel {
private static final int CELL_WIDTH = 20;
private static final Color CORRIDOR_COLOR = Color.LIGHT_GRAY;
private static final Color WALL_COLOR = Color.DARK_GRAY;
private static final Color END_COLOR = Color.ORANGE;
private static final Color SPRITE_COLOR = Color.RED;
private static final int GAP = 1;
private BufferedImage gridImg = null;
private SpritePosition spritePosition;
private JPanel mainPanel = new JPanel();
public View(MatrixModel matrixModel) {
gridImg = createImg(matrixModel);
spritePosition = matrixModel.getSpritePosition();
}
public JPanel getMainPanel() {
return mainPanel;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || gridImg == null) {
return super.getPreferredSize();
}
int prefW = gridImg.getWidth();
int prefH = gridImg.getHeight();
return new Dimension(prefW, prefH);
}
public void setSpritePoint(SpritePosition spritePosition) {
this.spritePosition = spritePosition;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (gridImg != null) {
g.drawImage(gridImg, 0, 0, this);
}
g.setColor(SPRITE_COLOR);
int y = spritePosition.row * CELL_WIDTH + GAP;
int x = spritePosition.column * CELL_WIDTH + GAP;
g.fillRect(x, y, CELL_WIDTH - 2 * GAP, CELL_WIDTH - 2 * GAP);
}
private BufferedImage createImg(MatrixModel matrixModel) {
BufferedImage img = null;
if (matrixModel != null && matrixModel.getRows() > 0) {
int w = matrixModel.getColumns() * CELL_WIDTH;
int h = matrixModel.getRows() * CELL_WIDTH;
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
for (int row = 0; row < matrixModel.getRows(); row++) {
for (int col = 0; col < matrixModel.getColumns(); col++) {
MatrixPosition position = matrixModel.getPosition(row, col);
Color c = null;
switch (position) {
case CORRIDOR:
c = CORRIDOR_COLOR;
break;
case WALL:
c = WALL_COLOR;
break;
case END:
c = END_COLOR;
break;
}
g2.setColor(c);
int x = col * CELL_WIDTH;
int y = row * CELL_WIDTH;
g2.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
}
}
g2.dispose();
}
return img;
}
}

java multiple graphics [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Okay so I have been working on this code for awhile that shows how the sorting algorithms work. Right now I have it working where it sorts multiple graphs with the same sort but I need each graph to do a different sort at the same time. I have been researching and trying to solve this for days and now I just have tunnel vision. I'll post my code in case my explanation was confusing. I feel like this could benefit a lot of people working with java graphics and any help would be appreciated.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Scanner;
public class Sort extends Applet {
/** Constructor. Only for starting the sorting animation as applet. */
public Sort() {}
/** For starting the sorting animation as application. */
public static void main(String[] argv) {
Frame _aFrame = new Frame("Sort Animations");
_aFrame.setBackground(Color.white);
_aFrame.setPreferredSize(new Dimension(2700,1000));
Scanner in = new Scanner(System.in);
int sizeOfArray;
System.out.println("How many numbers do you want to sort?");
sizeOfArray = in.nextInt();
_aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
}
);
_aFrame.setLayout(new BorderLayout());
_aFrame.add(new SortPanel(sizeOfArray));
_aFrame.pack();
_aFrame.setVisible(true);
}
}
class SortPanel extends Panel implements Runnable {
/** button triggering the sort animation */
private Button aSortButton_ = new Button("sort");
/** choice item for selecting the sort algorithm */
private Choice aChoice_ = new Choice();
/** component for handling the animation */
private ArrayCanvas anArrayCanvas_;
/////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*
* #param length no of elements of the array
* #param aBarColor the color the elements representing bars will be drawn in
*
* #exception IllegalArgumentException if the array <code>length</code> is
* to big to display (ie <code>length</code> is bigger than
* <code>BAR_WIDTH</code> or <code>BAR_HEIGHT</code>).
*/
public SortPanel(int arraySize) {
setLayout(new BorderLayout());
aSortButton_.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Thread(SortPanel.this).start();
}
}
);
anArrayCanvas_ = new ArrayCanvas(arraySize);
for (int i=0; i<ArrayCanvas.SORT_NAMES.length; ++i)
aChoice_.add(ArrayCanvas.SORT_NAMES[i]);
// add buttons at top:
Panel _aTopPanel = new Panel();
_aTopPanel.add(aSortButton_);
add(_aTopPanel, BorderLayout.NORTH);
// add choice and ArrayCanvas below:
Panel _aPanel = new Panel();
_aPanel.setLayout(new BorderLayout());
Panel _aChoicePanel = new Panel();
_aChoicePanel.add(aChoice_);
_aPanel.add(_aChoicePanel, BorderLayout.NORTH);
_aPanel.add(anArrayCanvas_, BorderLayout.CENTER);
add(_aPanel, BorderLayout.CENTER);
Panel _aBottomPanel = new Panel();
add(_aBottomPanel, BorderLayout.SOUTH);
}
/////////////////////////////////////////////////////////////////////////////
/** Runs the sorting animation. */
public void run() {
aSortButton_.setEnabled(false);
double time = System.currentTimeMillis();
anArrayCanvas_.sort(aChoice_.getSelectedItem());
aSortButton_.setEnabled(true);
}
}
class ArrayCanvas extends Canvas {
/** Labels of available sorting algorithms. */
public final static String[] SORT_NAMES = { "bubble sort", "insertion sort", "shell sort", "heap sort", "merge sort", "quick sort",};
/** offset between bars and border in x-directions (left and right) */
public final static int OFFSET_X = 5;
/** offset between bars and border in y-directions (top and bottom) */
public final static int OFFSET_Y = 5;
/** horizontal size of all bars together */
public final static int BAR_WIDTH = 350;
/** (max) vertical horizontal size of bars together */
public final static int BAR_HEIGHT = 250;
/** milliseconds to sleep after a swap in the sorting animation */
public final static int SLEEP_AFTER_SWAP = 20;
/** used for random permutation of the array elements */
private static Random aRandom_ = new Random(System.currentTimeMillis());
/** the array to display */
private int[] anArrayOfInt_;
/** offscreen buffer */
private Image image_;
/** graphics of the offscreen buffer */
private Graphics offscreenGraphics_;
/////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*
* #param length no of elements of the array
*
* #exception IllegalArgumentException if the array <code>length</code> is
* to big to display (ie <code>length</code> is bigger than
* <code>BAR_WIDTH</code> or <code>BAR_HEIGHT</code>).
*/
public ArrayCanvas(int length) {
if (length > BAR_WIDTH || length > BAR_HEIGHT)
throw new IllegalArgumentException("array to big: "+length);
anArrayOfInt_ = new int[length];
for (int i=0; i<length; ++i)
anArrayOfInt_[i] = i+1;
permute();
addMouseListener(
new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
repaint();
}
}
);
}
/////////////////////////////////////////////////////////////////////////////
// overloaded for double buffering
public void update(Graphics aGraphics) {
paint(aGraphics);
}
/** displays the array */
public void paint(Graphics aGraphics) {
int _deltaX = 0;
int w = BAR_WIDTH / anArrayOfInt_.length;
if (w > 1) {
--w;
++_deltaX;
}
int _heightFactor = BAR_HEIGHT / anArrayOfInt_.length;
if (offscreenGraphics_ == null) {
image_ = createImage(getSize().width, getSize().height);
offscreenGraphics_ = image_.getGraphics();
}
offscreenGraphics_.setColor(getBackground());
offscreenGraphics_.fillRect(0, 0, getSize().width-1, getSize().height-1);
offscreenGraphics_.setColor(Color.black);
//offscreenGraphics_.drawRect(0, 0, getSize().width-1, getSize().height-1);
offscreenGraphics_.translate(OFFSET_X, OFFSET_Y);
for (int i=0; i<anArrayOfInt_.length; ++i) {
int h = _heightFactor*anArrayOfInt_[i];
offscreenGraphics_.setColor(Color.blue);
offscreenGraphics_.fillRect((w+_deltaX)*i, BAR_HEIGHT-h, w, h);
if(anArrayOfInt_[i]==(i+1)){
offscreenGraphics_.setColor(Color.red);
offscreenGraphics_.fillRect((w+_deltaX)*i, BAR_HEIGHT-h, w, _heightFactor);
}
}
offscreenGraphics_.translate(-OFFSET_X, -OFFSET_Y);
aGraphics.drawImage(image_, 0, 0, this);
aGraphics.drawImage(image_, 475, 0, this);
aGraphics.drawImage(image_, 950, 0, this);
aGraphics.drawImage(image_, 0, 350, this);
aGraphics.drawImage(image_, 475, 350, this);
aGraphics.drawImage(image_, 950, 350, this);
}
public Dimension getMinimumSize() {
return new Dimension(BAR_WIDTH+2*OFFSET_X, BAR_HEIGHT+2*OFFSET_Y);
}
public Dimension getPreferredSize() {
return getMinimumSize();
}
///////////////////////////////////////////////////
/** random permutation of array entries */
public void permute() {
for (int i=anArrayOfInt_.length-1; i>0; --i) {
int j = Math.abs(aRandom_.nextInt()) % (i+1);
swap(anArrayOfInt_,i,j);
}
}
/** animated sort */
public void sort(String aSortNameString) {
mySort(aSortNameString);
}
///////////////////////////////////////////////////
private void mySort(String aSortNameString) {
if (aSortNameString.equals("bubble sort")) {
bubbleSort(anArrayOfInt_);
}
if (aSortNameString.equals("insertion sort")) {
insertionSort(anArrayOfInt_);
}
if (aSortNameString.equals("selection sort")) {
selectionSort(anArrayOfInt_);
}
if (aSortNameString.equals("shell sort")) {
shellSort(anArrayOfInt_);
}
if (aSortNameString.equals("heap sort")) {
heapSort(anArrayOfInt_);
}
if (aSortNameString.equals("merge sort")) {
mergeSort(anArrayOfInt_, 0, anArrayOfInt_.length-1);
}
if (aSortNameString.equals("quick sort")) {
qSort(anArrayOfInt_, 0, anArrayOfInt_.length-1);
}
}
/**
* swaps the two array elements, redisplays the array in its canvas,
* and waits a moment.
*/
private void swap(int[] anArrayOfInt, int i, int j) {
int x = anArrayOfInt[i];
anArrayOfInt[i] = anArrayOfInt[j];
anArrayOfInt[j] = x;
repaint();
try { Thread.sleep(SLEEP_AFTER_SWAP); } catch (InterruptedException e) {}
}
/////////////////////////////////////////////////////////////////////////////
// SORTING ALGORITHMS //
/////////////////////////////////////////////////////////////////////////////
/** bubble sort */
private void bubbleSort(int[] anArrayOfInt) {
for (int i=0; i<anArrayOfInt.length; ++i)
for (int j=1; j<anArrayOfInt.length-i; ++j)
if (anArrayOfInt[j-1]>anArrayOfInt[j]) {
swap(anArrayOfInt, j-1, j);
}
}
/** insertion sort */
private void insertionSort(int[] anArrayOfInt) {
for (int i=0; i<anArrayOfInt.length; ++i)
for (int j=i-1; j>=0 && anArrayOfInt[j]>anArrayOfInt[j+1]; --j)
swap(anArrayOfInt, j, j+1);
}
/** selection sort */
private void selectionSort(int[] anArrayOfInt) {
for (int i=0; i<anArrayOfInt.length-1; ++i) {
for (int j=i+1; j<anArrayOfInt.length; ++j)
if (anArrayOfInt[j] < anArrayOfInt[i])
swap(anArrayOfInt, i, j);
}
}
/** shell sort */
private void shellSort(int[] anArrayOfInt) {
// TODO: calculate needed STEPS-elements instead of using an array
// (STEPS[i+1] = 3*STEPS[i]+1)
for (int i=0; i<STEPS.length; ++i) {
int _delta = STEPS[i];
if (_delta >= anArrayOfInt.length)
continue;
for (int j=_delta; j<anArrayOfInt.length; ++j)
for (int k=j; k-_delta>=0 && anArrayOfInt[k]<anArrayOfInt[k- _delta];
k-=_delta)
swap(anArrayOfInt, k, k-_delta);
}
}
/** used by shell sort */
private final static int[] STEPS = { 1093, 364, 121, 40, 13, 4, 1 };
/** heap sort */
private void heapSort(int[] anArrayOfInt) {
int r = anArrayOfInt.length-1;
for (int l = anArrayOfInt.length/2 ; l>=0; --l)
sift(anArrayOfInt, l, r);
while (r > 0) {
swap(anArrayOfInt, 0, r);
sift(anArrayOfInt, 0, --r);
}
}
/** auxiliary function for heap sort. */
private void sift(int[] anArrayOfInt, int l, int r) {
if (r==l)
return;
int i = l, j = 2*l;
int x = anArrayOfInt[i];
if (j<r && anArrayOfInt[j]<anArrayOfInt[j+1])
++j;
while (j<=r && x<=anArrayOfInt[j]) {
swap(anArrayOfInt, i, j);
i = j; j = 2*j;
if (j<r && anArrayOfInt[j]<anArrayOfInt[j+1])
++j;
}
}
/** quick sort (pivot=(l+r)/2)*/
private void qSort(int[] anArrayOfInt, int l, int r) {
if (l >= r)
return;
swap(anArrayOfInt, l, (l+r)/2); // TODO: more clever pivot
int _last = l;
for (int i=l+1; i<=r; ++i)
if (anArrayOfInt[i] < anArrayOfInt[l])
swap(anArrayOfInt, ++_last, i);
swap(anArrayOfInt, l, _last);
qSort(anArrayOfInt, l, _last-1);
qSort(anArrayOfInt, _last+1, r);
}
/** merge sort */
private void mergeSort(int[] anArrayOfInt, int l, int r) {
int[][] B = new int[2][r+1];
mergeSort16(anArrayOfInt, B, l, r);
}
private void mergeSort16(int[] anArrayOfInt, int[][] B, int l, int r) {
if (l >= r)
return;
int _last = (l+r)/2;
mergeSort16(anArrayOfInt, B, l, _last);
mergeSort16(anArrayOfInt, B, _last+1, r);
merge6(anArrayOfInt, B, l, _last, r);
}
/** auxiliary function for merge sort */
protected void merge6(int[] anArrayOfInt, int[][] B, int l, int q, int r) {
for (int i=l;i<=q;i++) {
B[0][i] = i;
B[1][i] = i;
}
for (int i=r;i>q;i--) {
B[0][i] = r+q+1-i;
B[1][i] = r+q+1-i;
}
int i = l;
int j = r;
for (int k=l; k<r;k++) {
int s = B[0][i];
int t = B[0][j];
if (anArrayOfInt[s]<=anArrayOfInt[t]) {
i++;
} else {
s = t;
j--;
}
swap(anArrayOfInt, s, k);
t = B[1][k];
B[0][t] = s;
B[1][s] = t;
}
}
}
For each sort graph you need some kind of model, which should hold the current state of each sort. This would probably mean adding your list of ints to a separate list per sort.
You would also need some kind of mechanism that would allow you to loop through each sort algorithm and tell it to move to the next step in its algorithm, thus allowing you to control when each sort algorithm update and therefore control when the screen is updated.
Updated
Based on a comment from the OP, basically, I've ripped out the sort algorithm as a separate interface. Each algorithm would need to extend from this interface, but it provides the basic requirements to allow the UI to render the sort animation.
Bellow is basic implementation, while it's based on Swing, if required, it wouldn't be a stretch to get it to work with AWT.
import java.awt.BorderLayout;
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.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestSort {
public static void main(String[] args) {
new TestSort();
}
public TestSort() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
SortPane sortPane = new SortPane();
int values[] = new int[10];
for (int index = 0; index < values.length; index++) {
values[index] = (int)Math.round(Math.random() * 100f);
}
BubbleSort sorter = new BubbleSort(values);
sortPane.setSorter(sorter);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(sortPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
sorter.sort();
}
});
}
public class SortPane extends JPanel {
private Sorter sorter;
private ChangeHandler changeHandler;
private int maxValue;
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int values[] = getSorter().getValues();
int width = getWidth() - 1;
int height = getHeight() - 1;
int colWidth = Math.round((float)width / (float)values.length);
int x = 0;
Color fill = Color.YELLOW;
Color highlight = null;
switch (getSorter().getState()) {
case Sorting:
fill = Color.BLUE;
highlight = Color.RED;
break;
case Done:
fill = Color.GREEN;
break;
}
for (int index = 0; index < values.length; index++) {
g2d.setColor(fill);
int value = values[index];
int colHeight = (int)((float)height * ((float)value / (float)maxValue));
g2d.fillRect(x, height - colHeight, colWidth - 1, colHeight);
if (getSorter().isActiveIndex(index) && highlight != null) {
g2d.setColor(highlight);
g2d.drawRect(x, height - colHeight, colWidth - 1, colHeight);
}
x += colWidth;
}
g2d.dispose();
}
public Sorter getSorter() {
return sorter;
}
public void setSorter(Sorter value) {
if (sorter != value) {
if (sorter != null) {
sorter.removeChangeListener(getChangeHandler());
}
sorter = value;
if (sorter != null) {
sorter.addChangeListener(getChangeHandler());
maxValue = 0;
for (int intValue : sorter.getValues()) {
maxValue = Math.max(maxValue, intValue);
}
}
repaint();
}
}
public ChangeHandler getChangeHandler() {
if (changeHandler == null) {
changeHandler = new ChangeHandler();
}
return changeHandler;
}
public class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
}
}
public interface Sorter {
public enum State {
Waiting,
Sorting,
Done
}
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
public int[] getValues();
public void sort();
public State getState();
public boolean isActiveIndex(int index);
}
public abstract class AbstracSorter implements Sorter {
private List<ChangeListener> listeners;
private int[] values;
private State state = State.Waiting;
private List<Integer> activeIndices;
public AbstracSorter(int[] values) {
this.values = values;
listeners = new ArrayList<>(25);
activeIndices = new ArrayList<>(2);
}
#Override
public State getState() {
return state;
}
public void setState(State value) {
if (value != state) {
state = value;
fireStateChanged();
}
}
#Override
public int[] getValues() {
return values;
}
#Override
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
#Override
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
protected void fireStateChanged() {
if (listeners.size() > 0) {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
}
#Override
public boolean isActiveIndex(int index) {
return activeIndices.contains(index);
}
protected void setActiveIndicies(int lower, int upper) {
activeIndices.clear();
activeIndices.add(lower);
activeIndices.add(upper);
fireStateChanged();
}
protected void swap(int[] anArrayOfInt, int i, int j) {
setActiveIndicies(i, j);
int x = anArrayOfInt[i];
anArrayOfInt[i] = anArrayOfInt[j];
anArrayOfInt[j] = x;
fireStateChanged();
}
}
public class BubbleSort extends AbstracSorter {
private int outter = 0;
private int inner = 0;
public BubbleSort(int[] values) {
super(values);
}
#Override
public void sort() {
setState(State.Sorting);
outter = 0;
inner = 1;
Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int[] values = getValues();
inner++;
if (inner >= values.length - outter) {
outter++;
inner = 1;
}
if (outter < values.length) {
if (values[inner - 1] > values[inner]) {
swap(values, inner - 1, inner);
} else {
setActiveIndicies(inner - 1, inner);
}
} else {
((Timer)e.getSource()).stop();
setState(State.Done);
}
}
});
timer.setRepeats(true);
timer.start();
}
}
}
Example using the source array
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestSort {
public static void main(String[] args) {
new TestSort();
}
private List<Sorter> sorters;
public TestSort() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
sorters = new ArrayList<>(2);
int values[] = new int[10];
for (int index = 0; index < values.length; index++) {
values[index] = (int) Math.round(Math.random() * 100f);
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(0, 2));
frame.add(createBubbleSortPane(values));
frame.add(createBubbleSortPane(values));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
for (Sorter sorter : sorters) {
sorter.sort();
}
}
});
}
protected SortPane createBubbleSortPane(int[] values) {
SortPane sortPane = new SortPane();
BubbleSort sorter = new BubbleSort(values);
sortPane.setSorter(sorter);
sortPane.setBorder(new CompoundBorder(new LineBorder(Color.GRAY), new EmptyBorder(8, 8, 8, 8)));
sorters.add(sorter);
return sortPane;
}
public class SortPane extends JPanel {
private Sorter sorter;
private ChangeHandler changeHandler;
private int maxValue;
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int values[] = getSorter().getValues();
Insets insets = getInsets();
int width = getWidth() - 1 - (insets.left + insets.right);
int height = getHeight() - 1 - (insets.top + insets.bottom);
int colWidth = Math.round((float) width / (float) values.length);
int x = insets.left;
Color fill = Color.YELLOW;
Color highlight = null;
switch (getSorter().getState()) {
case Sorting:
fill = Color.BLUE;
highlight = Color.RED;
break;
case Done:
fill = Color.GREEN;
break;
}
for (int index = 0; index < values.length; index++) {
g2d.setColor(fill);
int value = values[index];
int colHeight = (int) ((float) height * ((float) value / (float) maxValue));
g2d.fillRect(x, insets.top + height - colHeight, colWidth - 1, colHeight);
if (getSorter().isActiveIndex(index) && highlight != null) {
g2d.setColor(highlight);
g2d.drawRect(x, insets.top + height - colHeight, colWidth - 1, colHeight);
}
x += colWidth;
}
g2d.dispose();
}
public Sorter getSorter() {
return sorter;
}
public void setSorter(Sorter value) {
if (sorter != value) {
if (sorter != null) {
sorter.removeChangeListener(getChangeHandler());
}
sorter = value;
if (sorter != null) {
sorter.addChangeListener(getChangeHandler());
maxValue = 0;
for (int intValue : sorter.getValues()) {
maxValue = Math.max(maxValue, intValue);
}
}
repaint();
}
}
public ChangeHandler getChangeHandler() {
if (changeHandler == null) {
changeHandler = new ChangeHandler();
}
return changeHandler;
}
public class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
}
}
public interface Sorter {
public enum State {
Waiting,
Sorting,
Done
}
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
public int[] getValues();
public void sort();
public State getState();
public boolean isActiveIndex(int index);
}
public abstract class AbstracSorter implements Sorter {
private List<ChangeListener> listeners;
private int[] values;
private State state = State.Waiting;
private List<Integer> activeIndices;
public AbstracSorter(int[] values) {
this.values = new int[values.length];
System.arraycopy(values, 0, this.values, 0, values.length);
listeners = new ArrayList<>(25);
activeIndices = new ArrayList<>(2);
}
#Override
public State getState() {
return state;
}
public void setState(State value) {
if (value != state) {
state = value;
fireStateChanged();
}
}
#Override
public int[] getValues() {
return values;
}
#Override
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
#Override
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
protected void fireStateChanged() {
if (listeners.size() > 0) {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
}
#Override
public boolean isActiveIndex(int index) {
return activeIndices.contains(index);
}
protected void setActiveIndicies(int lower, int upper) {
activeIndices.clear();
activeIndices.add(lower);
activeIndices.add(upper);
fireStateChanged();
}
protected void swap(int[] anArrayOfInt, int i, int j) {
setActiveIndicies(i, j);
int x = anArrayOfInt[i];
anArrayOfInt[i] = anArrayOfInt[j];
anArrayOfInt[j] = x;
fireStateChanged();
}
}
public class BubbleSort extends AbstracSorter {
private int outter = 0;
private int inner = 0;
public BubbleSort(int[] values) {
super(values);
}
#Override
public void sort() {
setState(State.Sorting);
outter = 0;
inner = 1;
Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int[] values = getValues();
inner++;
if (inner >= values.length - outter) {
outter++;
inner = 1;
}
if (outter < values.length) {
if (values[inner - 1] > values[inner]) {
swap(values, inner - 1, inner);
} else {
setActiveIndicies(inner - 1, inner);
}
} else {
((Timer) e.getSource()).stop();
setState(State.Done);
}
}
});
timer.setRepeats(true);
timer.start();
}
}
}
Example Insertion Sorter
This is an example of using a Thread as the primary sort engine instead of a Swing Timer
public class InsertionSorter extends AbstracSorter {
public InsertionSorter(int[] values) {
super(values);
}
#Override
public void sort() {
setState(State.Sorting);
new Thread(new SortRunnable()).start();
}
#Override
protected void swap(int[] anArrayOfInt, int i, int j) {
setActiveIndicies(i, j);
int x = anArrayOfInt[i];
anArrayOfInt[i] = anArrayOfInt[j];
anArrayOfInt[j] = x;
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
fireStateChanged();
}
});
} catch (InterruptedException | InvocationTargetException exp) {
exp.printStackTrace();
}
}
public class SortRunnable implements Runnable {
#Override
public void run() {
int[] values = getValues();
for (int i = 0; i < values.length; ++i) {
for (int j = i - 1; j >= 0 && values[j] > values[j + 1]; --j) {
try {
Thread.sleep(250);
} catch (InterruptedException ex) {
}
swap(values, j, j + 1);
}
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
setState(State.Done);
}
});
}
}
}

Categories

Resources