Inner Classes in Java - java

I am making a keyboard-like buttons for my Hangman game (SEE PICTURE HERE), my problem is about the inner classes. I've read this LINK about inner classes and it says that you can only access the outside variables with FINAL type. But if I declared the variable as such, I cannot change the value of it anymore... So my problem is that I need to change the value inside the inner class. My code is as follows:
public class MainGame extends JDialog {
private String player;
private char [] wordChar;
private JButton[] buttons;
private int level;
private int score;
private int livesLeft;
private int missedGuess;
void newGame() {
level = 0;
score = 0;
livesLeft = 10;
missedGuess = 0;
//label1:
// while (livesLeft!= 0) {
//get random WORD from LIST
Word hiddenWord = new Word();
//put random word in Array
wordChar = new char[hiddenWord.getHiddenWord().length()];
wordChar = hiddenWord.getHiddenWord().toCharArray();
buttons = new JButton[wordChar.length];
for (int i = 0; i < wordChar.length; i++){
JButton guessWord = new JButton(" ");
guessWord.setFont(new Font("Microsoft Sans Serif", 1, 18));
guessWord.setEnabled(false);
jPanel3.setLayout(new GridLayout(1, wordChar.length));
jPanel3.add(guessWord);
buttons[i] = guessWord;
}
checkLetter();
}
void checkLetter() {
int checker = 0;
while(checker != wordChar.length){
jPanel1.setLayout(new GridLayout(3, 9, 3, 5));
for (char buttonChar = 'a'; buttonChar <= 'z'; buttonChar++) {
String buttonText = String.valueOf(buttonChar);
final JButton letterButton = new JButton(buttonText);
letterButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
for (int j = 0; j < wordChar.length; j++){
String text = String.valueOf(wordChar[j]);
if(actionCommand.equals(text)){
buttons[j].setText(text);
checker++; //THIS CODE IS NOT POSSIBLE!!!!
}
}
}
});
jPanel1.add(letterButton);
}
checker++;
}
}
NOTE: The code above is not complete.
The int checker is used to count how many correct letters are already guessed so that if it is equal to the length of the word, I can now proceed to the next level
How can I re-do my code?

You can declare checker as a field of outer class, and access it with some method, something like increaseChecker().
UPDATE: Something like this:
1) Create checker field in outer class:
public class OuterClassName {
private int checker;
protected void increaseChecker() {
checker++;
}
void checkLetter() {
// ...
}
}
2) Use increaseChecker() method call instead of checker++

You can't access local variables in an anonymous inner class, and that's for a good reason. The actionPerformed() method isn't guaranteed to be called inside the checkLetter() function. It will be called later, possibly (and most probably) after the function exits so its local variables will be destroyed by that time. Therefore, the newly created anonymous class implicitly gets a copy of that variable. But it wouldn't make any sense to increase the copy, that's why only final local variables can be accessed from methods of an anonymous class.
The simplest workaround is just to make checker a field of the outer class. But that wouldn't make any sense if it's accessed only within the checkLetter() function unless it is necessary for it to retain its value between checkLetter() calls. In order to find out the true answer, you need to think why you are trying to increase checker inside actionPerformed()? When should it happen and what are you trying to achieve by doing it?

Why not keep the anonymous inner class but have it call a method of the class. This way final isn't an issue.
letterButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
letterButtonActionPerformed(e); // create this method
}
});
//.....
// new method
private void letterButtonActionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
for (int j = 0; j < wordChar.length; j++){
String text = String.valueOf(wordChar[j]);
if(actionCommand.equals(text)){
buttons[j].setText(text);
checker++; //THIS CODE IS NOT POSSIBLE!!!!
}
}
}

Related

StackOverflowError - Jaja

