This is implementation Lee's algorithm in Java. The problem is the deviation in the backtrace(on screenshots):
.
Please, any help?
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JComboBox;
public class Main {
JFrame frame;
//GENERAL VARIABLES
private int cells = 20;
private int delay = 30;
private int startx = -1;
private int starty = -1;
private int finishx = -1;
private int finishy = -1;
private int tool = 0;
private int checks = 0;
private int length = 0;
private int WIDTH = 850;
private final int HEIGHT = 650;
private final int MSIZE = 600;
private int CSIZE = MSIZE/cells;
//UTIL ARRAYS
private String[] tools = {"Start","Finish","Wall", "Eraser"};
//BOOLEANS
private boolean solving = false;
//UTIL
Node[][] map;
Algorithm Alg = new Algorithm();
Random r = new Random();
//SLIDERS
JSlider size = new JSlider(1,5,4);
JSlider speed = new JSlider(0,500,delay);
//LABELS
JLabel toolL = new JLabel("Toolbox");
JLabel sizeL = new JLabel("Size:");
JLabel cellsL = new JLabel(cells+"x"+cells);
JLabel delayL = new JLabel("Delay:");
JLabel msL = new JLabel(delay+"ms");
JLabel checkL = new JLabel("Checks: "+checks);
JLabel lengthL = new JLabel("Path Length: "+length);
//BUTTONS
JButton searchB = new JButton("Search");
JButton resetB = new JButton("Reset");
JButton clearMapB = new JButton("Clear");
//DROP DOWN
JComboBox toolBx = new JComboBox(tools);
//PANELS
JPanel toolP = new JPanel();
//CANVAS
Map canvas;
public static void main(String[] args) { //MAIN METHOD
new Main();
}
public Main() { //CONSTRUCTOR
clearMap();
initialize();
}
public void clearMap() { //CLEAR MAP
finishx = -1; //RESET THE START AND FINISH
finishy = -1;
startx = -1;
starty = -1;
map = new Node[cells][cells]; //CREATE NEW MAP OF NODES
for(int x = 0; x < cells; x++) {
for(int y = 0; y < cells; y++) {
map[x][y] = new Node(3,x,y); //SET ALL NODES TO EMPTY
}
}
reset(); //RESET SOME VARIABLES
}
public void resetMap() { //RESET MAP
for(int x = 0; x < cells; x++) {
for(int y = 0; y < cells; y++) {
Node current = map[x][y];
if(current.getType() == 4 || current.getType() == 5) //CHECK TO SEE IF CURRENT NODE IS EITHER CHECKED OR FINAL PATH
map[x][y] = new Node(3,x,y); //RESET IT TO AN EMPTY NODE
}
}
if(startx > -1 && starty > -1) { //RESET THE START AND FINISH
map[startx][starty] = new Node(0,startx,starty);
map[startx][starty].setHops(0);
}
if(finishx > -1 && finishy > -1)
map[finishx][finishy] = new Node(1,finishx,finishy);
reset(); //RESET SOME VARIABLES
}
private void initialize() { //INITIALIZE THE GUI ELEMENTS
frame = new JFrame();
frame.setVisible(true);
frame.setResizable(false);
frame.setSize(WIDTH,HEIGHT);
frame.setTitle("Lee Algorithm");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
int space = 25;
int buff = 45;
toolP.setLayout(null);
toolP.setBounds(10,10,210,600);
searchB.setBounds(40,space, 120, 25);
toolP.add(searchB);
space+=buff;
resetB.setBounds(40,space,120,25);
toolP.add(resetB);
space+=buff;
clearMapB.setBounds(40,space, 120, 25);
toolP.add(clearMapB);
space+=40;
toolL.setBounds(40,space,120,25);
toolP.add(toolL);
space+=25;
toolBx.setBounds(40,space,120,25);
toolP.add(toolBx);
space+=buff;
sizeL.setBounds(15,space,40,25);
toolP.add(sizeL);
size.setMajorTickSpacing(10);
size.setBounds(50,space,100,25);
toolP.add(size);
cellsL.setBounds(160,space,40,25);
toolP.add(cellsL);
space+=buff;
delayL.setBounds(15,space,50,25);
toolP.add(delayL);
speed.setMajorTickSpacing(5);
speed.setBounds(50,space,100,25);
toolP.add(speed);
msL.setBounds(160,space,40,25);
toolP.add(msL);
space+=buff;
checkL.setBounds(15,space,100,25);
toolP.add(checkL);
space+=buff;
lengthL.setBounds(15,space,100,25);
toolP.add(lengthL);
frame.getContentPane().add(toolP);
canvas = new Map();
canvas.setBounds(230, 10, MSIZE+1, MSIZE+1);
frame.getContentPane().add(canvas);
searchB.addActionListener(new ActionListener() { //ACTION LISTENERS
#Override
public void actionPerformed(ActionEvent e) {
reset();
if((startx > -1 && starty > -1) && (finishx > -1 && finishy > -1))
solving = true;
}
});
resetB.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
resetMap();
Update();
}
});
clearMapB.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clearMap();
Update();
}
});
toolBx.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
tool = toolBx.getSelectedIndex();
}
});
size.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
cells = size.getValue()*5;
clearMap();
reset();
Update();
}
});
speed.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
delay = speed.getValue();
Update();
}
});
startSearch(); //START STATE
}
public void startSearch() { //START STATE
if(solving)
{
Alg.LeeAlg();
}
pause(); //PAUSE STATE
}
public void pause() { //PAUSE STATE
int i = 0;
while(!solving) {
i++;
if(i > 500)
i = 0;
try {
Thread.sleep(1);
} catch(Exception e) {}
}
startSearch(); //START STATE
}
public void Update() { //UPDATE ELEMENTS OF THE GUI
CSIZE = MSIZE/cells;
canvas.repaint();
cellsL.setText(cells+"x"+cells);
msL.setText(delay+"ms");
lengthL.setText("Path Length: "+length);
checkL.setText("Checks: "+checks);
}
public void reset() { //RESET METHOD
solving = false;
length = 0;
checks = 0;
}
public void delay() { //DELAY METHOD
try {
Thread.sleep(delay);
} catch(Exception e) {}
}
class Map extends JPanel implements MouseListener, MouseMotionListener{ //MAP CLASS
public Map() {
addMouseListener(this);
addMouseMotionListener(this);
}
public void paintComponent(Graphics g) { //REPAINT
super.paintComponent(g);
for(int x = 0; x < cells; x++) { //PAINT EACH NODE IN THE GRID
for(int y = 0; y < cells; y++) {
switch(map[x][y].getType()) {
case 0:
g.setColor(Color.GREEN);
break;
case 1:
g.setColor(Color.BLUE);
break;
case 2:
g.setColor(Color.BLACK);
break;
case 3:
g.setColor(Color.WHITE);
break;
case 4:
g.setColor(Color.GRAY);
break;
case 5:
g.setColor(Color.YELLOW);
break;
}
g.fillRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
g.setColor(Color.BLACK);
g.drawRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
try {
int x = e.getX()/CSIZE;
int y = e.getY()/CSIZE;
Node current = map[x][y];
if((tool == 2 || tool == 3) && (current.getType() != 0 && current.getType() != 1))
current.setType(tool);
Update();
} catch(Exception z) {}
}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
resetMap(); //RESET THE MAP WHENEVER CLICKED
try {
int x = e.getX()/CSIZE; //GET THE X AND Y OF THE MOUSE CLICK IN RELATION TO THE SIZE OF THE GRID
int y = e.getY()/CSIZE;
Node current = map[x][y];
switch(tool) {
case 0: { //START NODE
if(current.getType()!=2) { //IF NOT WALL
if(startx > -1 && starty > -1) { //IF START EXISTS SET IT TO EMPTY
map[startx][starty].setType(3);
map[startx][starty].setHops(-1);
}
current.setHops(0);
startx = x; //SET THE START X AND Y
starty = y;
current.setType(0); //SET THE NODE CLICKED TO BE START
}
break;
}
case 1: {//FINISH NODE
if(current.getType()!=2) { //IF NOT WALL
if(finishx > -1 && finishy > -1) //IF FINISH EXISTS SET IT TO EMPTY
map[finishx][finishy].setType(3);
finishx = x; //SET THE FINISH X AND Y
finishy = y;
current.setType(1); //SET THE NODE CLICKED TO BE FINISH
}
break;
}
default:
if(current.getType() != 0 && current.getType() != 1)
current.setType(tool);
break;
}
Update();
} catch(Exception z) {} //EXCEPTION HANDLER
}
#Override
public void mouseReleased(MouseEvent e) {}
}
class Algorithm { // ALGORITHM CLASS
public void LeeAlg() {
ArrayList<Node> priority = new ArrayList<Node>(); //CREATE A PRIORITY QUE
priority.add(map[startx][starty]); //ADD THE START TO THE QUE
while (solving) {
if (priority.size() <= 0) { //IF THE QUE IS 0 THEN NO PATH CAN BE FOUND
solving = false;
break;
}
int hops = priority.get(0).getHops() + 1; //INCREMENT THE HOPS VARIABLE
ArrayList<Node> explored = exploreNeighbors(priority.get(0), hops); //CREATE AN ARRAYLIST OF NODES THAT WERE EXPLORED
if (explored.size() > 0) {
priority.remove(0); //REMOVE THE NODE FROM THE QUE
priority.addAll(explored); //ADD ALL THE NEW NODES TO THE QUE
Update();
delay();
} else { //IF NO NODES WERE EXPLORED THEN JUST REMOVE THE NODE FROM THE QUE
priority.remove(0);
}
}
}
public ArrayList<Node> exploreNeighbors(Node current, int hops) { //EXPLORE NEIGHBORS
ArrayList<Node> explored = new ArrayList<Node>(); //LIST OF NODES THAT HAVE BEEN EXPLORED
for(int a = -1; a <= 1; a++) {
for(int b = -1; b <= 1; b++) {
int xbound = current.getX()+a;
int ybound = current.getY()+b;
if((xbound > -1 && xbound < cells) && (ybound > -1 && ybound < cells)) { //MAKES SURE THE NODE IS NOT OUTSIDE THE GRID
Node neighbor = map[xbound][ybound];
if((neighbor.getHops()==-1 || neighbor.getHops() > hops) && neighbor.getType()!=2) { //CHECKS IF THE NODE IS NOT A WALL AND THAT IT HAS NOT BEEN EXPLORED
explore(neighbor, current.getX(), current.getY(), hops); //EXPLORE THE NODE
explored.add(neighbor); //ADD THE NODE TO THE LIST
}
}
}
}
return explored;
}
public void explore(Node current, int lastx, int lasty, int hops) { //EXPLORE A NODE
if(current.getType()!=0 && current.getType() != 1) //CHECK THAT THE NODE IS NOT THE START OR FINISH
current.setType(4); //SET IT TO EXPLORED
current.setLastNode(lastx, lasty); //KEEP TRACK OF THE NODE THAT THIS NODE IS EXPLORED FROM
current.setHops(hops); //SET THE HOPS FROM THE START
checks++;
if(current.getType() == 1) { //IF THE NODE IS THE FINISH THEN BACKTRACE TO GET THE PATH
backtrace(current.getLastX(), current.getLastY(),hops);
}
}
public void backtrace(int lx, int ly, int hops) { //BACKTRACE
length = hops;
while(hops > 1) { //BACKTRACE FROM THE END OF THE PATH TO THE START
Node current = map[lx][ly];
current.setType(5);
lx = current.getLastX();
ly = current.getLastY();
hops--;
}
solving = false;
}
}
class Node {
// 0 = start, 1 = finish, 2 = wall, 3 = empty, 4 = checked, 5 = finalpath
private int cellType = 0;
private int hops;
private int x;
private int y;
private int lastX;
private int lastY;
public Node(int type, int x, int y) { //CONSTRUCTOR
cellType = type;
this.x = x;
this.y = y;
hops = -1;
}
public int getX() {return x;} //GET METHODS
public int getY() {return y;}
public int getLastX() {return lastX;}
public int getLastY() {return lastY;}
public int getType() {return cellType;}
public int getHops() {return hops;}
public void setType(int type) {cellType = type;} //SET METHODS
public void setLastNode(int x, int y) {lastX = x; lastY = y;}
public void setHops(int hops) {this.hops = hops;}
}
}
That is, the shortest path on the map goes somewhere to the side, and should be in a straight line. What should be corrected in the code?
The problem is that according to the algorithm the answer is gave is as good as a strait line. Both the weird diagonal path and the strait desired path take 4 steps to reach the goal so they are both equal. To fix this you should add a weight. Instead of always incrementing hops by 1, increment it by 1.4 (sqrt(2)) when you move on a diagonal. This way there is a weighting for moving on a diagonal and the desired strait path would be the fastest (as it is in the real world).
Related
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().
I'm currently trying to implement Conway's Game of Life in Java. On a first glance the application seems to work as it either stalls in the states that are expected as stalling states (e.g. block, bee-hive and tub) or changes infinitely.
However, as I took a closer look I never actually saw a Blinker or Beacon nor a Loaf (for reference images of these states see here). So I decided to implement a drawing mode and a one-step-update method that gives me the possibility to analyze exactly what's going on.
The strange thing that I found was the following:
When entering Drawing Mode I reset all cells and all buffered cells on the board to dead. Then, I drew a vertical Blinker somewhere in the middle of the board and did one update step and checked for the update mechanism of all cells that are alive (which are only the 3 cells belonging to the Blinker). In the output however, all of them returned that the value to their bottom left was alive (which actually could not be the case because nothing is being logged for these cells).
I'm really confused about where I went wrong in my code because this just doesn't make any sense for me. The values for the next generation are being stored in a buffer and only written back after the next generation has been calculated entirely, so I don't think that this should be the issue.
For reproducibility, here is the code:
Main.java
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
createAndShowUI();
});
}
private static void createAndShowUI() {
AnimationPanel panel = new AnimationPanel();
JFrame frame = new JFrame("Game of Life");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
super.keyReleased(e);
if(e.getKeyCode() == e.VK_R) {
panel.reset();
panel.startAnimation();
}
if(e.getKeyCode() == e.VK_C) {
panel.clear();
}
if(e.getKeyCode() == e.VK_S) {
panel.startAnimation();
}
if(e.getKeyCode() == e.VK_SPACE) {
panel.stepAnimation();
}
}
});
frame.setVisible(true);
panel.populate();
panel.startAnimation();
}
}
AnimationPanel.java:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
public class AnimationPanel extends JPanel implements ActionListener {
private static final long serialVersionUID = 4929258196354814855L;
private int width = 1920;
private int height = 1080;
private int gridSize = 10;
private Cell[][] cells;
private Cell[][] buffer;
private Timer timer;
private boolean drawingMode = false;
public AnimationPanel() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if(drawingMode) {
int x = e.getX();
int y = e.getY();
int xIndex = (int)x / gridSize;
int yIndex = (int)y / gridSize;
cells[xIndex][yIndex].live = !cells[xIndex][yIndex].live;
repaint();
}
}
});
}
public void reset() {
timer.stop();
cells = null;
buffer = null;
populate();
}
public void clear() {
timer.stop();
for(Cell[] row : cells) {
for(Cell cell: row) {
cell.live = false;
}
}
for(Cell[] row : buffer) {
for(Cell cell: row) {
cell.live = false;
}
}
repaint();
drawingMode = true;
}
public void populate() {
Random random = new Random();
int horizontalCellCount = width / gridSize;
int verticalCellCount = height / gridSize;
cells = new Cell[horizontalCellCount][verticalCellCount];
buffer = new Cell[horizontalCellCount][verticalCellCount];
for(int i = 0; i < horizontalCellCount; i++) {
for(int j = 0; j < verticalCellCount; j++) {
double randVal = random.nextDouble();
boolean live = (randVal < 0.05) ? true : false;
int x = i * gridSize;
int y = j * gridSize;
cells[i][j] = new Cell(live, x, y, gridSize);
buffer[i][j] = new Cell(live, x, y, gridSize);
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(Cell[] row : cells) {
for(Cell cell : row) {
cell.draw(g);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void startAnimation() {
drawingMode = false;
timer = new Timer(250, this);
timer.start();
}
public void stepAnimation() {
update();
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
private void update() {
int horizontalCellCount = width / gridSize;
int verticalCellCount = height / gridSize;
boolean log = false;
for(int i = 0; i < horizontalCellCount; i++) {
for(int j = 0; j < verticalCellCount; j++) {
if(cells[i][j].live) {
log = true;
System.out.println("Cell: (" + i + "|" + j + ") " + cells[i][j].toString());
System.out.println("Row length: " + cells[i].length);
System.out.println("Column length: " + cells.length);
} else {
log = false;
}
int liveNeighours = 0;
for(int x = i - 1; x <= i + 1; x++) {
if(x < 0 || x == horizontalCellCount) {
continue;
}
for(int y = j - 1; y <= j + 1; y++) {
if(y < 0 || y == verticalCellCount || y == j && x == i) {
continue;
}
if(cells[x][y].live) {
liveNeighours++;
}
if(log) {
System.out.println("Cell at " + x + "|" + y + ": " + cells[x][y].live + " - liveNeighbours: " + liveNeighours);
}
}
}
Cell cell = cells[i][j];
if(liveNeighours > 3 || liveNeighours < 2) {
buffer[i][j].live = false;
} else if(!cell.live && liveNeighours == 3) {
buffer[i][j].live = true;
}
}
}
for(int i = 0; i < horizontalCellCount; i++) {
for(int j = 0; j < verticalCellCount; j++) {
cells[i][j] = buffer[i][j];
}
}
}
}
Cell.java
import java.awt.Color;
import java.awt.Graphics;
public class Cell {
public boolean live;
public int x;
public int y;
public int size;
public Cell(boolean live, int x, int y, int size) {
this.live = live;
this.x = x;
this.y = y;
this.size = size;
}
public void draw(Graphics g) {
if(live) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.WHITE);
}
g.fillRect(x, y, size, size);
}
#Override
public String toString() {
return "(" + x + " " + y + ") - Size: " + size;
}
}
Any help is really appreciated on this as I'm really confused what is wrong with the code.
I am writing a video game GUI and I want to firstly open a frame with a menu bar and when the user clicks on play in the menu a JPanel that is in a different class gets added to the current one and it ends up with a frame containing the menu bar and the JPanel. When I run the code bellow I don't get any errors and the console initiates the process. The problem is nothing shows on the screen?? Not the initial frame or anything else.
The code for the frame that calls the class with the JPanel is:
/*-----------------------------------------------------------------------------------------------------*/
package Testes;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Tetris extends JFrame{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 250;
public static final int HEIGHT = 490;
public Tetris() {
JFrame frame = new JFrame();
TetrisBoard janela = new TetrisBoard();
JMenuBar menubar = new JMenuBar();
JMenu start = new JMenu("Start");
JMenuItem play = new JMenuItem("Play");
play.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
janela.startGame();
}
});
start.add(play);
JMenuItem exit = new JMenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
start.add(exit);
JMenu help = new JMenu("Help");
JMenuItem manual = new JMenuItem("User Manual");
manual.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(null, "The goal of Tetris is to eliminate \nas many lines as possible before\n the Tetrominoes reach the top.\nControls:\n\u2190 - Move Left\n\u2192 - Move Right\n\u2193 - Drop\n" +
"C - Rotate AntiClockwise\nV - Rotate Clockwise\nP - Pause\nEsc - Quit","Instructions", JOptionPane.OK_OPTION, new ImageIcon());
}
});
help.add(manual);
JMenuItem about = new JMenuItem("About");
about.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JLabel label = new JLabel("<html><center>Tetris made by GG<br>MEEC<br>2020<html>");
label.setHorizontalAlignment(SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, label, "About", JOptionPane.INFORMATION_MESSAGE);
}
});
help.add(about);
menubar.add(start);
menubar.add(help);
frame.add(janela,BorderLayout.CENTER);
frame.add(menubar,BorderLayout.NORTH);
janela.setFocusable(true);
frame.setTitle("Tetris");
frame.setLayout(new BorderLayout());
frame.setSize(250, 490);
//setPreferredSize(new Dimension(255, 495));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.pack();
}
public static void main(String[] args) {
new Tetris();
}
}
/*-----------------------------------------------------------------------------------------------------*/
And the class with the JPanel is:
/*-----------------------------------------------------------------------------------------------------*/
package Testes;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
public class TetrisBoard extends JPanel implements KeyListener/*, ActionListener*/{
private static final long serialVersionUID = 1L;
public static final int COLOR_MIN = 35;
public static final int COLOR_MAX = 255 - COLOR_MIN;
public static final int BORDER_WIDTH = 5;
public static final int COL_COUNT = 10;
public static final int VISIBLE_ROW_COUNT = 20;
public static final int HIDDEN_ROW_COUNT = 2;
public static final int ROW_COUNT = VISIBLE_ROW_COUNT + HIDDEN_ROW_COUNT;
public static final int TILE_SIZE = 24;
public static final int SHADE_WIDTH = 4;
private static final int CENTER_X = COL_COUNT * TILE_SIZE / 2;
public static final int CENTER_Y = VISIBLE_ROW_COUNT * TILE_SIZE / 2;
public static final int PANEL_WIDTH = COL_COUNT * TILE_SIZE + BORDER_WIDTH * 2;
public static final int PANEL_HEIGHT = VISIBLE_ROW_COUNT * TILE_SIZE + BORDER_WIDTH * 2;
public static final Font LARGE_FONT = new Font("Tahoma", Font.BOLD, 16);
public static final Font SMALL_FONT = new Font("Tahoma", Font.BOLD, 12);
public static final long FRAME_TIME = 20L;
public static final int TYPE_COUNT = TileType.values().length;
public boolean isPaused;
public boolean isNewGame;
public boolean isGameOver;
public int level;
public int score;
public Random random;
public Clock logicTimer;
public TileType currentType;
public TileType nextType;
public int currentCol;
private int currentRow;
public int currentRotation;
public int dropCooldown;
public float gameSpeed;
public String difficulty = "Easy";
public int newLevel;
public int lines;
public int cleared;
public TileType[][] tiles;
public TetrisBoard() {
addKeyListener(this);
this.tiles = new TileType[ROW_COUNT][COL_COUNT];
setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
setBackground(Color.BLACK);
startGame();
}
public void clear() {
for(int i = 0; i < ROW_COUNT; i++) {
for(int j = 0; j < COL_COUNT; j++) {
tiles[i][j] = null;
}
}
}
public boolean isValidAndEmpty(TileType type, int x, int y, int rotation) {
if(x < -type.getLeftInset(rotation) || x + type.getDimension() - type.getRightInset(rotation) >= COL_COUNT) {
return false;
}
if(y < -type.getTopInset(rotation) || y + type.getDimension() - type.getBottomInset(rotation) >= ROW_COUNT) {
return false;
}
for(int col = 0; col < type.getDimension(); col++) {
for(int row = 0; row < type.getDimension(); row++) {
if(type.isTile(col, row, rotation) && isOccupied(x + col, y + row)) {
return false;
}
}
}
return true;
}
public void addPiece(TileType type, int x, int y, int rotation) {
for(int col = 0; col < type.getDimension(); col++) {
for(int row = 0; row < type.getDimension(); row++) {
if(type.isTile(col, row, rotation)) {
setTile(col + x, row + y, type);
}
}
}
}
public int checkLines() {
int completedLines = 0;
for(int row = 0; row < ROW_COUNT; row++) {
if(checkLine(row)) {
completedLines++;
}
}
return completedLines;
}
public boolean checkLine(int line) {
for(int col = 0; col < COL_COUNT; col++) {
if(!isOccupied(col, line)) {
return false;
}
}
for(int row = line - 1; row >= 0; row--) {
for(int col = 0; col < COL_COUNT; col++) {
setTile(col, row + 1, getTile(col, row));
}
}
return true;
}
public boolean isOccupied(int x, int y) {
return tiles[y][x] != null;
}
public void setTile(int x, int y, TileType type) {
tiles[y][x] = type;
}
public TileType getTile(int x, int y) {
return tiles[y][x];
}
//#Override
public void paintComponent(Graphics g) {
this.paintComponent(g);
g.translate(BORDER_WIDTH, BORDER_WIDTH);
if(isPaused()) {
g.setFont(LARGE_FONT);
g.setColor(Color.GREEN);
String msg = "PAUSED";
g.drawString(msg, CENTER_X - g.getFontMetrics().stringWidth(msg) / 2, CENTER_Y);
} else if(isNewGame() || isGameOver()) {
g.setFont(LARGE_FONT);
g.setColor(Color.WHITE);
g.setColor(Color.GREEN);
String msg = isNewGame() ? "TETRIS" : "GAME OVER";
g.drawString(msg, CENTER_X - g.getFontMetrics().stringWidth(msg) / 2, 150);
g.setFont(SMALL_FONT);
msg = "Press Enter to Play" + (isNewGame() ? "" : " Again");
g.drawString(msg, CENTER_X - g.getFontMetrics().stringWidth(msg) / 2, 300);
} else {
for(int x = 0; x < COL_COUNT; x++) {
for(int y = HIDDEN_ROW_COUNT; y < ROW_COUNT; y++) {
TileType tile = getTile(x, y);
if(tile != null) {
drawTile(tile, x * TILE_SIZE, (y - HIDDEN_ROW_COUNT) * TILE_SIZE, g);
}
}
}
TileType type = getPieceType();
int pieceCol = getPieceCol();
int pieceRow = getPieceRow();
int rotation = getPieceRotation();
for(int col = 0; col < type.getDimension(); col++) {
for(int row = 0; row < type.getDimension(); row++) {
if(pieceRow + row >= 2 && type.isTile(col, row, rotation)) {
drawTile(type, (pieceCol + col) * TILE_SIZE, (pieceRow + row - HIDDEN_ROW_COUNT) * TILE_SIZE, g);
}
}
}
g.setColor(Color.DARK_GRAY);
for(int x = 0; x < COL_COUNT; x++) {
for(int y = 0; y < VISIBLE_ROW_COUNT; y++) {
g.drawLine(0, y * TILE_SIZE, COL_COUNT * TILE_SIZE, y * TILE_SIZE);
g.drawLine(x * TILE_SIZE, 0, x * TILE_SIZE, VISIBLE_ROW_COUNT * TILE_SIZE);
}
}
}
g.setColor(Color.GREEN);
g.drawRect(0, 0, TILE_SIZE * COL_COUNT, TILE_SIZE * VISIBLE_ROW_COUNT);
}
public void drawTile(TileType type, int x, int y, Graphics g) {
drawTile(type.getBaseColor(), type.getLightColor(), type.getDarkColor(), x, y, g);
}
public void drawTile(Color base, Color light, Color dark, int x, int y, Graphics g) {
g.setColor(base);
g.fillRect(x, y, TILE_SIZE, TILE_SIZE);
g.setColor(dark);
g.fillRect(x, y + TILE_SIZE - SHADE_WIDTH, TILE_SIZE, SHADE_WIDTH);
g.fillRect(x + TILE_SIZE - SHADE_WIDTH, y, SHADE_WIDTH, TILE_SIZE);
g.setColor(light);
for(int i = 0; i < SHADE_WIDTH; i++) {
g.drawLine(x, y + i, x + TILE_SIZE - i - 1, y + i);
g.drawLine(x + i, y, x + i, y + TILE_SIZE - i - 1);
}
}
public void startGame() {
this.random = new Random();
this.isNewGame = true;
if(this.difficulty.equals("Easy")) {
this.gameSpeed=1.0f;
}else if(this.difficulty.equals("Intermediate")) {
this.gameSpeed=3.0f;
}else if(this.difficulty.equals("Hard")) {
this.gameSpeed=6.0f;
}
this.level=1;
this.cleared=0;
this.newLevel=0;
this.logicTimer = new Clock(gameSpeed);
logicTimer.setPaused(true);
while(true) {
long start = System.nanoTime();
logicTimer.update();
if(logicTimer.hasElapsedCycle()) {
updateGame();
}
//Decrement the drop cool down if necessary.
if(dropCooldown > 0) {
dropCooldown--;
}
renderGame();
long delta = (System.nanoTime() - start) / 1000000L; // delta in miliseconds
if(delta < FRAME_TIME) {
try {
Thread.sleep(FRAME_TIME - delta); // sleeps the difference between the fps and the time for the game to process (delta)
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
public void updateGame() {
if(isValidAndEmpty(currentType, currentCol, currentRow + 1, currentRotation)) {
currentRow++;
} else {
addPiece(currentType, currentCol, currentRow, currentRotation);
cleared = checkLines();
if(cleared > 0) {
lines += cleared;
score += 50 << cleared; // left bit shift - add the number of zeros on the right to the binary version of the number on the right
// score = score + 50 << cleared;
}
//newLevel+=cleared;
gameSpeed += 0.035f;
logicTimer.setCyclesPerSecond(gameSpeed);
logicTimer.reset();
dropCooldown = 25;
if(newLevel<10) {
newLevel+=cleared;
}else if(newLevel>=10) {
level+=1;
newLevel=0;
cleared=0;
}
spawnPiece();
}
}
public void renderGame() {
repaint();
}
public void resetGame() {
this.level = 1;
this.score = 0;
this.lines = 0;
this.newLevel = 0;
this.cleared = 0;
if(this.difficulty.equals("Easy")) {
this.gameSpeed=1.0f;
}else if(this.difficulty.equals("Intermediate")) {
this.gameSpeed=3.0f;
}else if(this.difficulty.equals("Hard")) {
this.gameSpeed=6.0f;
}
this.nextType = TileType.values()[random.nextInt(TYPE_COUNT)];
this.isNewGame = false;
this.isGameOver = false;
clear();
logicTimer.reset();
logicTimer.setCyclesPerSecond(gameSpeed);
spawnPiece();
}
public void spawnPiece() {
this.currentType = nextType;
this.currentCol = currentType.getSpawnColumn();
this.currentRow = currentType.getSpawnRow();
this.currentRotation = 0;
this.nextType = TileType.values()[random.nextInt(TYPE_COUNT)];
if(!isValidAndEmpty(currentType, currentCol, currentRow, currentRotation)) {
lose();
}
}
public void lose()
{
this.isGameOver = true;
logicTimer.setPaused(isPaused);
String info = "";
if (score>HighScore.getHighScores()[9].getScore())
{
info="You got a high score!\n<br>Please enter you name.\n<br>(Note: Only 10 characters will be saved)";
JLabel label = new JLabel("<html><center>GAME OVER\n<br>" + info);
label.setHorizontalAlignment(SwingConstants.CENTER);
String name=JOptionPane.showInputDialog(null, label,"Tetris", JOptionPane.INFORMATION_MESSAGE);
if (name!=null) {
HighScore.addHighScore(new HighScore(score,level,lines,(name.length()>10)?name.substring(0, 10):name,(difficulty.length()>12)?difficulty.substring(0, 12):difficulty));
}
}else {
info="You didn't get a high score:( \n<br>Keep trying you will get it next time!";
JLabel label = new JLabel("<html><center>GAME OVER\n<br>" + info);
label.setHorizontalAlignment(SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, label, "Tetris", JOptionPane.PLAIN_MESSAGE);
}
if (JOptionPane.showConfirmDialog(null, "Do you want to play again?",
"Tetris", JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION) {
this.score=0;
this.level=0;
this.lines=0;
startGame();
}else
{
//If not, quit
System.exit(0);
}
}
public void rotatePiece(int newRotation) {
int newColumn = currentCol;
int newRow = currentRow;
int left = currentType.getLeftInset(newRotation);
int right = currentType.getRightInset(newRotation);
int top = currentType.getTopInset(newRotation);
int bottom = currentType.getBottomInset(newRotation);
if(currentCol < -left) {
newColumn -= currentCol - left;
} else if(currentCol + currentType.getDimension() - right >= COL_COUNT) {
newColumn -= (currentCol + currentType.getDimension() - right) - COL_COUNT + 1;
}
if(currentRow < -top) {
newRow -= currentRow - top;
} else if(currentRow + currentType.getDimension() - bottom >= ROW_COUNT) {
newRow -= (currentRow + currentType.getDimension() - bottom) - ROW_COUNT + 1;
}
if(isValidAndEmpty(currentType, newColumn, newRow, newRotation)) {
currentRotation = newRotation;
currentRow = newRow;
currentCol = newColumn;
}
}
public boolean isPaused() {
return isPaused;
}
public boolean isGameOver() {
return isGameOver;
}
public boolean isNewGame() {
return isNewGame;
}
public int getScore() {
return score;
}
public int getLevel() {
return level;
}
public String getDiff(){
return difficulty;
}
public int getLines() {
return lines;
}
public TileType getPieceType() {
return currentType;
}
public TileType getNextPieceType() {
return nextType;
}
public int getPieceCol() {
return currentCol;
}
public int getPieceRow() {
return currentRow;
}
public int getPieceRotation() {
return currentRotation;
}
//#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_DOWN:
if(!isPaused && dropCooldown == 0) {
logicTimer.setCyclesPerSecond(25.0f);
}
break;
case KeyEvent.VK_LEFT:
if(!isPaused && isValidAndEmpty(currentType, currentCol - 1, currentRow, currentRotation)) {
currentCol--;
}
break;
case KeyEvent.VK_RIGHT:
if(!isPaused && isValidAndEmpty(currentType, currentCol + 1, currentRow, currentRotation)) {
currentCol++;
}
break;
case KeyEvent.VK_C:
if(!isPaused) {
rotatePiece((currentRotation == 0) ? 3 : currentRotation - 1);
}
break;
case KeyEvent.VK_V:
if(!isPaused) {
rotatePiece((currentRotation == 3) ? 0 : currentRotation + 1);
}
break;
case KeyEvent.VK_P:
if(!isGameOver && !isNewGame) {
isPaused = !isPaused;
logicTimer.setPaused(isPaused);
}
break;
case KeyEvent.VK_ENTER:
if(isGameOver || isNewGame) {
resetGame();
}
break;
case KeyEvent.VK_ESCAPE:
int ans = JOptionPane.showConfirmDialog(null, "Are you sure you want to quit?\n", "Tetris", JOptionPane.INFORMATION_MESSAGE);
if(ans==1 || ans==2) {
//isPaused = !isPaused;
//logicTimer.setPaused(isPaused);
return;
}else if(ans==0) {
System.exit(0);
}
}
}
}
//#Override
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_S:
logicTimer.setCyclesPerSecond(gameSpeed);
logicTimer.reset();
break;
}
}
#Override
public void keyTyped(KeyEvent e) {}
}
First of all, dont add a JMenuBar by frame.add(myJMenuBar,someConstraints). Do it by calling the method frame.setJMenuBar(myJMenuBar);
Secondly, you add the components into the frame (its content pane), and after that you frame.setLayout(new BorderLayout());, while you should first set the layout and AFTER add the components to it:
frame.setLayout(new BorderLayout());
frame.add(janela, BorderLayout.CENTER);
This works:
You might notice it replaces the ridiculously long & complicated TetrisBoard with a red panel with a preferred size of 400 x 200. This is how you should figure such things out. Post a minimal reproducible example in future.
import java.awt.*;
import javax.swing.*;
public class Tetris extends JFrame {
public Tetris() {
JFrame frame = new JFrame();
JPanel janela = new JPanel();
janela.setBackground(Color.RED);
janela.setPreferredSize(new Dimension(400,200));
JMenuBar menubar = new JMenuBar();
JMenu start = new JMenu("Start");
JMenuItem play = new JMenuItem("Play");
start.add(play);
JMenuItem exit = new JMenuItem("Exit");
start.add(exit);
JMenu help = new JMenu("Help");
JMenuItem manual = new JMenuItem("User Manual");
help.add(manual);
JMenuItem about = new JMenuItem("About");
help.add(about);
menubar.add(start);
menubar.add(help);
frame.add(janela, BorderLayout.CENTER);
frame.setJMenuBar(menubar);
janela.setFocusable(true);
frame.setTitle("Tetris");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new Tetris();
}
}
noob here trying to make a simple snake game. followed along with tutorial on youtube and my code mayches the working code as best i can tell...snake not responding to commands, seems KeyListener not working. printed out requestFocusInWindow in jpanel constructor to make sure it was in focus and got back false, even though i entered setFocusable(true) asfirst arg in panel constructor.
please help me figure out why snake not responding to movement commands
package otherSnake;
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 Panel extends JPanel implements Runnable {
public static final int width = 800, height = 800;
private boolean running = false;
private Thread thread;
private Bodypart b;
private ArrayList<Bodypart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int size = 5;
private int x = 10, y = 10;
private boolean right = true, left = false, up = false, down = false;
private int ticks = 0;
private Key key;
public Panel() {
setFocusable(true);
key = new Key();
addKeyListener(key);
setPreferredSize(new Dimension(width, height));
r = new Random();
snake = new ArrayList<Bodypart>();
apples = new ArrayList<Apple>();
start();
}
public void tick() {
if (snake.size() == 0) {
b = new Bodypart(x, y, 10);
snake.add(b);
}
if (apples.size() == 0) {
int xCord = r.nextInt(79);
int yCord = r.nextInt(79);
apple = new Apple(xCord, yCord, 10);
apples.add(apple);
}
ticks++;
if (ticks > 250000) {
if (right)
x++;
if (left)
x--;
if (up)
y--;
if (down)
y++;
ticks = 0;
b = new Bodypart(x, y, 10);
snake.add(b);
if (snake.size() > size) {
snake.remove(0);
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, width, height);
g.setColor(Color.BLACK);
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, width, 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);
}
}
public void start() {
running = true;
thread = new Thread(this, "Game Loop");
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run() {
while (running) {
tick();
repaint();
}
}
private class Key implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_RIGHT ) {
up = false;
down = false;
right = true;
//left=false;
}
if (key == KeyEvent.VK_LEFT ) {
up = false;
down = false;
left = true;
//right=false;
}
if (key == KeyEvent.VK_UP ) {
up = true;
down = false;
left = false;
right = false;
}
if (key == KeyEvent.VK_DOWN ) {
up = false;
down = true;
left = false;
right = false;
}
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
For my binary tree program, I have been using JTextFields as nodes and I have managed to make it so when I click left button and select two of the JTextFields, it will draw a line between them. The problem is if I want to drag the JtextField around, I want the line to be following as well between two of the midpoints of the JTextField. I don't know if it's possible with using only paintComponent or not. I did try it but it's like a one off thing and it will leave a trail of all the previously drawn lines.
Here, is the code so far, there are other classes so some of the bits won't work. The code has been fiddled around a bit as well for testing.
public class BinaryTreeMainPnl extends JPanel {
public static Graphics g1;
public int Width = 75;
public int Height = 45;
public String tempNode1 = "";
public int tempNode1Pos = 0;
public int tempNode2Pos = 0;
public String tempNode2 = "";
public static boolean leftBtnSelected;
public static boolean rightBtnSelected;
private static int x1, y1 = 50;
private static int x2, y2 = 500;
JToggleButton leftBtn = new JToggleButton("Left");
JToggleButton rightBtn = new JToggleButton("Right");
JTextField[] myArray = new JTextField[60];
ArrayList<String> nodeNames = new ArrayList<String>();
JFrame MainFrame;
JTextField txtFld1 = new JTextField("Enter Questions here");
JButton btn1 = new JButton("Submit");
public BinaryTreeMainPnl(JFrame frame) {
super();
setSize(800, 700);
MainFrame = frame;
readInput();
leftBtn.setFont(new Font("Arial", Font.BOLD, 15));
leftBtn.setForeground(Color.blue);
leftBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
rightBtn.setSelected(false);
leftBtnSelected = leftBtn.getModel().isSelected();
rightBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(leftBtn);
rightBtn.setFont(new Font("Arial", Font.BOLD, 15));
rightBtn.setForeground(Color.green);
rightBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
leftBtn.setSelected(false);
rightBtnSelected = rightBtn.getModel().isSelected();
leftBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(rightBtn);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
updateLine(g);
}
public void readInput() {
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
identifyNodeNames(txtFld1.getText());
displayNodes(nodeNames);
new TreeSorting().treeSort(nodeNames);
}
});
this.add(txtFld1);
this.add(btn1);
}
public void displayNodes(ArrayList<String> nodeNames) {
for (int i = 0; i < nodeNames.size(); i++) {
String currentSetText = nodeNames.get(i);
myArray[i] = new JTextField(currentSetText);
myArray[i].setEditable(false);
}
for (int i = 0; i < nodeNames.size(); i++) {
int I = i;
myArray[I].addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent evt) {
int x = evt.getX() + myArray[I].getX();
int y = evt.getY() + myArray[I].getY();
myArray[I].setBounds(x, y, myArray[I].getWidth(), myArray[I].getWidth());
System.out.println(myArray[I] + "dragged");
}
});
myArray[I].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
if (leftBtnSelected) {
if (tempNode1.equals("")) {
tempNode1 = myArray[I].getText();
System.out.println(tempNode1 + "clicked");
} else {
tempNode2 = myArray[I].getText();
System.out.println(tempNode2 + "Clicked as well");
leftBtn.setSelected(false);
leftBtnSelected = false;
x1 = 40;
y1 = 40;
x2 = 400;
y2 = 400;
updateLine(g1);
System.out.println("asdasd");
}
}
if (rightBtnSelected) {
}
}
public void moveComponent(MouseEvent evt) {
}
});
System.out.println("I " + I);
System.out.println(myArray[I].getText());
add(myArray[I]);
}
MainFrame.revalidate();
}
public int findMidPoint(JTextField temp) {
Point p = temp.getLocation();
Dimension d = temp.getSize();
return p.x + (d.width) / 2;
}
int coun = 0;
public void updateLine(Graphics g) {
g.drawLine(x1, x2, y1, y2);
x1 = x1 + 10;
y1 = y1 + 10;
y2 = y2 + 10;
x2 = x2 + 10;
System.out.println("Line Updated" + coun);
coun++;
}
public void identifyNodeNames(String answer) {
int arrayCounter = 0;
int lastNodePosition = 0;
for (int i = 0; i < answer.length(); i++) {
char c = answer.charAt(i);
if (c == ',') {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, i + 1).replaceAll(",", "").replaceAll(" ", ""));
lastNodePosition = i + 1;
arrayCounter++;
}
if (i == answer.length() - 1) {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, answer.length()).replaceAll(" ", ""));
}
}
}
}
import java.util.ArrayList;
public class TreeSorting {
public static int arrayLength;
String[][] Child;
String root = "";
boolean nodeSorted = false;
int parentCounter = 1;
public void treeSort(ArrayList<String> passedQuestions) {
// declaring nodes
arrayLength = passedQuestions.size();
System.out.println(arrayLength + "ARRAY LENGTH");
Child = new String[arrayLength][3];
for (int i = 0; i < arrayLength; i++) {
Child[i][0] = passedQuestions.get(i);
}
//initially calling the mainprocess with parentCounter 1;
root = Child[0][0];
mainProcess(1);
}
public void mainProcess(int parentCounter) {
if (parentCounter < Child.length) {
System.out.println(parentCounter);
sortingTree(Child[parentCounter][0], root, 0); //where the next node is passed on the tree is sorted recursively
for (int i = 0; i < Child.length; i++) {
System.out.println(Child[i][0]);
System.out.println(Child[i][1] + "," + Child[i][2]);
}
}
}
public void sortingTree(String CurrentNode, String PreviousNode, int PreviousPosition) {
nodeSorted = false;// node is not sorted in the beginning
if (isAfter(CurrentNode.toLowerCase(), PreviousNode.toLowerCase())) {
System.out.println(Child[PreviousPosition][2]);
if (Child[PreviousPosition][2] == null) { //checks if the right of the node is empty, if found empty the node is placed there.
Child[PreviousPosition][2] = CurrentNode;
nodeSorted = true; // if the node finds a position in the array node is sorted.
} else {
sortingTree(CurrentNode, Child[PreviousPosition][2], getPositionInArray(Child[PreviousPosition][2]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
} else if (Child[PreviousPosition][1] == null) { // if the left of the node is empty, the item will be placed there
Child[PreviousPosition][1] = CurrentNode;
nodeSorted = true;
} else {
sortingTree(CurrentNode, Child[PreviousPosition][1], getPositionInArray(Child[PreviousPosition][1]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
if (nodeSorted) { // if the node finds a position in the array, the nodeCounter increments and the next node in the question is processed.
parentCounter++;
mainProcess(parentCounter);
}
}
public int getPositionInArray(String node) {
int position = 0;
loop:
for (int i = 0; i < Child.length; i++) {
if (Child[i][0].equals(node)) {
position = i;
break loop;
}
}
return position;
}
public boolean isAfter(String CurrentNode, String PreviousNode) {
int loopLength = determineLoopLength(CurrentNode, PreviousNode);
boolean result = false;
String tempCheck = "";
loop:
for (int i = 0; i < loopLength; i++) {
if ((int) CurrentNode.charAt(i) > (int) PreviousNode.charAt(i)) {
result = true;
break loop;
}
if ((int) CurrentNode.charAt(i) < (int) PreviousNode.charAt(i)) {
result = false;
break loop;
} else if (CurrentNode.charAt(i) == PreviousNode.charAt(i) && CurrentNode.length() > PreviousNode.length()) {
System.out.println("I'm here");
tempCheck = tempCheck + CurrentNode.charAt(i) + "";
if (i == loopLength - 1 && tempCheck.equals(PreviousNode)) {
result = true;
break loop;
}
}
}
return result;
}
public int determineLoopLength(String CurrentNode, String PreviousNode) {
int loopLength = 0;
if (CurrentNode.length() < PreviousNode.length()) {
loopLength = CurrentNode.length();
}
if (PreviousNode.length() < CurrentNode.length()) {
loopLength = PreviousNode.length();
} else {
loopLength = CurrentNode.length();
}
return loopLength;
}
}
WTF, been working on this,.....
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class DragMyFields extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int COLS = 8;
private static final int DELTA_Y = 120;
private static final int MAX_DEPTH = 3;
private MySimpleTreeNode<JTextField> treeRoot = new MySimpleTreeNode<>();
private MyMouse myMouse = new MyMouse();
public DragMyFields() {
setLayout(null); // this is *** BAD ***
// much better would be to create a custom layout
JTextField field = new JTextField(COLS);
field.addMouseListener(myMouse);
field.addMouseMotionListener(myMouse);
field.setSize(field.getPreferredSize());
int x = (PREF_W - field.getPreferredSize().width) / 2;
int y = DELTA_Y;
field.setLocation(x, y);
add(field);
treeRoot.setNode(field);
recursiveCreateTree(treeRoot, MAX_DEPTH, x, y);
}
private void recursiveCreateTree(MySimpleTreeNode<JTextField> node, int depth, int x, int y) {
if (depth == 0) {
return;
}
JTextField leftField = new JTextField(COLS);
JTextField rightField = new JTextField(COLS);
MySimpleTreeNode<JTextField> leftNode = new MySimpleTreeNode<>(leftField);
MySimpleTreeNode<JTextField> rightNode = new MySimpleTreeNode<>(rightField);
node.setLeft(leftNode);
node.setRight(rightNode);
int multiplier = 4;
for (int i = 0; i < MAX_DEPTH - depth; i++) {
multiplier *= 2;
}
int xL = x - getPreferredSize().width / multiplier;
int xR = x + getPreferredSize().width / multiplier;
y += DELTA_Y;
leftField.setSize(leftField.getPreferredSize());
rightField.setSize(rightField.getPreferredSize());
leftField.setLocation(xL, y);
rightField.setLocation(xR, y);
leftField.addMouseListener(myMouse);
leftField.addMouseMotionListener(myMouse);
rightField.addMouseListener(myMouse);
rightField.addMouseMotionListener(myMouse);
add(leftField);
add(rightField);
recursiveCreateTree(leftNode, depth - 1, xL, y);
recursiveCreateTree(rightNode, depth - 1, xR, y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
recursiveDraw(g, treeRoot);
}
private void recursiveDraw(Graphics g, MySimpleTreeNode<JTextField> node) {
MySimpleTreeNode<JTextField> left = node.getLeft();
MySimpleTreeNode<JTextField> right = node.getRight();
Point p = getNodeCenter(node);
if (left != null) {
Point p2 = getNodeCenter(left);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, left);
}
if (right != null) {
Point p2 = getNodeCenter(right);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, right);
}
}
private Point getNodeCenter(MySimpleTreeNode<JTextField> node) {
JTextField field = node.getNode();
Point location = field.getLocation();
Dimension size = field.getSize();
return new Point(location.x + size.width / 2, location.y + size.height / 2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
Component source = null;
private Point pressedP;
private Point pressedLoc;
private Point parentP;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
source = e.getComponent();
parentP = source.getParent().getLocationOnScreen();
pressedLoc = source.getLocationOnScreen();
pressedP = e.getLocationOnScreen();
}
#Override
public void mouseReleased(MouseEvent e) {
moveComponent(e);
source = null;
pressedP = null;
pressedLoc = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (source == null) {
return;
}
moveComponent(e);
}
private void moveComponent(MouseEvent e) {
Point p = e.getLocationOnScreen();
int x = pressedLoc.x + p.x - pressedP.x - parentP.x;
int y = pressedLoc.y + p.y - pressedP.y - parentP.y;
Point newP = new Point(x, y);
source.setLocation(newP);
repaint();
}
}
private static void createAndShowGui() {
DragMyFields mainPanel = new DragMyFields();
JFrame frame = new JFrame("DragMyFields");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
class MySimpleTreeNode<T> {
private T node;
private MySimpleTreeNode<T> left;
private MySimpleTreeNode<T> right;
public MySimpleTreeNode() {
// default constructor
}
public MySimpleTreeNode(T node) {
this.node = node;
}
public void setNode(T node) {
this.node = node;
}
public T getNode() {
return node;
}
public MySimpleTreeNode<T> getLeft() {
return left;
}
public void setLeft(MySimpleTreeNode<T> left) {
this.left = left;
}
public MySimpleTreeNode<T> getRight() {
return right;
}
public void setRight(MySimpleTreeNode<T> right) {
this.right = right;
}
}