1

我试图在按下回车后立即将 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.

}

}

4

2 回答 2

4

您的 NPE 的原因很明显:

private ChatBox box;

这相当于:

private ChatBox box = null;

然后在这里你使用盒子:

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

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

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

解决方案是首先考虑您希望对象如何连接,如何相互通信,然后编写代码以便实现这一点。也许您想在 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。例如,请查看我对这个问题的回答中的代码。


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

   }
}
于 2013-08-26T00:24:30.087 回答
0

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

于 2013-08-26T00:40:12.907 回答