【问题标题】:Access static variable from another class从另一个类访问静态变量
【发布时间】:2012-09-06 02:32:12
【问题描述】:

我在同一个包中有两个类。我已经在一个类中声明了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();
            }
        });
    }
}

这是我要访问变量的代码

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");
    }
}

但是,我可以将第一类的变量作为参数传递。但问题是,当我运行程序时,值第一次变为空,这是我不想要的。我想当我在textfield 中输入值时,它应该转到另一个类。

谢谢。

【问题讨论】:

  • “值第一次变为空”是什么意思?基本上你应该改变你的设计——拥有一个全局变量真的不是一个好的解决方案。
  • 我同意@jon。在用户有机会更改它之前,您的 String 不会有一个像样的价值。此外,对于 Swing 应用程序来说,for 循环也不是一个好的设计。我想知道您是否真的想使用侦听器来侦听用户更改 JTextField 的状态然后对此进行操作。也许您还想考虑使用 Swing Timer,但在我们了解更多关于您的程序及其应该做什么之前很难知道。
  • 请告诉我们:你想用这段代码做什么?
  • 我想要做的是,在第一个 GUI 文件中,当用户应该在 textarea 中输入文本并按 enter 然后该值应该进入另一个类 play() method 并且将执行command class的命令

标签: java swing oop static


【解决方案1】:

我建议您使用一种或另一种侦听器来允许 Game 对象侦听并响应 GUI 对象状态的变化。有几种方法可以做到这一点,但我发现的最优雅和最有用的方法之一是使用 Swing 自己的固有 PropertyChangeSupport 来允许您使用 PropertyChangeListeners。所有 Swing 组件都允许您向其添加 PropertyChangeListener。所以我建议你这样做,让 Game 向你的 WampusGUI 类(应该大写)对象添加一个,如下所示:

public Game(WampusGUI w) {
  gui = w;

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

这将允许 Game 监听 gui 状态的变化。

然后,您需要将 gui 的 userCommand 字符串设置为“绑定属性”,这意味着为其提供一个 setter 方法,该方法将触发属性更改支持,通知所有侦听器更改。我会这样做:

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);
   } 

那么你只能通过这个setter方法改变这个String的值:

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

游戏的属性变化监听器会做出如下响应:

  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);

        }

     }
  });

这种技术的优点之一是被观察类,即 GUI,不必对观察者类(游戏)有任何了解。一个小的可运行示例如下所示:

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");
   }

}

【讨论】:

    【解决方案2】:

    查看您的代码,您似乎想向您的用户显示带有特定文本的对话框

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

    有时,该对话框应捕获用户输入,然后处理。

    1. 那些setTextArea 调用不是您想要使用的。用户永远不会看到欢迎消息,因为它会立即被描述消息替换。
    2. 确保您没有阻塞事件调度线程 (EDT),否则将不会显示任何内容。我不知道你的Command 类会做什么,但我看到Event Dispatch Thread 上有一个无限循环,这绝不是一件好事。查看Concurrency in Swing tutorial 了解更多信息
    3. 感谢for 循环,用户将无法输入任何命令,因为 EDT 正忙于处理您的循环。您需要的是一个允许用户提供输入的阻塞调用(不阻塞 EDT,而只是阻塞代码的执行)。 JOptionPane 类中的静态方法非常适合这种情况(例如 JOptionPane#showInputDialog)。这些方法还具有将用户输入传递回调用代码而不使用任何静态变量的机制,从而解决了您的问题。

    【讨论】:

      【解决方案3】:

      我同意 Jon Skeet 的观点,认为这不是一个好的解决方案...

      但如果你想要一个肮脏的解决方案来解决你的问题,那么你可以试试这个:

      public class wampusGUI extends javax.swing.JFrame
      {
          private static wampusGUI myInstance;
          public wampusGUI( )
          {
              myInstance = this;
              initComponents();
          }
      
          public static void getUserCommand()
          {
              if(myInstance!=null)
              {
                  return myInstance.commandText.getText();
              }
              else
              {
                  return null;
              }
          }
          ......
          ......
      }
      

      在其他类中使用:

      public void play()
      {
          .....
          //String s = userCommand; // here value should come should
          String s = wampusGUI.getUserCommand();
          .....
      }
      

      这种代码存在于我们的一些遗留项目中......我讨厌这样。

      【讨论】:

      • 这个没必要,还有更优雅的解决方案。
      • 我从来没有说过这是一个优雅的解决方案;)
      • 是的。我想这取决于程序员是希望通过侦听器推送数据还是通过轮询获取数据。如果可能的话,我更喜欢监听器的方法,但这并不总是可行的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 1970-01-01
      • 2014-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多