I'm trying to do a simple code in Java : I have a class called "Bloc", which create blocks (square), which inside it I create a random width (largeur), and a random height (hauteur) between 2 ints, and I create a random number of blocks (nombreBloc). I also create an ArrayList to put every block in it, to see how much I have left.
So, I did a function called "insererBlocList" (insert the block into the ArrayList), which create "nombreBloc" (numberBloc) of blocks and put it into the ArrayList.
I've got a graphic interface, in which I have 1 panel for the windows, which inside it I have 2 other panels: One of them is to put every block I created into it.
Here is my problem, I've got a "StackOverflowError" inside my function "insererBlocList", which means there is an infinite loop, but after writing the path of code, I don't see where I did the mistake... Here is the code :
Bloc class:
public class Bloc extends JPanel{
private int hauteur, largeur, nombreBloc;
private boolean premierPassage = true;
private ArrayList<Bloc> listeBlocRestant;
private Random rand = new Random();
public Bloc() {
this.hauteur = 10 + rand.nextInt(50 - 10);
this.largeur = 10 + rand.nextInt(50 - 10);
listeBlocRestant = new ArrayList<Bloc>();
if(premierPassage == true) {
this.nombreBloc = 5 + rand.nextInt(30 - 5);
insererBlocList();
}
}
public ArrayList<Bloc> insererBlocList(){
premierPassage = false;
for(int i=0; i<nombreBloc; i++) {
Bloc bloc = new Bloc();
listeBlocRestant.add(bloc);
}
return listeBlocRestant;
}
The GUI part of the panel block:
private JPanel initPanelBloc() {
panelBloc = new Bloc();
}
Your Bloc constructor calls insererBlocList(), and insererBlocList() creates additional Bloc instances (for each of them the constructor calls insererBlocList()), which leads to an infinite chain of method calls, leading to StackOverflowError.
insererBlocList() probably shouldn't be called by the Bloc constructor.
You might thought premierPassage = false; will prevent method calling again. But insererBlocList() makes new instance of Bloc and this boolean value will be true again. Change code like this:
public class Bloc extends JPanel{
private int hauteur, largeur, nombreBloc;
private ArrayList<Bloc> listeBlocRestant;
private Random rand = new Random();
public Bloc(boolean premierPassage) {
this.hauteur = 10 + rand.nextInt(50 - 10);
this.largeur = 10 + rand.nextInt(50 - 10);
listeBlocRestant = new ArrayList<Bloc>();
if(premierPassage == true) {
this.nombreBloc = 5 + rand.nextInt(30 - 5);
insererBlocList();
}
}
public ArrayList<Bloc> insererBlocList(){
premierPassage = false;
for(int i=0; i<nombreBloc; i++) {
Bloc bloc = new Bloc(false);
listeBlocRestant.add(bloc);
}
return listeBlocRestant;
}
And change GUI part like this:
private JPanel initPanelBloc() {
panelBloc = new Bloc(true);
}

How to get the alphanumerical token of a JLabel in a JLabel[] to pass to the method

I am trying to pass an element from jlb[] to the method new1(JLabel jl). Here is my code:
JLabel jlb[]=new JLabel[10];
for (int i = 0; i < 10; i++) {
jlb[i]=new JLabel("jlbl"+i);
}
new1(<variable name>);
new1 is a method. It has a JLabel parameter. I want call new1(). What should I place instead of <variable name> to call the method with variable from the array?
This is new1 method:
void new1(final JLabel jlbl){
new Thread(){
#Override
public void run() {
int y=10;
while (b>=150) {
for (int b=300; b > 150; b--) {
try {
Thread.sleep(10);
jlbl.setLocation(b, y);
} catch (Exception e) {
}
}
}
jLabel1.setLocation(b, y);
}
}.start();
}
As I understand you are looking for a alphanumerical token that would identify your variable like myJLabel or cuteLabelFromAnArray. Well, data stored in arrays can be accessed with special operator []. In your example this would be for example:
new1(jlb[<put index here>]);

Constructor is ignoring "for" loop(Java)

So I feel kind of stupid, because it looks like I'm missing something trivial and I've used loops before, but now we're at the stage in our class where we're using them a lot and I can't seem to find the problem after trying many different combinations, so here goes :
public class BusStop
{
private BusArrival[] _buses;
private int _noOfBuses;
final int MAX_ARRAY_SIZE = 1000;
//================================ CONSTRUCTORS ============================//
public BusStop(int size){ // THIS
_buses = new BusArrival[size]; // IS
// THE
for(int i=0; i< size; i++){ // PROBLEMATIC
if(_buses[i] != null){ // LOOP
_noOfBuses ++;
}
}
}
//=============================== METHODS =================================//
public int getNoOfBuses(){
return _noOfBuses;
}
public boolean add (int line, int pass, Time1 t){ // adds a BussArrival object to an empty array (if there's any).
for (int i=0; i < _buses.length; i++){
if(_buses[i] == null){
_buses[i] = new BusArrival(line, pass, t);
return true;
}
}
return false;
}
Here's a constructor of the BusArrival class, just so you have a general idea :
public BusArrival(int lineNum, int pass, Time1 t){
_lineNumber = lineNum;
_noOfPassengers = pass;
_arrivalTime = t;
}
And here's Time1 constructor from a saparate class, just for this to make sense :
public Time1(int h, int m, int s)
_hour = h;
_minute = m;
_second = s;
}
Here's my main method :
public class Test
{
public static void main (String [] args){
BusStop first = new BusStop(4);
Time1 one = new Time1(10,30,0);
Time1 two = new Time1(10,0,0);
first.add(1,2,one);
first.add(2,3,two);
System.out.println(first.getNoOfBuses());
}
}
Unfortunately the output is "0" when I do that.
Any help would be appreciated.
Thanks.
Here's the problem.
Number of buses is only assigned in the initializer, but in the initializer you aren't adding any buses. Hence you get 0 buses.
When you add a bus, you are not updating number of buses. So you get 0.
You should do _noOfBuses++; when you successfully added a bus. Also, take out that loop in the initializer. When you initialized an array all the entries are null, so the loop is useless :)
Edit:
You seem to be confused about the order of execution of your code.
In your main function, you are first initializing a BusStop. This means he initializer code is ran (which includes the loop in your initializer).
Then you added the two buses. However, note that the loop is already executed, it won't be executed again, because the initializer is only run once.
Therefore, your loop is never going to increment _noOfBuses
You need to increase the number of busses every time that you add a new one.
public BusStop(int size){ // THIS
_buses = new BusArrival[size]; // IS
// THE
for(int i=0; i< size; i++){ // PROBLEMATIC
if(_buses[i] != null){ // LOOP
_noOfBuses ++;
}
}
}
In the above code the array _buses just gets created with all the items pointing to null. In your for-loop you are using if statement to check if there is any non-null value (which in this case does not exist because there are no items in the array). so your _noOfBuses ++; is not reachable.
First Add another constructor with no arguments to your BusArrival class. Just like this.
public BusArrival() {}
Second Modify the BusStop constructor to the following
public BusStop(int size){
_buses = new BusArrival[size];
for(int i=0; i<_buses.length; i++) {
_buses[i] = new BusArrival();
_noOfBuses ++;
}
}

Access already running objects - Java

import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
public class vasilisTable extends JFrame {
Object[] split_data_l;
Object[][] split_data;
Object [][] split_data_clone;
Object [][] split_data_reverse;
Object [][] split_data_reverse_num;
String[] temp;
private JTable table;
private JPanel bottom_panel;
private JLabel average;
private JLabel max_dr;
public vasilisTable(String name, String data, int choice)
{
super(name);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); //the DISPOSE_ON_CLOSE means that when we press the x button is will close only the table window and not the whole programm
//this.getAccessibleContext().setAccessibleName(name);
//System.out.println(this.getAccessibleContext().getAccessibleName());
setSize(800,600);
String[] columnNames = {"Date", "Open","High","Low","Close",
"Volume", "Adjusted" };//defines the column names
//------ Start of making the arrays that will be used as data for the table creation
split_data_l = data.split( "\n" );
int lngth = split_data_l.length;
split_data = new Object[lngth-1][7];
split_data_clone = new Object[lngth-1][7];
split_data_reverse= new Object[lngth-1][7];
split_data_reverse_num= new Object[lngth-1][7];
double sum = 0;
for(int k=1; k<split_data_l.length; k++) //initializing the three arrays with the data we got from the URLReader
{
temp = split_data_l[k].toString().split(",");
for (int l=0; l<temp.length; l++)
{
split_data[k-1][l] = temp[l];
split_data_clone[k-1][l] = temp[l];
split_data_reverse[k-1][l] = temp[l];
split_data_reverse_num[k-1][l] = temp[l];
}
}
for(int k=split_data_l.length-2; k>=1; k--) // making of the clone array that contains all the last column with colours
{
Double temp = Double.parseDouble(split_data[k][6].toString());
Double temp1 = Double.parseDouble(split_data[k-1][6].toString());
double check =temp-temp1;
if (check>0)
{
String color_temp = "<html><span style = 'color:red'>" + split_data_clone[k-1][6] +"</span></html>" ;
split_data_clone[k-1][6] = color_temp;
}
else
{
String color_temp = "<html><span style = 'color:green'>" +split_data_clone[k-1][6]+"</span></html>" ;
split_data_clone[k-1][6] = color_temp;
}
}
int l = split_data_clone.length;
int m = l-1;
for (int i=0; i<l; i++) //making of the reversed array
{
for (int j = 0; j<=6; j++)
{
split_data_reverse[i][j]=split_data_clone[m][j];
}
m--;
}
m = l-1;
for (int i=0; i<l; i++) //making of the reversed array
{
for (int j = 0; j<=6; j++)
{
split_data_reverse_num[i][j]=split_data[m][j];
}
m--;
}
//------ End of making the arrays that will be used as data for the table creation
//------ Start of calculating the average
for (int i=0; i<lngth-1; i++)
{
Double temp = Double.parseDouble(split_data[i][6].toString());
sum = sum+temp;
//System.out.println("turn "+i+" = "+split_data[i][6]);
}
float avg = (float) (sum/(lngth-1));
avg = Round((float) avg,2);
String avg_str;
avg_str = "<html>Average: <b>"+avg+"</b></html>";
//"<html><b>Average: </b></html>"
//------ End of calculating the average
//------ Start of Calculating the Maximal Drawdown
double high=0;
double low=100000000;
double drawdown=0;
double max_drawdown=0;
int last_high=0;
int last_low=0;
for (int i=0; i<lngth-1; i++)
{
Double temp = Double.parseDouble(split_data_reverse_num[i][6].toString());
//Double temp1 = Double.parseDouble(split_data[i+1][6].toString());
if (temp>high)
{
high = temp;
last_high = i;
//System.out.println("max high = "+temp);
}
else
{
low = temp;
last_low = i;
//System.out.println("max low = "+temp);
}
if (last_low>last_high)
{
drawdown = high-low;
//System.out.println("drawdown = "+drawdown);
}
if (drawdown>max_drawdown)
{
max_drawdown = drawdown;
}
}
//System.out.println("max dr = "+max_drawdown);
String max_dr_str = "<html>Maximal Drawdown: <b>"+max_drawdown+"</b></html>";
//------ End of Calculating the Maximal Drawdown
average = new JLabel(avg_str);
max_dr = new JLabel(max_dr_str);
bottom_panel = new JPanel();
String space = " ";
JLabel space_lbl = new JLabel(space);
bottom_panel.add(average);
bottom_panel.add(space_lbl);
bottom_panel.add(max_dr);
//-------- Start of table creation ---------
if(choice==1)
{
table = new JTable(split_data_clone, columnNames);//creates an instance of the table with chronological order
}else
{
table = new JTable(split_data_reverse, columnNames);//creates an instance of the table with reverse chronological order
}
TableColumn column = null;
for (int i = 0; i < 7; i++) {
column = table.getColumnModel().getColumn(i);
if (i == 0) {
column.setPreferredWidth(100); //third column is bigger
} else if (i == 5) {
column.setPreferredWidth(85); //third column is bigger
}
else if (i == 6) {
column.setPreferredWidth(70); //third column is bigger
}
else {
column.setPreferredWidth(50);
}
}
table.setShowGrid(true);
table.setGridColor(Color.black);
//-------- End of table creation ---------
JPanel table_panel = new JPanel (new BorderLayout());
JScrollPane table_container = new JScrollPane(table); // create a container where we will put the table
//table.setFillsViewportHeight(true); // if the information are not enough it still fill the rest of the screen with cells
table_panel.add(table_container, BorderLayout.CENTER);
table_panel.add(bottom_panel, BorderLayout.SOUTH);
//table_panel.add();
setContentPane (table_panel);
pack(); // here i pack the final result to decrease its dimensions
}
public float Round(float Rval, int Rpl) // this functions rounds the number to 2 decimal points
{
float p = (float)Math.pow(10,Rpl);
Rval = Rval * p;
float tmp = Math.round(Rval);
return (float)tmp/p;
}
}
I am making an application which creates various instances of a class. These instances are actually some windows. After having create multiple of these windows, how can I access one of them and bring it in front? I know the .tofront() method, but how can I specify the window that I want to bring in front?
Above is the code that creates every window. My main problem is that after I have create e.g 5 windows, how can I access one of them?
ps
code that creates each window:
if (sData != null) {
//System.out.println("Success, waiting response");
vasilisTable ftable = new vasilisTable(name, sData, choice);
hashMap.put(name, ftable);
ftable.setVisible(true);
//choice=2;
}
My main problem is that after I have create e.g 5 windows, how can I access one of them?
You have to keep a reference to the relevant objects in variables or an array or a collection or something. The "bring it to the front" function needs to:
figure out what domain object needs to be brought to the front,
lookup its corresponding JFrame, and
call toFront() on it.
Java provides no built-in mechanisms for finding previously created instances of objects.
When you create your various instances of the above JFrame, you can keep track of the created instances, may be store them within a HashMap, then you can pick the right JFrame instance basing on its designated name and bring it to the front. Have a look at the below code for more illustration:
HashMap<String, VasilisTable> hashMap = new HashMap<String, VasilisTable>();
JFrame firstWindow = new VasilisTable("firstWindow",data, choice);
hashMap.put("firstWindow", firstWindow);
JFrame secondWindow = new VasilisTable("secondWindow",data, choice);
hashMap.put("secondWindow", secondWindow);
JFrame thirdWindow = new VasilisTable("thirdWindow",data, choice);
hashMap.put("thirdWindow", thirdWindow);
// To bring a certain window to the front
JFrame window = hashMap.get("firstWindow");
window.setVisible(true);
window.toFront();
Are these JFrame or JWindow objects? If they are you can call -
jframe.setVisible(true);
jframe.toFront();
This is something interesting I found at the API doc.
Places this Window at the top of the stacking order and shows it in
front of any other Windows in this VM. No action will take place if
this Window is not visible. Some platforms do not allow Windows which
own other Windows to appear on top of those owned Windows. Some
platforms may not permit this VM to place its Windows above windows of
native applications, or Windows of other VMs. This permission may
depend on whether a Window in this VM is already focused. Every
attempt will be made to move this Window as high as possible in the
stacking order; however, developers should not assume that this method
will move this Window above all other windows in every situation.
I would recommend you to check out these answers as well.
Java Swing: JWindow appears behind all other process windows, and will not disappear
Java: How can I bring a JFrame to the front?

