尝试从另一个面板获取文本时出现NullPointerException

时间:2013-08-26 00:21:18

标签: java swing nullpointerexception

我在按Enter键时尝试将sendText发送到我的messagePane。但是,我每次都会继续获得NPE,无论如何我都会尝试。

public class ChatBox extends JPanel {

private JScrollPane scrollPane;
private String sendText;

public ChatBox() {
    final JTextArea chatPane = new JTextArea();

    scrollPane = new JScrollPane(chatPane,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    add(scrollPane);
    scrollPane.setMinimumSize(new Dimension(550, 50));
    scrollPane.setPreferredSize(new Dimension(550, 50));

    chatPane.addKeyListener(new KeyListener() {

        @Override
        public void keyPressed(KeyEvent e) {
        }

        @Override
        public void keyReleased(KeyEvent e) {
            if( e.getKeyCode() == KeyEvent.VK_ENTER ) {
                sendText = chatPane.getText();
                chatPane.setText(null);
                System.out.println(sendText); // I can see this in console
            }

        }

        @Override
        public void keyTyped(KeyEvent e) {
        }

    });

}


public String getSendText() {
    return sendText;
}


public void setSendText(String sendText) {
    this.sendText = sendText;
}}

这就是我将“sendText”设置为在使用null清除之前在chatPane上输入的文本的位置。控制台上用于sendText的sysout显示了我输入的内容,这意味着代码直到那时我很希望。

然后当我尝试在MessageWindow类中抓取它时:

public class MessageWindow extends JPanel {

private ChatBox box;

public MessageWindow() {
    JTextArea messagePane = new JTextArea();

    setLayout(new GridBagLayout());

    GridBagConstraints gc = new GridBagConstraints();

    gc.weightx = 1;
    gc.weighty = 1;
    gc.fill = GridBagConstraints.BOTH;
    gc.insets = new Insets(5, 5, 5, 5);
    add(new JScrollPane(messagePane), gc);


    messagePane.append(box.getSendText());   // Here is where I am getting the NPE.

}}

新代码:

public class MessageWindow extends JPanel {

ChatBox box = new ChatBox();

public MessageWindow() {
    JTextArea messagePane = new JTextArea();

    setLayout(new GridBagLayout());

    GridBagConstraints gc = new GridBagConstraints();

    gc.weightx = 1;
    gc.weighty = 1;
    gc.fill = GridBagConstraints.BOTH;
    gc.insets = new Insets(5, 5, 5, 5);
    add(new JScrollPane(messagePane), gc);

    System.out.println(box.getText());  // Getting null in the console.
    messagePane.append(sendText);   // Not getting anything on messagePane.

}

}

2 个答案:

答案 0 :(得分:4)

您的NPE的原因很明显:

private ChatBox box;

这相当于:

private ChatBox box = null;

然后在这里使用box:

messagePane.append(box.getSendText());   // Here is where I am getting the NPE.

但是你永远不会给box变量任何可行的对象引用,所以当你尝试使用它时,它当然会为null。

但更重要的是,您是如何连接这两个类的,因为我看不到任何代码可以执行此类操作。

解决方案首先要考虑如何连接对象,相互通信,然后编写代码以便实现这一点。也许你想在MessageWindow类中创建一个新的ChatBox对象:

private ChatBox box = new ChatBox();

但是如果一个已经存在且已经是GUI的一部分,那么你实际上并不想这样做。如果已经存在,那么你想做的就是给MessageWindow一个setChat(ChatBox chat)...方法来设置引用,或者通过MessageWindow类的构造函数传递ChatBox引用:

public MessageWindow(ChatBox chat) {
   this.chat = chat;
   // ... plus other constructor-specific code
}

另外,正如评论中所提到的,你不应该在这里使用KeyListener,并且作为一般规则(偶尔会被破坏)应避免在大多数Swing程序中使用这些结构。

我建议你使用一个使用ActionListener来接受输入文本的JTextField,而不是使用KeyListener的JTextArea。例如,请在我对this question的回答中查看我的代码。


编辑2
修改我之前回答的代码,显示两个聊天窗口相互通信:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Scanner;

import javax.swing.*;
import javax.swing.text.JTextComponent;

@SuppressWarnings("serial")
public class TerminalForm extends JPanel {
   private static final int GAP = 3;
   private JTextArea textarea;
   private JTextField textfield;
   private String userName;

