Java Swing Programming: Implementing a Buffered Scrollable Window

Sunday, August 17, 2008

In one of my applications related to Java Swing, I was implementing a buffered scrollable window which will output live logs from the application. But as the size of the logs grows to some extent, I just don't want to retain the obsolete or topmost old entries. In other words I want to implement a buffered scrollable window which will output lines till the buffer size is reached (the buffer size is specified as the maximum number of lines which can be displayed in the buffer), then the topmost entry in the window will be replaced by the second line, the second line by the third and so on to accommodate the new line at the bottom of the window.

This is something similar to a DOS or a UNIX terminal window in which after some lines were output, the oldest entries (those at the top of the command window) will be replaced by the new lines one by one.

The below code is an implementation of a buffered scrollable window using JFrame Swing component.

  1 /*
2 *
3 * Author: S.Prasanna
4 * @version 1.00 08/12/2008
5 */

7 import javax.swing.JPanel;
8 import javax.swing.JTextArea;
9 import javax.swing.BorderFactory;
10 import javax.swing.JScrollPane;
11 import javax.swing.JFrame;
12 import javax.swing.BorderFactory;
13 import javax.swing.JDialog;
14 import java.awt.BorderLayout;
15 import java.awt.Dimension;
17 public class BufferedScrollableWindow {
19 final JTextArea statusmessageArea = new JTextArea();
20 final JScrollPane scroll = new JScrollPane(statusmessageArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
21 JFrame frame = new JFrame("This is a Buffered Scrollable Window");
22 int BUFFERSIZE = 10;
23 //BUFFERSIZE specifies maximum the no of lines in the window which can be printed
24 //before the topmost entry is replaced by the second line and all lines shifted
25 //one line above making way for the latest line to be printed out at the bottom of the
26 //window or buffer
28 BufferedScrollableWindow () {
29 statusmessageArea.setBorder(BorderFactory.createEtchedBorder());
30 statusmessageArea.setBorder(BorderFactory.createEtchedBorder());
31 statusmessageArea.setWrapStyleWord(true);
33 scroll.getViewport().setPreferredSize(new Dimension(400, 400));
35 frame.getContentPane().setLayout(new BorderLayout());
36 frame.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
37 frame.getContentPane().add(scroll, BorderLayout.CENTER);
38 frame.pack();
39 frame.setLocationRelativeTo(null);
40 frame.setVisible(true);
41 }
43 public void writeIndexStatusLine(String status) {
45 //When the line count in the text window > size of the buffer, replace the first line in buffer
46 //to give way to the last line, all lines in buffer shift one line up
47 if (statusmessageArea.getLineCount() > BUFFERSIZE) {
48 try {
49 statusmessageArea.replaceRange(null, statusmessageArea.getLineStartOffset(0),
50 } catch (Exception e) {
51 statusmessageArea.append("An exception occured in replacing the topmost entry in the buffer");
52 e.printStackTrace();
53 return;
54 }
55 }
57 statusmessageArea.append(status + "\n");
59 //Update the text window with the latest line to be printed
60 try {
61 statusmessageArea.setCaretPosition(statusmessageArea.getLineEndOffset(
statusmessageArea.getLineCount() - 1));
62 statusmessageArea.repaint();
63 } catch (Exception e1) {
64 statusmessageArea.append("An exception occured writing lines to buffer");
65 e1.printStackTrace();
66 }
67 }
69 public static void main(String[] args) throws Exception {
71 BufferedScrollableWindow BW = new BufferedScrollableWindow();
73 for (int i = 1; i<=50; i++) {
74 BW.writeIndexStatusLine("This is line " + i);
75 Thread.sleep(1000);
76 }
78 }
79 }
The working of the code is pretty cimple, a JScrollPane inside a JFrame displays a JTextArea component with horizontal and vertical scrollbars.

The two lines which does the trick were as follows.

Line 61: statusmessageArea.setCaretPosition(statusmessageArea.getLineEndOffset(statusmessageArea.getLineCount() - 1));

The setCaretPosition() method of JTextArea sets the position where the text will be appended, in our case this is set to the last line of the buffer so that a new line will be added to the bottom of the buffer.

Line 49: statusmessageArea.replaceRange(null, statusmessageArea.getLineStartOffset(0), statusmessageArea.getLineEndOffset(0));

The replaceRange() function of JTextArea replaces text from the indicated start to end position with the new text specified, if the specified text is null, the text between the start and end position is deleted, in our case when the number of lines exceeds the buffer size (i.e the maximum number of lines in the buffer), then the first line is deleted, the start and end position of the first line is fetched using statusmessageArea.getLineStartOffset(0) and statusmessageArea.getLineEndOffset(0) methods respectively.

In the below outputs, 50 lines are printed and we will look at cases where the buffer size is 10 and 40 lines respectively.

Output 1 and 2:

In the case the BUFFERSIZE = 10, the first ten lines are printed (Output 1) , when the 11th line is printed, line 1 in the top is replaced by line 2 and so on which is shown in the Output 2.

Output 3 and 4:
In the case the BUFFERSIZE = 40, the scrollbar comes into picture since the number of lines is greater than the dimension of the window, once 50 lines are printed (bottom scroll, Output 3), the top 10 lines were replaced in the buffer (top scroll, Output 4).


Jeremy said...

Good post Prasanna, very useful. I have been trying to scroll the Jscrollpane programmatically, and it would not move. Setting the carat position did the trick. Thanks for this

Prasanna Seshadri said...

Thanks, welcome.

Anonymous said...

It worked very nicely..Thank you

Anonymous said...

How would you implement this if the status (lines from the log) is multi-line rather than single line. replaceRange() replaces one line at a time.

Copyright © 2016 Prasanna Seshadri,, All Rights Reserved.
No part of the content or this site may be reproduced without prior written permission of the author.