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