   public TerminalForm(String userName, int rows, int cols, InputStream inStream,
         PrintStream printStream) {
      this.userName = userName;
      textarea = prepareTextArea(rows, cols, inStream);
      textfield = prepareTextField(cols, printStream, textarea);

      setLayout(new BorderLayout(GAP, GAP));
      setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      add(new JScrollPane(textarea), BorderLayout.CENTER);
      add(textfield, BorderLayout.SOUTH);
   }

   public String getUserName() {
      return userName;
   }

   private JTextField prepareTextField(int cols, PrintStream printStream,
         JTextArea textArea) {
      JTextField textField = new JTextField(cols);
      textField.addActionListener(new TextFieldListener(printStream, textArea));
      return textField;
   }

   private JTextArea prepareTextArea(int rows, int cols, InputStream inStream) {
      JTextArea textArea = new JTextArea(rows, cols);
      textArea.setEditable(false);
      textArea.setFocusable(false);
      InputStreamWorker instreamWorker = new InputStreamWorker(textArea,
            inStream);
      instreamWorker.execute();
      return textArea;
   }

   private class TextFieldListener implements ActionListener {
      private PrintStream printStream;
      private JTextArea textArea;

      public TextFieldListener(PrintStream printStream, JTextArea textArea) {
         this.printStream = printStream;
         this.textArea = textArea;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         JTextComponent textComponent = (JTextComponent) evt.getSource();
         String text = textComponent.getText();
         textComponent.setText("");

         printStream.println(userName + "> " + text);
         textArea.append(userName + "> " + text + "\n");
      }
   }

   private class InputStreamWorker extends SwingWorker<Void, String> {
      private Scanner scanner;
      private JTextArea textArea;

      private InputStreamWorker(JTextArea textArea, InputStream inStream) {
         this.textArea = textArea;
         scanner = new Scanner(inStream);
      }

      @Override
      protected Void doInBackground() throws Exception {
         while (scanner.hasNextLine()) {
            publish(scanner.nextLine());
         }
         return null;
      }

      @Override
      protected void process(List<String> chunks) {
         for (String chunk : chunks) {
            textArea.append(chunk + "\n");
         }
      }
   }

   private static void createAndShowGui(String userName, final InputStream inStream,
         final PrintStream printStream) {
      int rows = 20;
      int cols = 40;
      TerminalForm mainPanel = new TerminalForm(userName, rows, cols, inStream,
            printStream);

      JFrame frame = new JFrame("Terminal Form: " + userName);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      final PipedOutputStream outStream1 = new PipedOutputStream();
      final PipedInputStream inStream1 = new PipedInputStream();

      try {
         final PipedOutputStream outStream2 = new PipedOutputStream(inStream1);
         final PipedInputStream inStream2 = new PipedInputStream(outStream1);

         createAndShowGui("John", inStream1, new PrintStream(outStream1));
         createAndShowGui("Fred", inStream2, new PrintStream(outStream2));
      } catch (IOException e) {
         e.printStackTrace();
      }

   }
}

运行代码并输入两个聊天JTextFields以查看我的意思。


编辑3
密钥绑定版本

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Scanner;

import javax.swing.*;

@SuppressWarnings("serial")
public class TerminalFormWithTextArea extends JPanel {
   private static final int GAP = 3;
   private static final int ENTER_TEXT_AREA_ROWS = 3;
   private JTextArea textarea;
   private JTextArea enterTextArea;
   private String userName;

