简体   繁体   中英

Cannot refer to the non-final local variable display defined in an enclosing scope

This might be a very basic question. But I am stuck at this. The error that I get for the String variable display states:

Cannot refer to the non-final local variable display defined in an enclosing scope.

If I use a final keyword, I get the message:

The final local variable display cannot be assigned, since it is defined in an enclosing slope.*

The code is:

public class Frame {

public static void main(String[] args) {
    String display=" ";
    Frame ob=new Frame();
    JFrame frame=new JFrame("Test");
    frame.setBounds(300,100,800,500);
    //Container c=frame.getContentPane(); 
    frame.setLayout(null);
    final JTextField name=new JTextField();
    name.setBounds(500,212,150,20);
    JLabel nameLabel=new JLabel("Name: ");
    nameLabel.setForeground(Color.WHITE);
    nameLabel.setBounds(450,171,100,100);
    JTextField ohr=new JTextField();
    ohr.setBounds(500,282,150,20);
    JLabel ohrID=new JLabel("OHR ID: ");
    ohrID.setForeground(Color.WHITE);
    ohrID.setBounds(450,241,100,100);

    final JButton button=new JButton("Submit");
    button.setBounds(530,350,90,20);
    frame.add(name);
    frame.add(ohr);
    frame.add(ohrID);
    frame.add(nameLabel);
    frame.add(button);
    frame.getContentPane().setBackground(Color.DARK_GRAY);
    frame.setVisible(true);

    button.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            if(e.getSource()==button){
                display=name.getText();
                JOptionPane.showMessageDialog(null, "Hi "+ display);
                System.exit(0);
            }
        }
    });
}

Thanks in advance!

There are multiple issues with your code, and we'll address them right here, right now and solve your problem at the same time.

  1. public class Frame { this particular line has an error, Frame is the name of an AWT class, so it might confuse you or anyone who reads this code later on, give it a more meaningful name and avoid those names that could be confused with other Java packages.

  2. Frame ob=new Frame(); you create an instance of your class and never use it again, why?

  3. frame.setLayout(null); NEVER , please don't use null-layout , Swing has to deal with multiple PLAFs, screen sizes and resolutions, different OS, pixel perfect apps might seem like the easiest way to create complex UIs but later on you'll find that errors like this happen very often.

  4. .setBounds(...) on every component, again, this is due to null-layout but it's better to use Layout managers

  5. final JTextField name=new JTextField(); There's no need to declare any of your components as final , this is due to a poor design of your class, your components should be declared as class members (outside any method including main ).

  6. Speaking about main , separate your program into smaller pieces, don't throw everything at main or at the very least create a method that is not static so you can call it after creating an instance of your class (or else later on you'll end up with tons of static variables and that's a poor design of your class once again).

  7. System.exit(0); it will stop the JVM, it's never a good idea to do that, it's better to .dispose() the JFrame and have your JFrame 's defaultCloseOperation set to EXIT_ON_CLOSE which will safely dispose your app and then stop the JVM.

  8. display=name.getText(); , for this particular case, display could be an inner variable rather than a class member. This will solve your particular question

  9. JOptionPane.showMessageDialog(null, "Hi "+ display); that null should be a reference to your JFrame , this will place your dialog in the middle of that JFrame rather than in the middle of the screen.

  10. You never place your program inside the EDT, see point #2 in this answer .

So, having all the above points in mind, here's an improved version of your code.

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class UsingVariablesInsideActionListenerExample {
    //We declare our components here
    private JFrame frame;
    private JButton button;
    private JTextField name;
    private JTextField ohr;
    private JLabel nameLabel;
    private JLabel ohrID;
    private JPanel pane;
    private JPanel namePane;
    private JPanel ohrPane;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new UsingVariablesInsideActionListenerExample()::createAndShowGUI); //This is using Java 8 lambdas to place your program in the EDT
    }

    private void createAndShowGUI() {
        frame = new JFrame("Test"); //Create your JFrame 
        
        pane = new JPanel();
        pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS)); //This will make this JPanel to arrange components vertically
        
        namePane = new JPanel(); //By default, JPanels have FlowLayout which will arrange components horizontally
        ohrPane = new JPanel();
        
        name = new JTextField(10); //We create a JTextField with 10 columns 
        nameLabel = new JLabel("Name: ");
        nameLabel.setForeground(Color.WHITE);
        
        ohr = new JTextField(10);
        ohrID = new JLabel("OHR ID: ");
        ohrID.setForeground(Color.WHITE);

        button = new JButton("Submit");
        
        //Add the action listener
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == button) {
                    String display = name.getText(); //The display variable is now an inner variable rather than a class member
                    JOptionPane.showMessageDialog(frame, "Hi " + display);
                    frame.dispose(); //We dispose the JFrame and it will be closed after due to EXIT_ON_CLOSE below.
                }
            }
        });
        
        //We add the components to the namePane (horizontally), the order matters
        namePane.add(nameLabel);
        namePane.add(name);
        
        //Now we add these components to the ohrPane (horizontally again)
        ohrPane.add(ohrID);
        ohrPane.add(ohr);
        
        //We then add the name and ohr panes to a bigger JPanel (pane, which if you remember will add them vertically) and we add the button at the end
        pane.add(namePane);
        pane.add(ohrPane);
        pane.add(button);
        
        //We make them non opaque (transparent) so that we can see the background color of the JFrame
        namePane.setOpaque(false);
        ohrPane.setOpaque(false);
        pane.setOpaque(false);
        
        frame.add(pane);
        
        frame.getContentPane().setBackground(Color.DARK_GRAY);
        frame.pack(); //This will get every component's preferred size and make the JFrame as small as possible where it looks good on every OS, PLAF, screen size and resolution.
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true); //We make the frame visible (always at the very end, when we've added everything to it).
    }
}

And this is how it looks like now.

在此处输入图像描述

The UI may not be perfectly equal to the one you have, but I'm sure you can play with the different layout managers, and nest various JPanel s to get a much better looking UI than mine, or at least a more similar one to the one you had.

Variable used in side an inner class should be effectively final. You can use a string[] of length 1 instead of string to resolve this. Please read bellow post for more details

Difference between final and effectively final

Also check this post for more details

Variable used in lambda expression should be final or effectively final

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM