This question already has an answer here:
Java: GUI - JButton opening new JPanel and reading the JTextFields
(1 answer)
Closed 9 years ago.
My problem is making my Main class and Journal class connect together, in the Main class users will input two variables and click the button to create the table, in the Journal class, it will take the two variables and make it go through a process before they get added into the table so i need JTextField1 as variable a and JTextField2 as variable b.
I used netbeans to create the Main class and my own methods to create the table class please help! Thanks! This is the part of the Main class Netbeans tells me to edit when I right click > Events > Action > Action Performed
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
int data1 = Integer.parseInt(jTextField1.getText());
int data2 = Integer.parseInt(jTextField2.getText());
}
Here is my Code:
package Components;
/**
*
* #author dustinpx2014
*/
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class Journal extends JPanel
{
private JTable table;
private int a;//Number of Students
private int b;// Length of Trip
public Journal()
{
String colN1 = "Date";
String colN2 = "Student";
int c = a*2/b; // Determining # of Journals
int col = c*2; // Creating two columns for every journal(Day and Student)
String[] columnNames = new String[col]; //For Loop: inserting column names
for(int colF = 0; colF < col; colF++)
{
if(colF%2 == 0)
{
columnNames[colF] = colN1;
}
else
{
columnNames[colF] = colN2;
}
}
int row = b; //row = number of days
int d = 1; //day number
int s = 1; //student number
int x = 0; //counter for the # of times students write
int z = 1; // student number(no limit)
int z1 = a/2; // student number 2
int x1 = 0; // counter for the # of times students write 2
int x2 = 0;
int w = 1;
Object[][] data = new Object[row][col];
for (int col1 = 0; col1 < data[0].length; col1++)
{
for (int row1 = 0; row1<data.length; row1++)//goes through the table by column
{
if(d > b) //reseting the date
{
d = 1;
}
if(s > a && x <= 2) //reseting student number and adds count
{
s = 1;
x++;
}
if(z > a)
{
z = 1;
}
if(z1 > a && x1 <= 2)
{
z1 = 1;
x1++;
}
if (w>a)
{
w++;
}
if(col1%2 == 0) //inserts the day
{
data[row1][col1]= "Day " + d;
d++;
}
else if (s!=data[row1][col1])//inserts student number
{
data[row1][col1]= s;
s++;
z++;
w++;
}
for (int col2 = 1; col2 < data[0].length; col2++)
{
for (int row2 = 0; row2<data.length; row2++)//goes through the table by column
{
if(z == data[row2][col2] && col2%2!=0)//checks for repeats and replaces them
{
for (int y = 0; y < col; y++) //checking all columns
{
if (z1 == a/2 && x1 <= 5) //adds count
{
x1++;
}
else if(z1 > a && x1 <= 5)
{
z1 = 1;
x1++;
}
if(z == data[row2][y])
{
data[row2][col2] = z1;
z1++;
w++;
}
}
}
}
}
for (int row3 = 1; row3 < data.length; row3++)
{
for (int col3 = 0; col3<data[0].length; col3++)//goes through the table by rows
{
if(w == data[row3][col3] && col3%2!=0)//checks for repeats and replaces them
{
for(int y2 = 0; y2 < col; y2++)
{
if(
row3<row-1 &&
row3> 1 &&
w==data[row3+1][y2] &&
w==data[row3-1][y2] &&
w==data[row3][y2]
) //checks rows
{
data[row3][col3] = 0;
}
}
}
}
}
}
}
JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public JTable getTable() {
return table;
}
private static void gui()
{
JFrame gui = new JFrame();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setTitle("Journal List");
gui.setSize(700,200);
gui.setLocationRelativeTo(null);
gui.setVisible(true);
gui.add(new Journal());
}
}
Please help add anything or delete anything in my code to make them work, THANK YOU :)
write that over your constrictor
public static void main(String args[]){
Journal is= new Journal();
}
public Journal()
{...}
Related
So basically, I want to save all the coordinates of all row numbers that are processed in the actionPerformed method in the ButtonListener class to my Board class in order to move pieces for chess. When I run the program, the inner class ButtonListener saves all the variables which is good. But the variables do not keep the saved values when they are called to my constructor in class Board. I want to keep the values in the variables from the inner class to the outer class.
Edit:Provided the entire class.
public class Board extends JPanel {
Piece movingPiece;
ImageIcon image;
private int row1;
private int col1;
private int row2;
private int col2;
private JButton btn[][];
private Square squares[][];
public Board(String gameType, int row, int col) {
setLayout(new GridLayout(8, 8));
squares = new Square[row][col];
btn = new JButton[row][col];
setUpSquares();
setUpBtns();
setUpChessPieces();
findPieces();
movePiece(row1, col1, row2, col2);// all 0's
}
public void setUpSquares() {
for (int i = 0; i < ChessGame.EIGHT; i++) {
for (int j = 0; j < ChessGame.EIGHT; j++) {
squares[i][j] = new Square();
}
}
}
public void setUpBtns() {
for (int i = 0; i < ChessGame.EIGHT; i++) {
for (int j = 0; j < ChessGame.EIGHT; j++) {
btn[i][j] = new JButton();
add(btn[i][j]);
btn[i][j].addActionListener(new ButtonListener());
if ((i + j) % 2 == 0) {
btn[i][j].setBackground(Color.WHITE);
btn[i][j].setForeground(Color.WHITE);
} else {
btn[i][j].setBackground(Color.DARK_GRAY);
btn[i][j].setForeground(Color.DARK_GRAY);
}
}
}
}
public void movePiece(int row1, int col1, int row2, int col2) {
squares[row1][col1].getPiece().setRow(row2);
squares[row1][col1].getPiece().setCol(col2);
movingPiece = squares[row1][col1].getPiece();
squares[row2][col2].setPiece(movingPiece);
btn[row2][col2].setIcon(new ImageIcon(squares[row2][col2].getPiece().getPieceColor()));
}
/**
* Finds pieces and sets the piece icons to the button.
*/
public void findPieces() {
for (int i = 0; i < ChessGame.EIGHT; i++) {
for (int j = 0; j < ChessGame.EIGHT; j++) {
if (squares[i][j].getPiece() != null) {
btn[i][j].setIcon(new ImageIcon(squares[i][j].getPiece().getPieceColor()));
} else {
btn[i][j].setIcon(null);
}
}
}
}
public void setUpChessPieces() {
// white pieces
for (int i = 0; i < ChessGame.EIGHT; i++) {
Pawn pawn1 = new Pawn(1, i, 1, "white");
squares[1][i].setPiece(pawn1);
}
for (int i = 0; i < ChessGame.EIGHT; i += 7) {
Rook rook1 = new Rook(0, i, 1, "white");
squares[0][i].setPiece(rook1);
}
for (int i = 1; i < ChessGame.EIGHT; i += 5) {
Knight knight1 = new Knight(0, i, 1, "white");
squares[0][i].setPiece(knight1);
}
for (int i = 2; i < ChessGame.EIGHT; i += 3) {
Bishop bishop1 = new Bishop(0, i, 1, "white");
squares[0][i].setPiece(bishop1);
}
King king1 = new King(0, 4, 1, "white");
squares[0][4].setPiece(king1);
Queen queen1 = new Queen(0, 3, 1, "white");
squares[0][3].setPiece(queen1);
// black pieces
for (int i = 0; i < ChessGame.EIGHT; i++) {
Pawn pawn2 = new Pawn(6, i, 2, "black");
squares[6][i].setPiece(pawn2);
}
for (int i = 0; i < ChessGame.EIGHT; i += 7) {
Rook rook2 = new Rook(7, i, 1, "black");
squares[7][i].setPiece(rook2);
}
for (int i = 1; i < ChessGame.EIGHT; i += 5) {
Knight knight2 = new Knight(7, i, 1, "black");
squares[7][i].setPiece(knight2);
}
for (int i = 2; i < ChessGame.EIGHT; i += 3) {
Bishop bishop2 = new Bishop(7, i, 1, "black");
squares[7][i].setPiece(bishop2);
}
King king2 = new King(7, 4, 1, "black");
squares[7][4].setPiece(king2);
Queen queen2 = new Queen(7, 3, 1, "black");
squares[7][3].setPiece(queen2);
}
public class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
JButton src = (JButton) e.getSource();
if (src.getBackground() != Color.DARK_GRAY && src.getBackground() != Color.WHITE) {
src.setBackground(src.getForeground());
} else {
src.setBackground(Color.MAGENTA);
}
for (int i = 0; i < ChessGame.EIGHT; i++) {
for (int j = 0; j < ChessGame.EIGHT; j++) {
if (squares[i][j].getPiece() != null) {
if (btn[i][j] == src) {
row1 = i;
col1 = j;
}
}
if (squares[i][j].getPiece() == null) {
if (btn[i][j] == src) {
row2 = i;
col2 = j;
}
}
}
}
System.out.println("row1:" + row1 + " col1:" + col1);
System.out.println("row2:" + row2 + " col2:" + col2);
}
}
}
Your problem is that you are calling the movePiece(int, int, int, int) from the constructor, and 2 buttons have not necessarily been clicked. The listener has been added to each button, but you don't know that the listener has been activated at that point. So, row1, col1, row2, and col2 are all set to the value that ints take when they have not been initiated yet, 0. So, you really want to call the move method from the listener. Something like:
btn[i][j].addActionListener(e -> {
JButton src = (JButton) e.getSource();
//Process src to get row1, col1, row2, and col2 as you did
movePiece(row1, col1, row2, col2);
});
I replaced your ButtonListener class with a lambda expression, but you can leave it as you did. The important part is that you are calling movePiece from the action listener because it ensures that row1, col1, row2, and col2 are all defined.
I coded a Swing class where in the main there is only one call to a method solve(). This method implements a while loop and uses another method in almost every round, this method is called paint() and changes the value of only one JPanel inside of a 9x9 GridLayout, whose reference is stored in a 2D array.
I need a timer inisde paint() so before the panel is modified, 2 seconds pass. It does this the first time is called, but after the 2 seconds it does every round of the loop without waiting. The goal is to watch 2 seconds pass before any panel is modified. I tried using javax Timer. Thread.sleep() doesn't work in a Swing class apparently.
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.Stack;
public class SudokuApp {
private JFrame frame;
int i = 9;
int j = 9;
JPanel[][] board = new JPanel[i][j];
JButton nextButton = new JButton("Resolver");
Box[][] sudoku = new Box[9][9];
Box newCurrent = new Box();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SudokuApp window = new SudokuApp();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SudokuApp() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setTitle("Sudoku Solver");
frame.setBounds(100, 100, 510, 555);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(new GridLayout(i, j));
//Initiate board
for (int m = 0; m < i; m++) {
for (int n = 0; n < j; n++) {
board[m][n] = new JPanel();
JTextField textField = new JTextField(1);
textField.setFont(new Font("Lucida Grande", Font.BOLD, 25));
board[m][n].add(textField);
panel.add(board[m][n]);
}
}
Box last = new Box();
for (int m = 0; m < this.i; m++) {
for (int n = 0; n < this.j; n++) {
sudoku[m][n] = new Box(m, n);
if (m != 0 || n != 0) sudoku[m][n].back = last;
last = sudoku[m][n];
}
}
//Solve button action listener
nextButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {
if (validBoard()) {
nextButton.setEnabled(false);
solve();
}
else JOptionPane.showMessageDialog(null, "Condiciones iniciales inválidas.");
} });
frame.getContentPane().add(nextButton, BorderLayout.SOUTH);
}
private boolean validBoard() {
for (int m = 0; m < i; m++) {
for (int n = 0; n < j; n++) {
JTextField current = (JTextField) board[m][n].getComponent(0);
String text = current.getText();
if (text.length() == 1 && !text.contains("0")) {
try {
int number = Integer.parseInt(text);
if (!add(number, m, n)) return false;
current.setEditable(false);
} catch (NumberFormatException e) {
return false;
}
} else {
current.setText("");
current.setEditable(false);
}
}
}
return true;
}
private void solve() {
int i = 0;
int j = 0;
int newI = i + 1;
while (i < 9) {
while (j < 9) {
Box current = sudoku[i][j];
if (current.number == 0) {
HashSet<Integer> possibles = new HashSet<>();
HashSet<Integer> takenNumbers = getTakenNumbers(i, j);
for (int k = 1; k <= 9; k++) if (!takenNumbers.contains(k)) possibles.add(k);
if (possibles.isEmpty()) {
current.number = 0;
erase(i, j);
tryOther(current.back);
i = newCurrent.i;
newI = i + 1;
j = newCurrent.j + 1;
} else {
for (Integer p : possibles) current.possibles.push(p);
current.number = (int) current.possibles.pop();
paint(current.number, i, j);
j++;
newI = i + 1;
}
} else {
j++;
newI = i + 1;
}
}
i = newI;
j = 0;
}
}
private void tryOther(Box box) {
if (box.possibles.empty()) {
if (box.back != null) {
if (!box.initial) {
box.number = 0;
erase(box.i, box.j);
}
tryOther(box.back);
}
else newCurrent = null;
} else {
if (getTakenNumbers(box.i, box.j).contains(box.possibles.peek())) {
box.possibles.pop();
tryOther(box);
}
newCurrent = box;
box.number = (int) box.possibles.pop();
paint(box.number, box.i, box.j);
}
}
private boolean add(int a, int i, int j) {
if (getTakenNumbers(i, j).contains(a)) return false;
sudoku[i][j].number = a;
sudoku[i][j].initial = true;
return true;
}
private void paint(int a, int i, int j) {
JPanel panel = board[i][j];
JTextField jTextField = (JTextField) board[i][j].getComponent(0);
jTextField.setFont(new Font("Lucida Grande", Font.PLAIN, 25));
jTextField.setForeground(Color.gray);
ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("T");
}
};
Timer timer = new Timer(3000 , task);
timer.setRepeats(false);
timer.start();
jTextField.setText("" + a);
panel.revalidate();
panel.repaint();
}
private void erase(int i, int j) {
JTextField jTextField = (JTextField) board[i][j].getComponent(0);
jTextField.setText("");
board[i][j].revalidate();
board[i][j].repaint();
}
private HashSet<Integer> getTakenNumbers(int i, int j) {
HashSet<Integer> takenNumbers = new HashSet<>();
for (int k = 0; k < 9; k++) if (sudoku[i][k].number != 0 && k != j) takenNumbers.add(sudoku[i][k].number);
for (int k = 0; k < 9; k++) if (sudoku[k][j].number != 0 && k != i) takenNumbers.add(sudoku[k][j].number);
int bigBoxRow = 0;
int bigBoxColumn = 0;
if (i <= 5 && i > 2) bigBoxRow = 3;
if (i <= 8 && i > 5) bigBoxRow = 6;
if (j <= 5 && j > 2) bigBoxColumn = 3;
if (j <= 8 && j > 5) bigBoxColumn = 6;
for (int k = bigBoxRow; k < bigBoxRow + 3; k++) for (int l = bigBoxColumn; l < bigBoxColumn + 3; l++) if (sudoku[k][l].number != 0 && k != i && l != j) takenNumbers.add(sudoku[k][l].number);
return takenNumbers;
}
}
import java.util.Stack;
public class Box {
public int number = 0;
public int i, j;
public Stack possibles = new Stack();
public Box back;
public boolean initial = false;
public Box(int i, int j) {
this.i = i;
this.j = j;
}
public Box() {}
}
You need to change the structure of your program. Specifically, you will want to get rid of the nested while loops within your solve method and instead replace it with a single Swing Timer. That Timer will repeat 9 * 9 times, and will have a counter field inside of it, and inside of it you will want to do the code that you currently do within your nested while loops.
It could look something like...
// TIMER_DELAY could be 2000 if you want a 2 second delay
new Timer(TIMER_DELAY, new ActionListener() {
private int i = 0;
private int j = 0;
#Override
public void actionPerformed(ActionEvent e) {
// MAX_ROWS is 9
if (i == MAX_ROWS) {
// we've iterated through the whole thing
((Timer) e.getSource()).stop();
}
if (j == MAX_ROWS) {
// we've gone through all the columns
i++; // the next row
j = 0; // start at column 0
}
// TODO the code in the nested while loop.
j++;
}
}).start();
For an example of a functioning program that places text in fields with a delay (but doesn't solve anything):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SudokuMCVE extends JPanel {
private static final int CLUSTER = 3;
private static final int MAX_ROWS = 9;
private static final float FIELD_PTS = 32f;
private static final int GAP = 3;
private static final Color BG = Color.BLACK;
private static final Color SOLVED_BG = Color.LIGHT_GRAY;
public static final int TIMER_DELAY = 2 * 1000;
private JTextField[][] fieldGrid = new JTextField[MAX_ROWS][MAX_ROWS];
public SudokuMCVE() {
JPanel mainPanel = new JPanel(new GridLayout(CLUSTER, CLUSTER));
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.setBackground(BG);
JPanel[][] panels = new JPanel[CLUSTER][CLUSTER];
for (int i = 0; i < panels.length; i++) {
for (int j = 0; j < panels[i].length; j++) {
panels[i][j] = new JPanel(new GridLayout(CLUSTER, CLUSTER, 1, 1));
panels[i][j].setBackground(BG);
panels[i][j].setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(panels[i][j]);
}
}
for (int row = 0; row < fieldGrid.length; row++) {
for (int col = 0; col < fieldGrid[row].length; col++) {
fieldGrid[row][col] = createField(row, col);
int i = row / 3;
int j = col / 3;
panels[i][j].add(fieldGrid[row][col]);
}
}
setLayout(new BorderLayout());
add(mainPanel, BorderLayout.CENTER);
add(new JButton(new SolveAction("Solve")), BorderLayout.PAGE_END);
}
private JTextField createField(int row, int col) {
JTextField field = new JTextField(2);
field.setHorizontalAlignment(JTextField.CENTER);
field.setFont(field.getFont().deriveFont(Font.BOLD, FIELD_PTS));
return field;
}
private class SolveAction extends AbstractAction {
public SolveAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
new Timer(TIMER_DELAY, new ActionListener() {
private int i = 0;
private int j = 0;
#Override
public void actionPerformed(ActionEvent e) {
// MAX_ROWS is 9
if (i == MAX_ROWS) {
((Timer) e.getSource()).stop();
}
if (j == MAX_ROWS) {
i++;
j = 0;
}
int number = (int) (MAX_ROWS * Math.random()) + 1;
fieldGrid[i][j].setBackground(SOLVED_BG);
fieldGrid[i][j].setText(String.valueOf(number));
j++;
}
}).start();
}
}
private static void createAndShowGui() {
SudokuMCVE mainPanel = new SudokuMCVE();
JFrame frame = new JFrame("SudokuMCVE");
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();
});
}
}
This question already has an answer here:
Java: GUI - JButton opening new JPanel and reading the JTextFields
(1 answer)
Closed 9 years ago.
I need to have
1.the JButton open the JTable in the Journal class
2.transfer the ints in the JTextFields to the variables a and b in the Journal Class
I used netbeans to create the Main class and my own methods to create the table class please help! Thanks! This is the part of the Main class Netbeans tells me to edit when I right click > Events > Action > Action Performed
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
int data1 = Integer.parseInt(jTextField1.getText());
int data2 = Integer.parseInt(jTextField2.getText());
}
Here is my Code:
package Components;
/**
*
* #author dustinpx2014
*/
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class Journal extends JPanel
{
private JTable table;
private int a;//Number of Students
private int b;// Length of Trip
public Journal()
{
String colN1 = "Date";
String colN2 = "Student";
int c = a*2/b; // Determining # of Journals
int col = c*2; // Creating two columns for every journal(Day and Student)
String[] columnNames = new String[col]; //For Loop: inserting column names
for(int colF = 0; colF < col; colF++)
{
if(colF%2 == 0)
{
columnNames[colF] = colN1;
}
else
{
columnNames[colF] = colN2;
}
}
int row = b; //row = number of days
int d = 1; //day number
int s = 1; //student number
int x = 0; //counter for the # of times students write
int z = 1; // student number(no limit)
int z1 = a/2; // student number 2
int x1 = 0; // counter for the # of times students write 2
int x2 = 0;
int w = 1;
Object[][] data = new Object[row][col];
for (int col1 = 0; col1 < data[0].length; col1++)
{
for (int row1 = 0; row1<data.length; row1++)//goes through the table by column
{
if(d > b) //reseting the date
{
d = 1;
}
if(s > a && x <= 2) //reseting student number and adds count
{
s = 1;
x++;
}
if(z > a)
{
z = 1;
}
if(z1 > a && x1 <= 2)
{
z1 = 1;
x1++;
}
if (w>a)
{
w++;
}
if(col1%2 == 0) //inserts the day
{
data[row1][col1]= "Day " + d;
d++;
}
else if (s!=data[row1][col1])//inserts student number
{
data[row1][col1]= s;
s++;
z++;
w++;
}
for (int col2 = 1; col2 < data[0].length; col2++)
{
for (int row2 = 0; row2<data.length; row2++)//goes through the table by column
{
if(z == data[row2][col2] && col2%2!=0)//checks for repeats and replaces them
{
for (int y = 0; y < col; y++) //checking all columns
{
if (z1 == a/2 && x1 <= 5) //adds count
{
x1++;
}
else if(z1 > a && x1 <= 5)
{
z1 = 1;
x1++;
}
if(z == data[row2][y])
{
data[row2][col2] = z1;
z1++;
w++;
}
}
}
}
}
for (int row3 = 1; row3 < data.length; row3++)
{
for (int col3 = 0; col3<data[0].length; col3++)//goes through the table by rows
{
if(w == data[row3][col3] && col3%2!=0)//checks for repeats and replaces them
{
for(int y2 = 0; y2 < col; y2++)
{
if(
row3<row-1 &&
row3> 1 &&
w==data[row3+1][y2] &&
w==data[row3-1][y2] &&
w==data[row3][y2]
) //checks rows
{
data[row3][col3] = 0;
}
}
}
}
}
}
}
JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
public JTable getTable() {
return table;
}
private static void gui()
{
JFrame gui = new JFrame();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setTitle("Journal List");
gui.setSize(700,200);
gui.setLocationRelativeTo(null);
gui.setVisible(true);
gui.add(new Journal());
}
Please help! thanks :)
I have two classes Main with JTextFields and Jbutton and Journal with a Jtable extending JPanel. I need to use the Main class to operate the Journal class how do you use JButton to open up the JPanel and how do you use the variables in JTextField and apply them to variables a and b?
I assume that your Main class has a Journal field, say called journal, and that this JPanel has been added to your main. To call methods of your Journal instance, simply call methods on the journal variable. For instance Journal should have public getter methods that would allow Main to query the data held by its fields.
Note that I don't see any JTextFields in Journal, but if Journal were my class, again, I'd give it a public method to allow it to get information out of the JTable, and in that method, I'd call one of JTable's methods to get the information that your Journal method could return. A decent JTable method you could use is the getValueAt(int row, int column). In fact your Journal method could simply wrap that method:
public class Journal {
private JTable table;
// ...... lots more code
public Object getValueAt(int row, int column) {
// first check that row and column are not out of bounds, and deal with it
return table.getValueAt(row, column);
}
}
Now if you're also looking to display this JTable on button press, then you will need to add it to one of the containers in your Main class, and then call revalidate and repaint on the same container after changing its contents. It's important to know and understand the layout manager used by that container as well since some accept new components with greater ease than others.
I am working on Conway's Game of Life for a school project. I am not looking for the code directly. I am looking to find out what is wrong with my code.
In Conway's Game of Life a cell goes from dead to alive if it has 3 alive neighbors. It stays alive if it has two or three alive neighbors. If none of those are true it is dead.
My LifeView class has a method that displays the cell simulation and afterwards displays how many alive cells are around the given point.
This is the output I am getting:
How many rows is your simulation?
5
How many columns is your simulation?
5
How many generations is your simulation?
3
xxxxx
xxxxx
xx0xx
xx0xx
xx0xx
00000
01110
02120
03230
02120
xxxxx
xxxxx
xxxxx
xxxxx
xxxxx
00000
00000
00000
00000
00000
xxxxx
xxxxx
xxxxx
xxxxx
xxxxx
00000
00000
00000
00000
00000
This is wrong because the second generation is supposed to be a horizontal line of live cells crossing the center of the first generation alive cells. Instead of crossing that center, all cells are turned dead. I am stumped as to why it doesn't work.
Main class:
package gameOfLife;
import java.util.Scanner;
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
Scanner numReader = new Scanner(System.in);
System.out.println("How many rows is your simulation?");
int rows = numReader.nextInt();
System.out.println("How many columns is your simulation?");
int columns = numReader.nextInt();
System.out.println("How many generations is your simulation?");
int generations = numReader.nextInt();
LifeModel model = new LifeModel(rows,columns);
LifeView life = new LifeView(model);
for(int i=0; i<generations; i++)
{
life.displayLife();
model.nextGeneration();
}
}
LifeView class:
package gameOfLife;
import java.util.Scanner;
public class LifeView {
private LifeModel model;
public LifeView(LifeModel model)
{
this.model = model;
}
public void displayLife()
{
for(int i=0; i < model.getWorld().length; i++)
{
for(int j=0; j < model.getWorld()[0].length; j++)
{
if(model.getWorld()[i][j])
{
System.out.print("0");
}
else
{
System.out.print("x");
}
}
System.out.println("");
}
System.out.println("");
for(int i=0; i < model.getWorld().length; i++)
{
for(int j=0; j < model.getWorld()[0].length; j++)
{
System.out.print(model.numLivingNeighbors(i,j));
}
System.out.println("");
}
System.out.println("");
System.out.println("");
}
}
LifeModel class:
package gameOfLife;
public class LifeModel
{
private boolean[][] world;
private int numRows;
private int numCols;
private boolean[][] tempWorld;
public LifeModel(int rows, int cols)
{
this.numRows=rows;
this.numCols=cols;
world = new boolean[rows][cols];
initWorld();
tempWorld = world;
}
private void initWorld()
{
boolean done = false;
while(!done)
{
int i = (int) (Math.random()*numRows);
int j = (int) (Math.random()*numCols);
if(j>0 && i>0 && i<numRows-1 && j<numCols-1)
{
/*
world[i-1][j-1] = true;
world[i-1][j] = true;
world[i-1][j+1] = true;
world[i][j+1] = true;
world[i+1][j] = true;
*/
world[i][j]=true;
world[i+1][j]=true;
world[i-1][j]=true;
done = true;
}
}
}
public void nextGeneration()
{
//tempWorld = new boolean[numRows+2][numCols+2];
int rows = world.length;
int columns = world[0].length;
for(int i=0; i < rows; i++)
{
for(int j = 0; j < columns; j++)
{
toggleCell(i,j);
}
}
world = tempWorld;
}
public void toggleCell(int r, int c)
{
int count = numLivingNeighbors(r,c);
if(!world[r][c] && count==3)
{
tempWorld[r][c] = true;
}
else if(world[r][c] && (count>=2 && count<=3))
{
tempWorld[r][c] = true;
}
else
{
tempWorld[r][c] = false;
}
}
public int numLivingNeighbors(int r, int c)
{
int count = 0;
boolean newCells[][] = world;
for(int i = -1; i<=1; i++)
{
for(int j = -1; j<=1; j++)
{
if(i!=0 || j!=0)
{
int row = r + i;
int column = c + j;
if(row>=0 && row < newCells.length && column>=0 && column<newCells[0].length && newCells[row][column])
{
count++;
}
}
}
}
return count;
}
public void userChange()
{
}
public boolean[][] getWorld()
{
return world;
}
}
Any help is GREATLY appreciated!
You just have a couple small issues with your LifeModel class.
In your constructor you set the tempWorld to reference the same array as the actual game world. This will cause any modifications to tempWorld to also affect the gameWorld.
public LifeModel(int rows, int cols)
{
this.numRows=rows;
this.numCols=cols;
world = new boolean[rows][cols];
initWorld();
//tempWorld = world; // You can remove this line.
}
Then in next generation you have the line "//tempWorld = new boolean[numRows+2][numCols+2];" commented out. You really do need to create a new temp array here so you aren't changing the game board as you read it. However, I'm not sure what the +2 is supposed to be, so I removed it. You should have:
public void nextGeneration()
{
tempWorld = new boolean[numRows][numCols]; // Keep it the same size
int rows = world.length;
int columns = world[0].length;
for(int i=0; i < rows; i++)
{
for(int j = 0; j < columns; j++)
{
toggleCell(i,j);
}
}
world = tempWorld;
}
After I made those changes it worked perfectly for me. I've included the full LifeModel class below that I used on my machine.
package gameOfLife;
public class LifeModel
{
private boolean[][] world;
private int numRows;
private int numCols;
private boolean[][] tempWorld;
public LifeModel(int rows, int cols)
{
this.numRows=rows;
this.numCols=cols;
world = new boolean[rows][cols];
initWorld();
}
private void initWorld()
{
boolean done = false;
while(!done)
{
int i = (int) (Math.random()*numRows);
int j = (int) (Math.random()*numCols);
if(j>0 && i>0 && i<numRows-1 && j<numCols-1)
{
/*
world[i-1][j-1] = true;
world[i-1][j] = true;
world[i-1][j+1] = true;
world[i][j+1] = true;
world[i+1][j] = true;
*/
world[i][j]=true;
world[i+1][j]=true;
world[i-1][j]=true;
done = true;
}
}
}
public void nextGeneration()
{
tempWorld = new boolean[numRows][numCols];
int rows = world.length;
int columns = world[0].length;
for(int i=0; i < rows; i++)
{
for(int j = 0; j < columns; j++)
{
toggleCell(i,j);
}
}
world = tempWorld;
}
public void toggleCell(int r, int c)
{
int count = numLivingNeighbors(r,c);
if(!world[r][c] && count==3)
{
tempWorld[r][c] = true;
}
else if(world[r][c] && (count>=2 && count<=3))
{
tempWorld[r][c] = true;
}
else
{
tempWorld[r][c] = false;
}
}
public int numLivingNeighbors(int r, int c)
{
int count = 0;
boolean newCells[][] = world;
for(int i = -1; i<=1; i++)
{
for(int j = -1; j<=1; j++)
{
if(i!=0 || j!=0)
{
int row = r + i;
int column = c + j;
if(row>=0 && row < newCells.length && column>=0 && column<newCells[0].length && newCells[row][column])
{
count++;
}
}
}
}
return count;
}
public void userChange()
{
}
public boolean[][] getWorld()
{
return world;
}
}
Check that numLivingNeighbors is returning the proper value for each cell in the world.
Also check the step for staying alive
Hey You have done a simple mistake in your code
public LifeModel(int rows, int cols)
{
this.numRows=rows;
this.numCols=cols;
world = new boolean[rows][cols];
initWorld();
tempWorld = world;
}
this is LifeModel constructor.
In this constructor you need to initialize tempworld also. You should not assign your world to tempworld.
After modification this block of code will become like this....
public LifeModel(int rows, int cols)
{
this.numRows=rows;
this.numCols=cols;
world = new boolean[rows][cols];
tempWorld = new boolean[rows][cols];
initWorld();
}
After this your output will be correct.
I'm trying to solve the problem of positioning N queens on NxN board without row, column and diagonal conflicts. I use an algorithm with minimizing the conflicts. Firstly, on each column randomly a queen is positioned. After that, of all conflict queens randomly one is chosen and for her column are calculated the conflicts of each possible position. Then, the queen moves to the best position with min number of conflicts. It works, but it runs extremely slow. My goal is to make it run fast for 10000 queens. Would you, please, suggest me some improvements or maybe notice some mistakes in my logic?
Here is my code:
public class Queen {
int column;
int row;
int d1;
int d2;
public Queen(int column, int row, int d1, int d2) {
super();
this.column = column;
this.row = row;
this.d1 = d1;
this.d2 = d2;
}
#Override
public String toString() {
return "Queen [column=" + column + ", row=" + row + ", d1=" + d1
+ ", d2=" + d2 + "]";
}
#Override
public boolean equals(Object obj) {
return ((Queen)obj).column == this.column && ((Queen)obj).row == this.row;
}
}
And:
import java.util.HashSet;
import java.util.Random;
public class SolveQueens {
public static boolean printBoard = false;
public static int N = 100;
public static int maxSteps = 2000000;
public static int[] queens = new int[N];
public static Random random = new Random();
public static HashSet<Queen> q = new HashSet<Queen>();
public static HashSet rowConfl[] = new HashSet[N];
public static HashSet d1Confl[] = new HashSet[2*N - 1];
public static HashSet d2Confl[] = new HashSet[2*N - 1];
public static void init () {
int r;
rowConfl = new HashSet[N];
d1Confl = new HashSet[2*N - 1];
d2Confl = new HashSet[2*N - 1];
for (int i = 0; i < N; i++) {
r = random.nextInt(N);
queens[i] = r;
Queen k = new Queen(i, r, i + r, N - 1 + i - r);
q.add(k);
if (rowConfl[k.row] == null) {
rowConfl[k.row] = new HashSet<Queen>();
}
if (d1Confl[k.d1] == null) {
d1Confl[k.d1] = new HashSet<Queen>();
}
if (d2Confl[k.d2] == null) {
d2Confl[k.d2] = new HashSet<Queen>();
}
((HashSet<Queen>)rowConfl[k.row]).add(k);
((HashSet<Queen>)d1Confl[k.d1]).add(k);
((HashSet<Queen>)d2Confl[k.d2]).add(k);
}
}
public static void print () {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(queens[i] == j ? "♕ " : "◻◻◻ ");
}
System.out.println();
}
System.out.println();
}
public static boolean checkItLinear() {
Queen r = choseConflictQueen();
if (r == null) {
return true;
}
Queen newQ = findNewBestPosition(r);
q.remove(r);
q.add(newQ);
rowConfl[r.row].remove(r);
d1Confl[r.d1].remove(r);
d2Confl[r.d2].remove(r);
if (rowConfl[newQ.row] == null) {
rowConfl[newQ.row] = new HashSet<Queen>();
}
if (d1Confl[newQ.d1] == null) {
d1Confl[newQ.d1] = new HashSet<Queen>();
}
if (d2Confl[newQ.d2] == null) {
d2Confl[newQ.d2] = new HashSet<Queen>();
}
((HashSet<Queen>)rowConfl[newQ.row]).add(newQ);
((HashSet<Queen>)d1Confl[newQ.d1]).add(newQ);
((HashSet<Queen>)d2Confl[newQ.d2]).add(newQ);
queens[r.column] = newQ.row;
return false;
}
public static Queen choseConflictQueen () {
HashSet<Queen> conflictSet = new HashSet<Queen>();
boolean hasConflicts = false;
for (int i = 0; i < 2*N - 1; i++) {
if (i < N && rowConfl[i] != null) {
hasConflicts = hasConflicts || rowConfl[i].size() > 1;
conflictSet.addAll(rowConfl[i]);
}
if (d1Confl[i] != null) {
hasConflicts = hasConflicts || d1Confl[i].size() > 1;
conflictSet.addAll(d1Confl[i]);
}
if (d2Confl[i] != null) {
hasConflicts = hasConflicts || d2Confl[i].size() > 1;
conflictSet.addAll(d2Confl[i]);
}
}
if (hasConflicts) {
int c = random.nextInt(conflictSet.size());
return (Queen) conflictSet.toArray()[c];
}
return null;
}
public static Queen findNewBestPosition(Queen old) {
int[] row = new int[N];
int min = Integer.MAX_VALUE;
int minInd = old.row;
for (int i = 0; i < N; i++) {
if (rowConfl[i] != null) {
row[i] = rowConfl[i].size();
}
if (d1Confl[old.column + i] != null) {
row[i] += d1Confl[old.column + i].size();
}
if (d2Confl[N - 1 + old.column - i] != null) {
row[i] += d2Confl[N - 1 + old.column - i].size();
}
if (i == old.row) {
row[i] = row[i] - 3;
}
if (row[i] <= min && i != minInd) {
min = row[i];
minInd = i;
}
}
return new Queen(old.column, minInd, old.column + minInd, N - 1 + old.column - minInd);
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
init();
int steps = 0;
while(!checkItLinear()) {
if (++steps > maxSteps) {
init();
steps = 0;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Done for " + (endTime - startTime) + "ms\n");
if(printBoard){
print();
}
}
}
Edit:
Here is my a-little-bit-optimized solution with removing some unused objects and putting the queens on diagonal positions when initializing.
import java.util.Random;
import java.util.Vector;
public class SolveQueens {
public static boolean PRINT_BOARD = true;
public static int N = 10;
public static int MAX_STEPS = 5000;
public static int[] queens = new int[N];
public static Random random = new Random();
public static int[] rowConfl = new int[N];
public static int[] d1Confl = new int[2*N - 1];
public static int[] d2Confl = new int[2*N - 1];
public static Vector<Integer> conflicts = new Vector<Integer>();
public static void init () {
random = new Random();
for (int i = 0; i < N; i++) {
queens[i] = i;
}
}
public static int getD1Pos (int col, int row) {
return col + row;
}
public static int getD2Pos (int col, int row) {
return N - 1 + col - row;
}
public static void print () {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(queens[i] == j ? "Q " : "* ");
}
System.out.println();
}
System.out.println();
}
public static boolean hasConflicts() {
generateConflicts();
if (conflicts.isEmpty()) {
return false;
}
int r = random.nextInt(conflicts.size());
int conflQueenCol = conflicts.get(r);
int currentRow = queens[conflQueenCol];
int bestRow = currentRow;
int minConfl = getConflicts(conflQueenCol, queens[conflQueenCol]) - 3;
int tempConflCount;
for (int i = 0; i < N ; i++) {
tempConflCount = getConflicts(conflQueenCol, i);
if (i != currentRow && tempConflCount <= minConfl) {
minConfl = tempConflCount;
bestRow = i;
}
}
queens[conflQueenCol] = bestRow;
return true;
}
public static void generateConflicts () {
conflicts = new Vector<Integer>();
rowConfl = new int[N];
d1Confl = new int[2*N - 1];
d2Confl = new int[2*N - 1];
for (int i = 0; i < N; i++) {
int r = queens[i];
rowConfl[r]++;
d1Confl[getD1Pos(i, r)]++;
d2Confl[getD2Pos(i, r)]++;
}
for (int i = 0; i < N; i++) {
int conflictsCount = getConflicts(i, queens[i]) - 3;
if (conflictsCount > 0) {
conflicts.add(i);
}
}
}
public static int getConflicts(int col, int row) {
return rowConfl[row] + d1Confl[getD1Pos(col, row)] + d2Confl[getD2Pos(col, row)];
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
init();
int steps = 0;
while(hasConflicts()) {
if (++steps > MAX_STEPS) {
init();
steps = 0;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Done for " + (endTime - startTime) + "ms\n");
if(PRINT_BOARD){
print();
}
}
}
Comments would have been helpful :)
Rather than recreating your conflict set and your "worst conflict" queen everything, could you create it once, and then just update the changed rows/columns?
EDIT 0:
I tried playing around with your code a bit. Since the code is randomized, it's hard to find out if a change is good or not, since you might start with a good initial state or a crappy one. I tried making 10 runs with 10 queens, and got wildly different answers, but results are below.
I psuedo-profiled to see which statements were being executed the most, and it turns out the inner loop statements in chooseConflictQueen are executed the most. I tried inserting a break to pull the first conflict queen if found, but it didn't seem to help much.
Grouping only runs that took more than a second:
I realize I only have 10 runs, which is not really enough to be statistically valid, but hey.
So adding breaks didn't seem to help. I think a constructive solution will likely be faster, but randomness will again make it harder to check.
Your approach is good : Local search algorithm with minimum-conflicts constraint. I would suggest try improving your initial state. Instead of randomly placing all queens, 1 per column, try to place them so that you minimize the number of conflicts. An example would be to try placing you next queen based on the position of the previous one ... or maybe position of previous two ... Then you local search will have less problematic columns to deal with.
If you randomly select, you could be selecting the same state as a previous state. Theoretically, you might never find a solution even if there is one.
I think you woud be better to iterate normally through the states.
Also, are you sure boards other than 8x8 are solvable?
By inspection, 2x2 is not, 3x3 is not, 4x4 is not.