2

I am using eclipse and windows builder --> Swing --> Jframe. I have added textField, lblNewLabel and btnNewButton. By clicking and dropping it on contentPane. When trying to assign a value to a lblNewLabelusing methods lblNewLabel.setText(textField.getText());. I get the following error: Cannot refer to a non-final variable lblNewLabel inside an inner class defined in a different method.

This is my source code:

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;


public class MultAppMed extends JFrame {

    private JPanel contentPane;
    private JTextField textField;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MultAppMed frame = new MultAppMed();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public MultAppMed() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JLabel lblNewLabel = new JLabel("New label");
        lblNewLabel.setBounds(106, 14, 46, 14);
        contentPane.add(lblNewLabel);

        JButton btnNewButton = new JButton("New button");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                lblNewLabel.setText(textField.getText());
            }
        });
        btnNewButton.setBounds(335, 228, 89, 23);
        contentPane.add(btnNewButton);

        textField = new JTextField();
        textField.setBounds(10, 11, 86, 20);
        contentPane.add(textField);
        textField.setColumns(10);
    }

}

Why is this happening? I was reading some answers that say: "Java requires references to variables from inner classes to be final variables" but if needed why doesn't Jframe insert it as such automatically. My textField is working and I can get and set Its value using the same methods. I was meaning to ask why and how to solve this. I appreciate your help.

  • It sounds like you already have a solution to your problem. What is your question? – Keppil Jun 22 '14 at 11:06
  • My question is why do i have to tweak the code to use a simple example of assigning a value to a label. Given that i don't need to do that for a text field. Is it a bug or a feature. And how to do it, what is the best way to achieve that. –  Jun 22 '14 at 11:11
  • what don't you need to do for a text field? Either make `lblNewLabel` final or make it instance member. What you want to achieve? – Braj Jun 22 '14 at 11:13
  • Just make your variable final, for the reason stated in the answers you have read. It is required by design in Java, so it is not a bug. Note that from Java 8, this requirement is not as strict. There Java only requires that the variable is _effectively final_, i.e. not changed after initialization. – Keppil Jun 22 '14 at 11:15
  • I can use text field "textField" methods to get and set its value: textField.getText() but I can't do that for "lblNewLabel" this gives me an error: lblNewLabel.getText() –  Jun 22 '14 at 11:18
  • Yes, `textField` is not a local variable. The restriction only applies to local variables. – Keppil Jun 22 '14 at 11:20
  • @eror404 take a look at my update, found an option inside the window builder which lets you create final local varaibles. – isaias-b Jun 22 '14 at 11:22
  • 1
    @eror404: To understand __WHY__, might be this [example](http://stackoverflow.com/a/13209458/1057230), of mine will help you in the direction :-) – nIcE cOw Jun 22 '14 at 11:43
  • Consider retagging your question to java swing windowbuilder local-variables final to attract other users reading the question if none of the presented answers fit your requirements. – isaias-b Jun 22 '14 at 11:56

2 Answers2

3

You most probably want to change the settings of the window builder with this option "Declare variable as final" on local varaibles.

enter image description here

This should do the trick, since "... . However, a local class can only access local variables that are declared final."

Alternative with fields

Consider using the "convert to local field" operation inside the window builder.

enter image description here

This will change the definition of the label from

JLabel lblNewLabel = new JLabel("New label");

into

private JLabel lblNewLabel;
// in initialization method / c'tor
lblNewLabel = new JLabel("New label");

Environment

Everything tested using

  • eclipse Version: Kepler Service Release 1 | Build id: 20130919-0819
  • window builder Version: 1.6.1 | Build id: 2013.09.10

eclipse.ini

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20130807-1835
-product
org.eclipse.epp.package.standard.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xms40m
-Xmx512m

java version

C:\....\isi>java -version
java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode)
isaias-b
  • 2,255
  • 2
  • 25
  • 38
  • when i do that when and drag and drop I get the: Internal Error WindowBuilder encountered unexpected internal error. This could be caused by a WindowBuilder bug or by a misconfiguration issue, conflict, partial update, etc. java.lang.Error: new JLabel("New label") –  Jun 22 '14 at 11:35
  • Strange: I could change the option without restarting eclipse, but i needed to recreate the label in order to get the correct result. I added the eclipse version and window builder version to the answer – isaias-b Jun 22 '14 at 11:38
1

My question is why do i have to tweak the code to use a simple example of assigning a value to a label. Given that i don't need to do that for a text field

lblNewLabel is a local variable that can't be accessed inside the anonymous inner class until and unless it's final.

JLabel lblNewLabel = new JLabel("New label");

where as textField is instance member that can be accessed easily inside the anonymous inner class.

private JTextField textField;

Inner class and local variables

Local variables always live on the stack, the moment method is over all local variables are gone.

But your inner class objects might be on heap even after the method is over (Say an instance variable holds on to the reference), so in that case it cannot access your local variables since they are gone, unless you mark them as final.

The local variable could change before the inner class accesses it. Making it final prevents that because final variable can't be changed once assigned.

Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76