我在按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.
}
}
答案 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
每个实例。