Access static variable from another class

14,410

Solution 1

I suggest that you use a listener of one sort or another to allow the Game object to listen for and respond to changes in the state of the GUI object. There are several ways to do this, but one of the most elegant and useful I've found is to use Swing's own innate PropertyChangeSupport to allow you to use PropertyChangeListeners. All Swing components will allow you to add a PropertyChangeListener to it. And so I suggest that you do this, that you have Game add one to your WampusGUI class (which should be capitalized) object like so:

public Game(WampusGUI w) {
  gui = w;

  gui.addPropertyChangeListener(new PropertyChangeListener() {
     // ....
  }

This will allow Game to listen for changes in the gui's state.

You'll then want to make the gui's userCommand String a "bound property" which means giving it a setter method that will fire the property change support notifying all listeners of change. I would do this like so:

public class WampusGUI extends JFrame {
   public static final String USER_COMMAND = "user command";
   // ....

   private void setUserCommand(String userCommand) {
      String oldValue = this.userCommand;
      String newValue = userCommand;
      this.userCommand = userCommand;
      firePropertyChange(USER_COMMAND, oldValue, newValue);
   } 

Then you would only change this String's value via this setter method:

private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
  setUserCommand(commandText.getText());
}

The Game's property change listener would then respond like so:

  gui.addPropertyChangeListener(new PropertyChangeListener() {

     @Override
     public void propertyChange(PropertyChangeEvent pcEvt) {

        // is the property being changed the one we're interested in?
        if (WampusGUI.USER_COMMAND.equals(pcEvt.getPropertyName())) {

           // get user command:
           String userCommand = pcEvt.getNewValue().toString();

           // then we can do with it what we want
           play(userCommand);

        }

     }
  });

One of the beauties of this technique is that the observed class, the GUI, doesn't have to have any knowledge about the observer class (the Game). A small runnable example of this is like so:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

public class WampusGUI extends JFrame {
   public static final String USER_COMMAND = "user command";
   private String userCommand;
   private JTextArea displayTextArea = new JTextArea(10, 30);
   private JTextField commandText = new JTextField(10);

   public WampusGUI() {
      initComponents();
   }

   private void setUserCommand(String userCommand) {
      String oldValue = this.userCommand;
      String newValue = userCommand;
      this.userCommand = userCommand;
      firePropertyChange(USER_COMMAND, oldValue, newValue);
   }

   private void initComponents() {
      displayTextArea.setEditable(false);
      displayTextArea.setFocusable(false);
      JButton enterButton = new JButton("Enter Command");
      enterButton.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent evt) {
            enterButtonActionPerformed(evt);
         }
      });
      JPanel commandPanel = new JPanel(); 
      commandPanel.add(commandText);
      commandPanel.add(Box.createHorizontalStrut(15));
      commandPanel.add(enterButton);

      JPanel mainPanel = new JPanel();
      mainPanel.setLayout(new BorderLayout());
      mainPanel.add(new JScrollPane(displayTextArea));
      mainPanel.add(commandPanel, BorderLayout.SOUTH);
      add(mainPanel);
   }

   public void setTextArea(String text) {
      displayTextArea.append(text);
   }

   private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
      setUserCommand(commandText.getText());
   }

   public static void main(String args[]) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            WampusGUI w = new WampusGUI();
            w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            w.pack();
            w.setLocationRelativeTo(null);
            w.setVisible(true);
            Game g = new Game(w);
            g.play();
         }
      });
   }
}

class Game {
   private WampusGUI gui;

   public Game(WampusGUI w) {
      gui = w;

      gui.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {

            // is the property being changed the one we're interested in?
            if (WampusGUI.USER_COMMAND.equals(pcEvt.getPropertyName())) {

               // get user command:
               String userCommand = pcEvt.getNewValue().toString();

               // then we can do with it what we want
               play(userCommand);

            }
         }
      });
   }

   public void play() {
      gui.setTextArea("Welcome!\n");
      gui.setTextArea("Please enjoy the game!\n");
   }

   public void play(String userCommand) {
      // here we can do what we want with the String. For instance we can display it in the gui:
      gui.setTextArea("User entered: " + userCommand + "\n");
   }

}

Solution 2

Looking at your code, it seems you want to show dialogs to your user with a certain text

gui.setTextArea(welcome());
gui.setTextArea(describe());

and sometimes, that dialog should capture user input which is handled afterwards.

  1. Those setTextArea calls are not what you want to use. The user will never see the welcome message as it will immediately be replaced by the describe message.
  2. Make sure you do not block the Event Dispatch Thread (EDT) or nothing will be shown at all. I do not know what your Command class will do, but I see an infinite loop on the Event Dispatch Thread which is never a good thing. Take a look at the Concurrency in Swing tutorial for more information
  3. Thanks to that for loop, the user will simply not be capable to input any command as the EDT is busy handling your loop. What you need is a blocking call allowing the user to provide input (not blocking the EDT, but just blocking the execution of your code). The static methods in the JOptionPane class are perfectly suited for this (e.g. the JOptionPane#showInputDialog). These methods also have a mechanism to pass the user input back to the calling code without any static variables, which solves your problem.
Share:
14,410
RK.
Author by

RK.

Programmer.

Updated on June 22, 2022

Comments

  • RK.
    RK. about 2 years

    I have two classes in same package. i have declared a static variable in one class and want to access that variable in another class.

    Here is my code in which i have declared the static variable

    public class wampusGUI extends javax.swing.JFrame {
    
        static String userCommand;
    
        public wampusGUI() {
            initComponents();
        }
    
        public void setTextArea(String text) {
            displayTextArea.append(text);
        }
    
        private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
            userCommand = commandText.getText();
        }
    
        public static void main(String args[]) {
            /* Create and display the form */
            java.awt.EventQueue.invokeLater(new Runnable() {
    
                public void run() {
                    wampusGUI w = new wampusGUI();
                    w.setVisible(true);
                    Game g = new Game(w);
                    g.play();
                }
            });
        }
    }
    

    Here is the code in which i want to access variable

    public class Game {
    
        private wampusGUI gui;
    
        public Game(wampusGUI w) {
            world = new World();
            world.start();
            gui = w;
        }
    
        public void play() {
            gui.setTextArea(welcome());
            gui.setTextArea(describe());
            for (;;) {
                String s = userCommand; // here value should come should 
                System.out.println(userCommand);
                Command c = Command.create(s);
                String r = c.perform(world);
                // is game over?
                if (r == null) {
                    break;
                }
                System.out.println(r);
            }
            System.out.println("Game over");
        }
    }
    

    However, i can pass the variable from first class as a argument. but the problem is that, when i will run program the value is going null first time, which i dont want. i want when i enter value in textfield then it should go to another class.

    Thank you.

  • Hovercraft Full Of Eels
    Hovercraft Full Of Eels almost 12 years
    There's no need for this, and there are much more elegant solutions.
  • PC.
    PC. almost 12 years
    i never told that this is an elegant solution ;)
  • Hovercraft Full Of Eels
    Hovercraft Full Of Eels almost 12 years
    True. I guess it depends if the programmer wants to have the data pushed via a listener or pulled via polling. If possible, I prefer the listener approach, but this isn't always possible to do.