所以,想象一个 Chat 类,它包含一个 String ,该 String 表示 chatter(或者更好的是,一个明确定义的 User 类型对象)以及该用户正在发送的文本:
public class Chat {
String name;
String text;
public Chat(String name, String text) {
super();
this.name = name;
this.text = text;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
然后你可以创建一个列表模型和一个 JList 来保存这种类型的对象:
private DefaultListModel<Chat> chatListModel = new DefaultListModel<Chat>();
private JList<Chat> chatList = new JList<Chat>(chatListModel);
然后您可以创建一个渲染器,将 Chatter 的文本显示为默认渲染器文本,并在单个渲染器周围的标题边框中显示 Chatter 的名称(默认渲染器是 JLabel):
private class ChatRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
Chat chat = (Chat) value;
String text = chat.getText();
String name = chat.getName();
JLabel rendererComponent = (JLabel) super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
rendererComponent.setBorder(BorderFactory.createTitledBorder(name));
return rendererComponent;
}
}
整个事情可能看起来像:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class FooGui01 extends JPanel {
private DefaultListModel<Chat> chatListModel = new DefaultListModel<Chat>();
private JList<Chat> chatList = new JList<Chat>(chatListModel);
private JTextField inputField = new JTextField(20);
private JButton submitButton = new JButton("Submit");
public FooGui01() {
chatList.setCellRenderer(new ChatRenderer());
chatList.setPrototypeCellValue(new Chat("John", "abc def ghi jkl abc def ghi jkl abc def ghi jkl abc def ghi jkl abc def ghi jkl abc def ghi jkl "));
chatList.setVisibleRowCount(10);
JScrollPane scrollPane = new JScrollPane(chatList);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
ActionListener listener = new SubmitListener();
inputField.addActionListener(listener);
submitButton.addActionListener(listener);
submitButton.setMnemonic(KeyEvent.VK_S);
JPanel submitPanel = new JPanel();
submitPanel.setLayout(new BoxLayout(submitPanel, BoxLayout.LINE_AXIS));
submitPanel.add(inputField);
submitPanel.add(submitButton);
setLayout(new BorderLayout());
add(scrollPane);
add(submitPanel, BorderLayout.PAGE_END);
}
// public method called by outside code that is wanting to pass chat to you
public void submitChat(Chat chat) {
if (SwingUtilities.isEventDispatchThread()) {
chatListModel.addElement(chat);
} else {
SwingUtilities.invokeLater(() -> chatListModel.addElement(chat));
}
}
private class SubmitListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String text = inputField.getText();
chatListModel.addElement(new Chat("Me", text));
inputField.selectAll();
inputField.requestFocusInWindow();
// here you would send the chat text or object to a socket's output stream
}
}
private class ChatRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
Chat chat = (Chat) value;
String text = chat.getText();
String name = chat.getName();
JLabel rendererComponent = (JLabel) super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
rendererComponent.setBorder(BorderFactory.createTitledBorder(name));
return rendererComponent;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FooGui01 gui = new FooGui01();
frame.add(gui);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}