How can I pass a non final variable to an anonymous inner class?

I have these lines of code. I know you can not pass a non final variable to an inner class but I need to pass the variable i to the anonymous inner class to be used as a seatingID. Can you suggest ways of doing that ?
JButton [] seats = new JButton [40]; //creating a pointer to the buttonsArray
for (int i = 0; i < 40; i++)
{
seats[i] = new JButton();//creating the buttons
seats[i].setPreferredSize(new Dimension(50,25));//button width
panel4seating.add(seats[i]);//adding the buttons to the panels
seats[i].addActionListener(new ActionListener()
{ //anonymous inner class
public void actionPerformed(ActionEvent evt)
{
String firstName = (String)JOptionPane.showInputDialog("Enter First Name");
String lastName = (String)JOptionPane.showInputDialog("Enter Last Name");
sw101.AddPassenger(firstName, lastName, seatingID);
}
});
}
The simple way is to create a local final variable and initialize it with the value of the loop variable; e.g.
JButton [] seats = new JButton [40]; //creating a pointer to the buttonsArray
for (int i = 0; i < 40; i++)
{
seats[i] = new JButton();//creating the buttons
seats[i].setPreferredSize(new Dimension(50,25));//button width
panel4seating.add(seats[i]);//adding the buttons to the panels
final int ii = i; // Create a local final variable ...
seats[i].addActionListener(new ActionListener()
{ //anonymous inner class
public void actionPerformed(ActionEvent evt)
{
String firstName = (String)JOptionPane.showInputDialog("Enter First Name");
String lastName = (String)JOptionPane.showInputDialog("Enter Last Name");
sw101.AddPassenger(firstName, lastName, ii);
}
});
}
You can't directly, but you can make a (static private) subclass of ActionListener that takes a seatingID in its constructor.
Then rather than
seats[i].addActionListener(new ActionListener() { ... });
you'd have
seats[i].addActionListener(new MySpecialActionListener(i));
[Edit] Actually, there's so much else wrong with your code that I'm not really sure that this advice is good. How about presenting code that would compile.

Categories

Resources