Simple "console like" chat

Hello,

I want to share with you some code which I have recently finished, which gives respect to the game chat GUI. For the game I’m making, I needed some component, which would allow coloured text, content appending and removing when some limit of lines is reached and some scroll behaviour, which I’ll post after I will implement it ;).

The chat has following aspect

http://game2dei.com/upload/2011/02/console.png

So, as main container of the content I have chosen JTextPane, since it allows HTML(which make possible full personalization of the text, including colour, text styles and much more). But there were several problems and challenges to solve, like appending and removing the text because JTextPane doesn’t have such options.

I’m using the following code for creation of the JTextPane, note that there should be set HTMLEditorKit and HTMLDocument to the JTextPane, else HTML will not be rendered(thanks for people from StackOverflow helping me solve this issue)


this.text_panel = new JTextPane();
this.text_panel.setContentType("text/html");
this.text_panel.setEditable(false);
this.text_panel.setBackground(this.text_background_color);
this.text_panel_html_kit = new HTMLEditorKit();this.text_panel.setEditorKit(text_panel_html_kit);
this.text_panel.setDocument(new HTMLDocument());

scroll_pane = new JScrollPane(this.text_panel);
scroll_pane.setBounds(5,5,580,110);
scroll_pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll_pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
this.add(scroll_pane);

The next step was creating the append function. You will need to work directly with the HTMLDocument set to the JTextPane in previous step. My append function looks like:


public void append(String line){
	SimpleDateFormat date_format = new SimpleDateFormat("HH:mm:ss");
	Date date = new Date();
		
	line = "<div><font size=3 color=GRAY>[" + date_format.format(date) + "]</font><font size=3 color=BLACK>"+ line + "</font></div>";
		
	try {
		this.text_panel_html_kit.insertHTML((HTMLDocument) this.text_panel.getDocument(), this.text_panel.getDocument().getLength(), line, 0, 0, null);
	} catch (Exception e) {
		e.printStackTrace();
	} 
}

The next step is creating line limit and remove the lines from the start which pass the limit. For this step I have used LimitLinesDocumentListener taken from http://tips4java.wordpress.com/2008/10/15/limit-lines-in-document/ (read on the blog about how it’s being used). Though I needed to do some changes in the removeLines function(which in my case will not use functions removeFromStart and removeFromEnd. And now it’s looks like:


private void removeLines(DocumentEvent e)
{
	Document document = e.getDocument();

	try {
		while (((HTMLDocument) document).getText(0, document.getLength()).split("\\n").length > maximumLines)
		{
			int end = document.getText(0, document.getLength()).split("\\n")[0].length();
				
			document.remove(0, end+1);
		}
	} catch (BadLocationException e1) {
		e1.printStackTrace();
	}
}

The last step is adding the listener to the text_panel, this is done with following code:


LimitLinesDocumentListener limitLinesListener = new LimitLinesDocumentListener(Configuration.getInstance().CHAT_VISIBLE_LINES);
this.text_panel.getDocument().addDocumentListener(limitLinesListener);

And before finishing note, there was also added some scroll behaviour, which makes the scroll jump to the last inserted item, achieved with following code:


DefaultCaret caret = (DefaultCaret)text_panel.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

I hope this will help some1 and save some time implementing nice chat(console) with colours and appending/removing. If you will find some optimization issues in my code or some things which can be simplified I will be very thankful if you report them in this topic or via pm.

Thanks for attention :wink:

To append or remove strings from JTextPane, you use the StyledDocument by calling getStyledDocument() on the JTextPane object. StyledDocument has insertString() and remove()

Instead of using HTML, you create Styles by calling addStyle() in StyledDocument, which returns a Style object that you can customize using the StyleConstants class. Then whenever you need to insert a string, you give insertString() the string and the style you want to use.
Example:


StyledDocument styledDoc = textPane.getStyledDocument();
...
Style style = styledDoc.addStyle("MyStyleName",null);
StyleConstants.setForeground(style,Color.red);
...
styledDoc.insertString(styledDoc.getLength(),line,styledDoc.getStyle("MyStyleName"));

I have tried to work with StyledDocument… I could get it showing correctly different colour line(different colors in the same line). That was the main reason why I started to work with HTML. Another thing, does Styled document will allow to be extended to show emotes and for example links to items?

Yes, images and JComponent’s are supported, though you use the methods insertIcon() and insertComponent() in JTextPane.

I have looked everywhere how to add links and have still found nothing. The only way I can think of doing links is to add a JLabel to the text pane and have a mouseListener set on it that would process the click.

For the complete set of API, refer here:
http://ra4king.is-a-geek.net/javadocs/javax/swing/JTextPane.html
http://ra4king.is-a-geek.net/javadocs/javax/swing/text/StyledDocument.html

If you want example code from my chat box, ask and I will post a link to the zip file.

Hope that helps!

EDIT: I have just realized that HTMLDocument implements StyledDocument. This means you can just give it links using


<a href="www.example.com">www.example.com</a>

You could post some code of you chat, so every could have benefit from using it.

Sure! I have removed all the networkings and listeners to just show what I used to create the visual. I use 2 custom Styles: Names and Notifications. The Names is just to bold the name of the chatter. The Notifications is for system messages. This is an applet so that’s why you see the init() and add() methods.


private JButton connect;
private JScrollPane scrollPane;
private JTextPane chatArea;
private JTextField chatField;
private StyledDocument chat;
private Box names;

public void init() {
	createChatArea();
	createNamesArea();
	
	chat = chatArea.getStyledDocument();
	createStyles();
	
	setSize(500,500);
	
	users = new ArrayList<JLabel>();
	
	chatField.addActionListener(new ChatListener());
}

private void createChatArea() {
	JPanel panel = new JPanel(new BorderLayout());
	
	chatArea = new JTextPane();
	chatArea.setEditable(false);
	scrollPane = (JScrollPane)panel.add(new JScrollPane(chatArea,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
	chatField = new JTextField();
	panel.add(chatField,BorderLayout.SOUTH);
	
	add(panel);
}

private void createNamesArea() {
	Box box = Box.createVerticalBox();
	
	names = Box.createVerticalBox();
	
	JScrollPane pane = new JScrollPane(names);
	box.add(pane);
	
	pane.setPreferredSize(new Dimension(100,500));
	
	Box box2 = Box.createHorizontalBox();
	
	JButton button = (JButton)box2.add(new JButton("Send"));
	button.setMinimumSize(new Dimension(65,20));
	button.setPreferredSize(new Dimension(65,20));
	button.setMaximumSize(new Dimension(65,20));
	button.addActionListener(new ChatListener());
	
	connect = (JButton)box2.add(new JButton("Connect"));
	connect.setMinimumSize(new Dimension(85,20));
	connect.setPreferredSize(new Dimension(85,20));
	connect.setMaximumSize(new Dimension(85,20));
	connect.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent ae) {
			if(!connected) {
				chatArea.setText("");
			}
		}
	});
	
	box.add(box2);
	
	add(box,BorderLayout.EAST);
}

private void createStyles() {
	Style s = chat.addStyle("Names",null);
	StyleConstants.setBold(s,true);
	
	s = chat.addStyle("Notifications",null);
	StyleConstants.setForeground(s,Color.white);
	StyleConstants.setBackground(s,Color.red);
}

When I receive a new messages from a chatter, this is the code to output:


chat.insertString(chat.getLength(),name + ": ",chat.getStyle("Names"));
chat.insertString(chat.getLength(),message + "\n",null);

And for a system notification:


chat.insertString(chat.getLength(),notif + "\n",chat.getStyle("Notifications"));

You could also take a look at the TWL Chat Demo and it’s source code.