   public TerminalFormWithTextArea(String userName, int rows, int cols, InputStream inStream,
         PrintStream printStream) {
      this.userName = userName;
      textarea = prepareTextArea(rows, cols, inStream);
      enterTextArea = prepareEnterTextArea(cols, printStream, textarea);

      setLayout(new BorderLayout(GAP, GAP));
      setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
      add(new JScrollPane(textarea), BorderLayout.CENTER);
      add(new JScrollPane(enterTextArea), BorderLayout.SOUTH);
   }

   public String getUserName() {
      return userName;
   }

   private JTextArea prepareEnterTextArea(int cols, PrintStream printStream,
         JTextArea textArea) {
      JTextArea enterTxtArea = new JTextArea(ENTER_TEXT_AREA_ROWS, cols);
      enterTxtArea.setWrapStyleWord(true);
      enterTxtArea.setLineWrap(true);
      // textField.addActionListener(new TextFieldListener(printStream, textArea));
      int condition = JComponent.WHEN_FOCUSED;
      InputMap inputMap = enterTxtArea.getInputMap(condition);
      ActionMap actionMap = enterTxtArea.getActionMap();

      KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
      String enter = "enter";
      inputMap.put(enterKeyStroke, enter);
      actionMap.put(enter, new EnterAction(printStream, enterTxtArea, textArea));
      return enterTxtArea;
   }

   private JTextArea prepareTextArea(int rows, int cols, InputStream inStream) {
      JTextArea textArea = new JTextArea(rows, cols);
      textArea.setEditable(false);
      textArea.setFocusable(false);
      textArea.setWrapStyleWord(true);
      textArea.setLineWrap(true);
      InputStreamWorker instreamWorker = new InputStreamWorker(textArea,
            inStream);
      instreamWorker.execute();
      return textArea;
   }

   private class EnterAction extends AbstractAction {
      private PrintStream printStream;
      private JTextArea enterTxtArea;
      private JTextArea textArea;

      public EnterAction(PrintStream printStream, JTextArea enterTextArea,
            JTextArea textArea) {
         this.printStream = printStream;
         this.enterTxtArea = enterTextArea;
         this.textArea = textArea;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         String text = userName + "> " + enterTxtArea.getText();
         enterTxtArea.setText("");
         printStream.println(text);
         textArea.append(text + "\n");
      }
   }

   private class InputStreamWorker extends SwingWorker<Void, String> {
      private Scanner scanner;
      private JTextArea textArea;

      private InputStreamWorker(JTextArea textArea, InputStream inStream) {
         this.textArea = textArea;
         scanner = new Scanner(inStream);
      }

      @Override
      protected Void doInBackground() throws Exception {
         while (scanner.hasNextLine()) {
            publish(scanner.nextLine());
         }
         return null;
      }

      @Override
      protected void process(List<String> chunks) {
         for (String chunk : chunks) {
            textArea.append(chunk + "\n");
         }
      }
   }

   private static void createAndShowGui(String userName, final InputStream inStream,
         final PrintStream printStream) {
      int rows = 20;
      int cols = 40;
      TerminalFormWithTextArea mainPanel = new TerminalFormWithTextArea(userName, rows, cols, inStream,
            printStream);

      JFrame frame = new JFrame("Terminal Form: " + userName);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      final PipedOutputStream outStream1 = new PipedOutputStream();
      final PipedInputStream inStream1 = new PipedInputStream();

      try {
         final PipedOutputStream outStream2 = new PipedOutputStream(inStream1);
         final PipedInputStream inStream2 = new PipedInputStream(outStream1);

         createAndShowGui("John", inStream1, new PrintStream(outStream1));
         createAndShowGui("Fred", inStream2, new PrintStream(outStream2));
      } catch (IOException e) {
         e.printStackTrace();
      }

   }
}

答案 1 :(得分:0)

在使用内部方法之前,请先记住new每个实例。