JScrollPane 没有出现在 JFrame 中
JScrollPane doesn't show up in JFrame
那里。我正在编写一个 GUI 聊天客户端,它向服务器发送消息并从服务器接收回显。
客户端 JFrame 的上半部分包含一个包裹在 JScrollPane 中的 JTextArea,该 JTextArea 位于菜单栏下方。这个 JScrollPane 负责接收来自服务器的响应,服务器接收来自客户端的消息并将其广播给所有客户端。因此,客户端专门使用一个单独的线程来接收消息。
下半部分包含一个 JPanel,它本身包含一个 JTextArea 和一个 JButton。此 JPanel 负责接收用户的输入作为消息并将其发送到服务器。
现在的问题是,当客户端JFrame为运行时,JFrame的上半部分,即带有JTextArea的JScrollPane没有出现在JFrame的上半部分。另一个问题是,尽管我已将 JTextArea 设置为可编辑,但我无法在下半部分的 JTextArea 中键入任何内容。
请帮我破解这两个迷思。非常感谢!
客户端代码如下:
package chatroom;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class MultithreadEchoChatroomClientGUI {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable () {
public void run () {
ClientFrame client = new ClientFrame();
client.setTitle("Chat");
client.setSize(400, 500);
client.setVisible(true);
}
});
}
}
class ClientFrame extends JFrame {
private Socket socket;
private Scanner input;
private PrintWriter output;
private JTextArea serverResponseArea;
private JTextArea messageArea;
private JButton sendButton;
private static final int PORT = 1234;
public ClientFrame () {
initNetwork();
initFrame();
}
private void initNetwork () {
String address;
InetAddress host = null;
address = JOptionPane.showInputDialog("Enter the host name or IP address:");
try {
host = InetAddress.getByName(address);
}
catch (UnknownHostException uhEx) {
JOptionPane.showMessageDialog(null, "Unknown Host!", "Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
try {
socket = new Socket(host, PORT);
input = new Scanner(socket.getInputStream());
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(null, ioEx.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
try {
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(this, "Cannot create input or output stream!", "Error", JOptionPane.ERROR_MESSAGE);
closeSocket();
System.exit(1);
}
}
private final void closeSocket () {
try {
socket.close();
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(this, "Cannot disconnect from chatroom!", "Error", JOptionPane.ERROR_MESSAGE);
}
}
private void initFrame () {
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
JScrollPane responsePanel = createResponsePanel();
add(responsePanel, BorderLayout.NORTH);
JPanel messagePanel = createMessagePanel();
add(messagePanel, BorderLayout.CENTER);
addWindowListener(new WindowAdapter () {
@Override
public void windowClosing (WindowEvent we) {
closeSocket();
System.exit(0);
}
});
new Thread(new Runnable () {
public void run () {
String clientName = null;
String serverResponse = null;
Scanner in = null;
PrintWriter out = null;
try {
in = new Scanner(socket.getInputStream());
out = new PrintWriter(socket.getOutputStream());
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(ClientFrame.this, "Cannot create input or output stream!",
"Error", JOptionPane.ERROR_MESSAGE);
closeSocket();
System.exit(1);
}
do {
clientName = JOptionPane.showInputDialog("What nickname would you like to use in the chatroom?");
} while (clientName == null);
out.println("#" + clientName);
serverResponse = in.nextLine();
serverResponseArea.append(serverResponse);
}
}).start();
}
private JMenuBar createMenuBar () {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Operations");
JMenuItem quit = new JMenuItem("Quit");
quit.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent event) {
closeSocket();
System.exit(0);
}
});
menu.add(quit);
menuBar.add(menu);
return menuBar;
}
private JScrollPane createResponsePanel () {
JScrollPane scrlPane = new JScrollPane();
scrlPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 10, 20));
serverResponseArea = new JTextArea(30, 50);
serverResponseArea.setEditable(false);
serverResponseArea.setLineWrap(true);
serverResponseArea.setWrapStyleWord(true);
scrlPane.add(serverResponseArea);
return scrlPane;
}
private JPanel createMessagePanel () {
JPanel msgPanel = new JPanel();
msgPanel.setBorder(BorderFactory.createEmptyBorder(20,10, 10, 20));
msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.LINE_AXIS));
JScrollPane srlPanel = createMessageTextPanel();
msgPanel.add(srlPanel);
JButton sdButton = createSendButton();
msgPanel.add(sdButton);
return msgPanel;
}
private JScrollPane createMessageTextPanel () {
JScrollPane mtPanel = new JScrollPane();
messageArea = new JTextArea(15, 35);
messageArea.setEditable(true);
messageArea.setLineWrap(true);
messageArea.setWrapStyleWord(true);
mtPanel.add(messageArea);
return mtPanel;
}
private JButton createSendButton () {
JButton button = new JButton("Send");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent event) {
String message;
message = messageArea.getText();
output.println(message);
messageArea.setText("");
}
});
return button;
}
}
根据@MadProgrammer 提供的线索,我发现问题出在我将 JTextArea 添加到 JScrollPane 的方式上。它不应该通过 scrlPane.add(serverResponseArea);
完成,而应该通过 JScrollPane scrlPane = new JScrollPane(serverResponseArea);
完成。
但是,既然 scrlPane.add(serverResponseArea);
没有达到目的或产生任何明显的视觉效果,为什么编译器一开始就放过它,而运行时没有抛出这样的异常?这不是图书馆设计中的错误吗? add
mehtod 可能是从父组件继承的,但是如果它是 'useless' 给子组件,为什么不把它踢出子组件呢?也许有某种原因让该方法继续留在子组件中,但它可能会导致问题。
那里。我正在编写一个 GUI 聊天客户端,它向服务器发送消息并从服务器接收回显。
客户端 JFrame 的上半部分包含一个包裹在 JScrollPane 中的 JTextArea,该 JTextArea 位于菜单栏下方。这个 JScrollPane 负责接收来自服务器的响应,服务器接收来自客户端的消息并将其广播给所有客户端。因此,客户端专门使用一个单独的线程来接收消息。
下半部分包含一个 JPanel,它本身包含一个 JTextArea 和一个 JButton。此 JPanel 负责接收用户的输入作为消息并将其发送到服务器。
现在的问题是,当客户端JFrame为运行时,JFrame的上半部分,即带有JTextArea的JScrollPane没有出现在JFrame的上半部分。另一个问题是,尽管我已将 JTextArea 设置为可编辑,但我无法在下半部分的 JTextArea 中键入任何内容。
请帮我破解这两个迷思。非常感谢!
客户端代码如下:
package chatroom;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class MultithreadEchoChatroomClientGUI {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable () {
public void run () {
ClientFrame client = new ClientFrame();
client.setTitle("Chat");
client.setSize(400, 500);
client.setVisible(true);
}
});
}
}
class ClientFrame extends JFrame {
private Socket socket;
private Scanner input;
private PrintWriter output;
private JTextArea serverResponseArea;
private JTextArea messageArea;
private JButton sendButton;
private static final int PORT = 1234;
public ClientFrame () {
initNetwork();
initFrame();
}
private void initNetwork () {
String address;
InetAddress host = null;
address = JOptionPane.showInputDialog("Enter the host name or IP address:");
try {
host = InetAddress.getByName(address);
}
catch (UnknownHostException uhEx) {
JOptionPane.showMessageDialog(null, "Unknown Host!", "Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
try {
socket = new Socket(host, PORT);
input = new Scanner(socket.getInputStream());
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(null, ioEx.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
try {
input = new Scanner(socket.getInputStream());
output = new PrintWriter(socket.getOutputStream(), true);
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(this, "Cannot create input or output stream!", "Error", JOptionPane.ERROR_MESSAGE);
closeSocket();
System.exit(1);
}
}
private final void closeSocket () {
try {
socket.close();
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(this, "Cannot disconnect from chatroom!", "Error", JOptionPane.ERROR_MESSAGE);
}
}
private void initFrame () {
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
JScrollPane responsePanel = createResponsePanel();
add(responsePanel, BorderLayout.NORTH);
JPanel messagePanel = createMessagePanel();
add(messagePanel, BorderLayout.CENTER);
addWindowListener(new WindowAdapter () {
@Override
public void windowClosing (WindowEvent we) {
closeSocket();
System.exit(0);
}
});
new Thread(new Runnable () {
public void run () {
String clientName = null;
String serverResponse = null;
Scanner in = null;
PrintWriter out = null;
try {
in = new Scanner(socket.getInputStream());
out = new PrintWriter(socket.getOutputStream());
}
catch (IOException ioEx) {
JOptionPane.showMessageDialog(ClientFrame.this, "Cannot create input or output stream!",
"Error", JOptionPane.ERROR_MESSAGE);
closeSocket();
System.exit(1);
}
do {
clientName = JOptionPane.showInputDialog("What nickname would you like to use in the chatroom?");
} while (clientName == null);
out.println("#" + clientName);
serverResponse = in.nextLine();
serverResponseArea.append(serverResponse);
}
}).start();
}
private JMenuBar createMenuBar () {
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Operations");
JMenuItem quit = new JMenuItem("Quit");
quit.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent event) {
closeSocket();
System.exit(0);
}
});
menu.add(quit);
menuBar.add(menu);
return menuBar;
}
private JScrollPane createResponsePanel () {
JScrollPane scrlPane = new JScrollPane();
scrlPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 10, 20));
serverResponseArea = new JTextArea(30, 50);
serverResponseArea.setEditable(false);
serverResponseArea.setLineWrap(true);
serverResponseArea.setWrapStyleWord(true);
scrlPane.add(serverResponseArea);
return scrlPane;
}
private JPanel createMessagePanel () {
JPanel msgPanel = new JPanel();
msgPanel.setBorder(BorderFactory.createEmptyBorder(20,10, 10, 20));
msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.LINE_AXIS));
JScrollPane srlPanel = createMessageTextPanel();
msgPanel.add(srlPanel);
JButton sdButton = createSendButton();
msgPanel.add(sdButton);
return msgPanel;
}
private JScrollPane createMessageTextPanel () {
JScrollPane mtPanel = new JScrollPane();
messageArea = new JTextArea(15, 35);
messageArea.setEditable(true);
messageArea.setLineWrap(true);
messageArea.setWrapStyleWord(true);
mtPanel.add(messageArea);
return mtPanel;
}
private JButton createSendButton () {
JButton button = new JButton("Send");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent event) {
String message;
message = messageArea.getText();
output.println(message);
messageArea.setText("");
}
});
return button;
}
}
根据@MadProgrammer 提供的线索,我发现问题出在我将 JTextArea 添加到 JScrollPane 的方式上。它不应该通过 scrlPane.add(serverResponseArea);
完成,而应该通过 JScrollPane scrlPane = new JScrollPane(serverResponseArea);
完成。
但是,既然 scrlPane.add(serverResponseArea);
没有达到目的或产生任何明显的视觉效果,为什么编译器一开始就放过它,而运行时没有抛出这样的异常?这不是图书馆设计中的错误吗? add
mehtod 可能是从父组件继承的,但是如果它是 'useless' 给子组件,为什么不把它踢出子组件呢?也许有某种原因让该方法继续留在子组件中,但它可能会导致问题。