0

I have been stuck on this all weekend, i have looked everywhere and not a single solution. All help is appreciated.

    int iDayBirth = Integer.parseInt(jTextField_DoBDay.getText());
    int iMonthBirth = Integer.parseInt(jTextField_DoBMonth.getText());
    int iYearBirth = Integer.parseInt(jTextField_DoBYear.getText());

    int iDayCurrent = Integer.parseInt(jTextField_CdDay.getText());
    int iMonthCurrent = Integer.parseInt(jTextField_CdMonth.getText());
    int iYearCurrent = Integer.parseInt(jTextField_CdYear.getText());

    double iDaysAlive = 0;
    Calendar caBirthDate = new GregorianCalendar(iYearBirth, iMonthBirth - 1, iDayBirth);
    Calendar caCurrentDate = new GregorianCalendar(iYearCurrent, iMonthCurrent - 1, iDayCurrent);

    JButton btnCalculate = new JButton("Calculate");
    btnCalculate.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            iDaysAlive = (caCurrentDate.getTimeInMillis() - caBirthDate.getTimeInMillis());
            iDaysAlive = (iDaysAlive / (24 * 60 * 60 * 1000) + 1);
            // GET THE ERROR HERE: "Cannot refer to a non-final variable caBirthDate inside an inner class defined in a different method
            //get the same error for, caBirthDate and iDaysAlive
        }
    });
    btnCalculate.setFont(new Font("Calibri", Font.BOLD, 12));
    btnCalculate.setBounds(188, 187, 89, 23);
    frame.getContentPane().add(btnCalculate);

    jTextField_Result = new JTextField("Total Days Alive: " + iDaysAlive);
    jTextField_Result.setBounds(150, 233, 170, 20);
    frame.getContentPane().add(jTextField_Result);
    jTextField_Result.setColumns(10);

If i move the calender and integer variable to inside the ActionListener then i can't access the iDaysAlive variable in the final textfield.

theSwein
  • 9
  • 4
  • The variables that aren't declared in `actionPerformed`, but are used in it, [must be declared `final`](http://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class). Or you could use a [lambda](http://java-demos.blogspot.com/2013/03/lambda-expressions-in-java-8-for-actionlistener.html?m=1) – Vince Apr 26 '15 at 07:08

3 Answers3

0

As the error suggests:

Cannot refer to a non-final variable caBirthDate inside an inner class defined in a different method

You need to declare the variables final inorder to access them inside the ActionListener:

final int CURR_X = redSquare.getX();

But be careful:

Making a variable final means that it can/will not be modified by the program. It allows the compiler to optimize some of the code. Also it tells anyone reading the program the variables are CONSTANTS. For example in a program you would define the value of PI as a constant and use that variable in your program instead of typing in 3.14... everywhere you needed to have the value.

For this reason a good solution would be:

To create a class the implements ActionListener class. Then you can have any class access to the variables needed.

Another possible solution:

  1. To wrap the needed variables inside a class as class variables.
  2. Declare a variable from this class as final inside your main class.
  3. Then use its class members to suit your needs

for example:

class Wrapper {
  public int iDaysAlive;

  public Wrapper (int iDaysAlive){
    this.iDaysAlive = iDaysAlive;
  }
}

Then:

int iDaysAlive = 0;
final Wrapper w = new Wrapper(iDaysAlive);

Then in ActionListener:

w.iDaysAlive = (caCurrentDate.getTimeInMillis() - caBirthDate.getTimeInMillis());
GingerHead
  • 8,130
  • 15
  • 59
  • 93
  • thankyou that works for the calenders but not for iDaysAlive because it needs to be changed inside the ActionListener – theSwein Apr 26 '15 at 07:14
  • any chance you could write out the code to implement it with my variables? i understand what you mean but i cant for the life of me put it into practice – theSwein Apr 26 '15 at 07:21
  • ok now im getting an error for: (caCurrentDate.getTimeInMillis() - caBirthDate.getTimeInMillis()); Typer Mistmatch: cannot convert from long to int – theSwein Apr 26 '15 at 07:34
  • Now this is another problem, you should create another question for this one – GingerHead Apr 26 '15 at 07:56
  • If this answer suits your needs and answers your question please to accept it – GingerHead Apr 26 '15 at 07:57
  • I checked your profile, and you seem to have 3 similar questions, with great answers, why do you keep asking the same question several times, when it's already answered?? – GingerHead Apr 26 '15 at 08:04
  • maybe because no ones actually given me a solution that works! – theSwein Apr 26 '15 at 08:21
  • I checked all the answers and they pretty well answer your question – GingerHead Apr 26 '15 at 09:08
  • i thought this was a place beginners could ask questions, most beginners will struggle to get across exactly what they're trying to do. When im only getting answers that create triple the errors to what i already had thats not very encouraging to pursue another question with your added errors – theSwein Apr 26 '15 at 09:12
  • I can't see any errors that my code would generate: the error that you say that this code generates: `caCurrentDate.getTimeInMillis() - caBirthDate.getTimeInMillis()` is not my code, I copy/pasted it from your code – GingerHead Apr 26 '15 at 09:15
  • `getTimeInMillis()` gives a `long` result, and your variable `iDaysAlive` is an `int`. so it's better to declare it as `int` as well or cast the result to `int`, but you would lose some details from the original value in casting – GingerHead Apr 26 '15 at 09:18
  • i think anyone could write an isolated bit of code that doesn't create errors. i had no errors on that part of code until i implemented your solution. What i would have liked is for you to explain this part of your solution "To create a class the implements ActionListener class. Then you can have any class access to the variables needed." because i feel that would work in my situation but i dont know how to write it out. the wrapper class just causes problems – theSwein Apr 26 '15 at 09:19
  • look at this example: https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html – GingerHead Apr 26 '15 at 09:21
  • 1
    @VinceEmigh You kidding me, he hardly gets this one, don't mention any lambda yet pleaaase xxxd – GingerHead Apr 26 '15 at 15:39
  • @GingerHead I'd rather not retract my comment.. If he's interested, he'll look into it and allow himself to decide whether or not it's too difficult. I know programmers who were aware of lambdas before they were aware of anonymous classes. It's beneficial in many ways, and should be mentioned to anyone still using anonymous classes for functional interfaces. – Vince Apr 26 '15 at 15:50
  • 2
    @VinceEmigh Thanks for emphasizing your previous comment, that made me enthusiastic to use more lambda whenever possible ;) – GingerHead Apr 27 '15 at 12:10
0

A solution is to create class the implements Action listener. Then you can give tha class access to the variable needed:

class ActionHandler implements ActionListener {
 public ActionHandler (MainClass mainClass) {
    //now getters of the main class can be called 
 }
    public void actionPerformed(ActionEvent e) { }
}
amnesiac
  • 21
  • 5
0

You declared an anonymous class of ActionListener. Refer to https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html#accessing for oracle's documentation:

An anonymous class cannot access local variables in its enclosing scope that are >not declared as final or effectively final.

Refer to Why a non-final "local" variable cannot be used inside an inner class, and instead a non-final field of the enclosing class can? for why

A work-around for your situation: 1. declare iDaysAlive, caBirthDate, caCurrentDate and other variables you need to access inside the annoymous class in the class scope 2. refactor actionPerformed(ActionEvent e) to call a handler method

actionPerformed(ActionEvent e) {
     handleEvent(e);
}
Community
  • 1
  • 1
Bon
  • 3,073
  • 5
  • 21
  • 40