2012-09-13 25 views
5

Mam dwie klasy w tym samym pakiecie. zadeklarowałem static variable w jednej klasie i chcę uzyskać dostęp do tej zmiennej w innej klasie.Dostęp do zmiennej statycznej z innej klasy

Oto mój kod, w którym zadeklarowały statycznej zmiennej

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

Oto kod, w którym chcę, aby uzyskać dostęp do zmiennej

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

Mogę jednak przekazać zmienną z pierwszą klasa jako argument. ale problem polega na tym, że kiedy uruchomię program, wartość po raz pierwszy będzie null, czego nie chcę. Chcę, gdy wprowadzę wartość w textfield, a następnie powinien przejść do innej klasy.

Dziękuję.

+7

Co masz na myśli, mówiąc, że "wartość jest równa zeru"? Zasadniczo powinieneś zmieniać projekt - posiadanie zmiennej globalnej naprawdę nie jest dobrym rozwiązaniem. –

+1

Zgadzam się z @jon. Twój ciąg nie będzie miał przyzwoitą wartość, dopóki użytkownik nie będzie miał szansy go zmienić. Również twoja pętla forever for nie jest dobrym projektem dla aplikacji Swing. Zastanawiam się, czy naprawdę chcesz użyć detektora zamiast tego, aby słuchać, że użytkownik zmienia stan JTextField, a następnie działa w tym kierunku. Być może będziesz także chciał zaglądać do gry używając Swing Timer, ale trudno się z nim zapoznać, dopóki nie dowiemy się więcej o twoim programie io tym, co powinien zrobić. –

+0

Poinformuj nas: co próbujesz zrobić z tym kodem? –

Odpowiedz

2

Proponuję użyć detektora jednego lub drugiego rodzaju, aby umożliwić obiektowi Game nasłuchiwanie i reagować na zmiany w stanie obiektu GUI. Istnieje kilka sposobów, aby to zrobić, ale jednym z najbardziej eleganckich i użytecznych, jakie znalazłem, jest wykorzystanie własnego wrodzonego PropertyChangeSupport Swinga, aby umożliwić korzystanie z PropertyChangeListeners. Wszystkie komponenty Swing umożliwiają dodanie do niego obiektu PropertyChangeListener.A więc proponuję, aby to zrobić, że trzeba Gra dodasz do swojej klasy WampusGUI (które powinny być kapitalizowane) obiektu tak:

public Game(WampusGUI w) { 
    gui = w; 

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

Pozwoli to gra do nasłuchiwania zmian w stanie GUI za.

Będziesz wtedy chciał, aby komenda użytkownika GUI była "właściwością związaną", co oznacza, że ​​daje ona metodę ustawiającą, która będzie uruchamiała obsługę zmiany właściwości, powiadamiając wszystkich odbiorców o zmianie. Chciałbym zrobić to tak:

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

Następnie należy zmienić wartość tylko ten ciąg za pośrednictwem tej metody setter:

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

zmiana nieruchomość słuchacz Gra byłaby następnie odpowiedzieć tak:

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

     } 

    } 
    }); 

Jedną z piękności tej techniki jest to, że obserwowana klasa, GUI, nie musi mieć żadnej wiedzy o klasie obserwatorów (Grze). Niewielki, działający przykład tego jest następujący:

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

} 
0

zgadzam się z Jon Skeet, że nie jest to dobre rozwiązanie ...

Jednak w przypadku u Chcesz brudny rozwiązanie problemu ur następnie u może spróbuj tego:

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

w drugiej wykorzystanie klasy:

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

Ten rodzaj kodu jest obecny w niektórych naszych starszych projektach ... i nienawidzę tego.

+0

Nie ma takiej potrzeby, a istnieje wiele bardziej eleganckich rozwiązań. –

+0

Nigdy nie powiedziałem, że to jest eleganckie rozwiązanie;) –

+0

Prawda. Sądzę, że to zależy od tego, czy programista chce, aby dane były przesyłane przez słuchacza lub pobierane przez odpytywanie. Jeśli to możliwe, preferuję podejście słuchacza, ale nie zawsze jest to możliwe. –

4

Patrząc na kod, wydaje się, chcesz pokazać dialogi do swojego użytkownika z pewnym tekstem

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

i czasami, że dialog powinien przechwytywania danych wprowadzonych przez użytkownika, który jest obsługiwany później.

  1. Te połączenia setTextArea nie są tym, z których chcesz korzystać. Użytkownik nigdy nie zobaczy wiadomości powitalnej, ponieważ zostanie natychmiast zastąpiony przez komunikat opisujący.
  2. Upewnij się, że nie blokujesz wątku wysyłki zdarzeń (EDT) lub nic nie będzie wyświetlane. Nie wiem, co zrobi twoja klasa Command, ale widzę nieskończoną pętlę na Event Dispatch Thread, która nigdy nie jest dobra. Aby uzyskać więcej informacji, patrz:
  3. Dzięki tej pętli for użytkownik po prostu nie będzie mógł wprowadzić żadnego polecenia, ponieważ EDT jest zajęty obsługą pętli. To, czego potrzebujesz, to wywołanie blokujące, pozwalające użytkownikowi na wprowadzenie danych wejściowych (nie blokowanie EDT, a jedynie blokowanie wykonania twojego kodu). Metody statyczne w klasie JOptionPane idealnie do tego nadają się (np. JOptionPane#showInputDialog). Metody te mają również mechanizm przekazywania danych wejściowych użytkownika z powrotem do kodu wywołującego bez żadnych zmiennych statycznych, co rozwiązuje problem.
Powiązane problemy