1

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

null でクリアする前に、chatPane に入力されたテキストに「sendText」を設定しているところです。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.

ただし、ボックス変数に実行可能なオブジェクト参照を与えることは決してないため、それを使用しようとすると、もちろん null になります。

しかし、もっと重要なのは、このようなことを行うコードが見当たらないので、これら 2 つのクラスをどのように接続しようとしているのかということです。

解決策は、最初にオブジェクトをどのように接続し、相互に通信するかを考えてから、これが起こるようにコードを書くことです。おそらく、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 プログラムでこれらの構造を使用しないようにする必要があります。

KeyListener を使用する JTextArea ではなく、ActionListener を使用して入力テキストを受け入れる JTextField を使用することをお勧めします。たとえば、この質問に対する私の回答のコードを見てください。


編集 2
相互に通信する 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 に答える