I'm new to Java and I'm wonder if someone can help me with this.
I have a class that's constructor makes a Gui window, and it's main calls this constructor. The problem is the event handling doesn't work because the event handling code can't access the GUI window variables (It just gives errors). I tried putting the Gui code inside main,but then I get errors about accessing non static variables from inside the static main.
This is the code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SwingMenu implements ActionListener{

  public static void main(String[] args) {

SwingMenu s = new SwingMenu();



}

public SwingMenu(){
Toolkit toolkit = Toolkit.getDefaultToolkit();

    // Get size
    Dimension dimension = toolkit.getScreenSize();
    JFrame frame = new JFrame(" ");
    JPanel panel = new JPanel();

panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JMenuBar menubar = new JMenuBar();
    JMenu filemenu = new JMenu("File");
    JMenuItem fileItem1 = new JMenuItem("Exit");
    filemenu.add(fileItem1);
    fileItem1.addActionListener(this);
    menubar.add(filemenu);
    frame.setJMenuBar(menubar);
    JTextArea textArea = new JTextArea(27,27);
    JScrollPane scrollPane = new JScrollPane(textArea);
    panel.add(scrollPane);
     JTextArea textArea2 = new JTextArea(3,3);
    JScrollPane scrollPane2 = new JScrollPane(textArea2);
    panel.add(scrollPane2);
frame.add(panel);
int height = dimension.height-30;
    frame.setSize(dimension.width,height);
    frame.setVisible(true);
}


public void actionPerformed(ActionEvent ev) {

  // this is where I want to handle the events
}
}

Let me know if you need a better explanation.

Dani AI

Generated

The root cause is scope and threading. In your constructor you create components as local variables, so actionPerformed (or any other method) cannot see them. Moving them to instance fields fixes the scope problem. Also build and show Swing UIs on the Event Dispatch Thread (EDT) — main should call SwingUtilities.invokeLater(...) to construct the GUI. is right to suggest class-level fields; is right that separating handlers (inner class / separate class / Action) improves clarity — both approaches are valid.

Concrete tips:

  • Declare components you need in listeners as private instance fields so event handlers can reference them.
  • If you use anonymous inner classes or lambdas, note that local variables must be final (or effectively final), so instance fields are usually simpler when the UI changes state.
  • Register listeners with the menu items (or use Action), and in actionPerformed check either e.getSource() or e.getActionCommand() (or set a dedicated action) to decide what to do. For an Exit item call frame.dispose() (or System.exit(0) if you want a hard exit).
  • Call frame.pack() or frame.setSize(...) and frame.setLocationRelativeTo(null) and then frame.setVisible(true) as the last step.
  • Avoid long work on the EDT; use SwingWorker for background tasks.

Example pattern (minimal, Java 8+ lambda shown):

public static void main(String[] args) {
  SwingUtilities.invokeLater(() -> new SwingMenu().createAndShowGui());
}

private final JFrame frame = new JFrame("Demo");
private final JMenuItem exitItem = new JMenuItem("Exit");

private void createAndShowGui() {
  exitItem.addActionListener(e -> frame.dispose());
  // build menu, add to frame, pack, setDefaultCloseOperation, then:
  frame.pack();
  frame.setLocationRelativeTo(null);
  frame.setVisible(true);
}

This keeps scope clear, runs on the EDT, and makes the Exit handler trivial.

Recommended Answers

All 2 Replies

I think you might be better off listing your GUI components outside the methods. You still initialise your components inside the swingMenu method, but doing it this way gives global access within the class. For example,

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SwingMenu implements ActionListener{
   JMenuBar menuBar;
   JMenu filemenu;
   // etc
   public static void main(String[] args) {
      SwingMenu s = new SwingMenu();
   }

   public SwingMenu(){
      menuBar = new JMenuBar();
      filemenu = new JMenu("File");
      // etc
   }
}

Then you can access the components within the actionPerformed method as needed.

Hope this helps.

Hi curt22 ,

It's best practice to separate event handling method from the event source class(class which contains UI widgets). So that later it will be easy to change that without affecting event source class.

Consider this example :

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SwingMenu {

 
// Inner Class Implementation

 /* 
 
class actionListener implements ActionListener {
   public void actionPerformed(ActionEvent avt) {
   System.out.println("Triggered");
 }
}   */

public static void main(String[] args) {
  
    SwingMenu swingMenu = new SwingMenu();
    

    JMenuBar menuBar = new JMenuBar();
    JMenu file = new JMenu("File");
    JMenuItem demo = new JMenuItem("demo");

    //demo.addActionListener(swingMenu.new actionListener()); // Using Inner class Implementation 
   
    demo.addActionListener(new actionListener()); // Using a Separate class 


    file.add(demo);
    menuBar.add(file);

    JFrame frame = new JFrame("Frame");
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(BorderLayout.NORTH,menuBar);
    frame.setSize(300,400);
  } 
}

// Event Handling class
 class actionListener implements ActionListener {
   public void actionPerformed(ActionEvent avt) {
   System.out.println("Triggered");
 }
}

In this example I have written a separate class for event handling. you can use inner class or a separate class

Hope this helps

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.