Search code examples
javaswingjscrollpanejtextareaexecutorservice

Keep JScrollPane as same length java


I have a several JScrollPanes that contains a single JTextArea each. The JTextAreas are populated with a list of variables that are constantly updated.

I have a ScheduledExecutorService that constantly clears the JTextAreas and replaces the variables. For most the the JScrollPanes, the change are very seamless, and it looks like the numbers contained in the lists are changing in a smooth manner.

There is one JScrollPane that is giving an issue. It will constantly give off a flash (the text area and scroll bar go blank and reappear) which I correlate to it being repainted (I should note that even though the other panes get updated in the exact same manner, they do not encounter this problem). The scroll bar also will scroll wildly (back to the top); all in all looking very messy. This particular JScrollPane is also the longest so I assume that is the reason. There isn't anything else different about this particular pane from the others.

Unless someone has a better solution, I believe my best bet is to set the Caret to NEVER_UPDATE, but in order for this to work, the JScrollPane would have to remain the same size, even when I null out all of the text.

Does anyone know how to do this? To clarify, I don't want to make the pane larger, I want to essentially be able to scroll down to a set length, even if the pane is empty.


Solution

  • I'm not sure if this is what you're looking for, but in the past I've created a JTextPane that was constantly updated with exception messages, each colour coded. It had a scroll pane, and a text size buffer so when reached, it will remove from the start the amount of text appended to the end.

    Every time I caught an exception, I ran this:

    printExceptionMessage(new TCException(ex));
    

    Which in turn:

    protected void printExceptionMessage(final TCException exception) {
    
        SwingUtilities.invokeLater(
            new Runnable() {
                public void run() {
    
                    Date recordDate = exception.getTimeStamp();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss z");
                    String recordTime = sdf.format(recordDate);
    
                    String message = "(" + recordTime + ") EXCEPTION:   " + exception.getMessage() + "\n";
    
                    statusColorTextPane.setEditable(true);
    
                    // trim the textPane to the buffer size
                    Document doc = statusColorTextPane.getStyledDocument();
                    int overLength = doc.getLength() + message.length() - Foo.TEXT_BUFFER_SIZE;
    
                    if (overLength > 0) {
                        try {
                            doc.remove(0, overLength);
                        } catch (Exception ex) {
    
                            System.err.println("Error occured while trimming the textPane.");
                            ex.printStackTrace();
                        }
                    }
                    statusColorTextPane.append(Color.red, message);
                    statusColorTextPane.setEditable(false);
                }
            });     
    }
    

    In this case, statusColorTextPane is an extended class of JTextPane. It needs these two methods in it:

    public void appendNaive(Color c, String s) { // naive implementation
    
        SimpleAttributeSet aset = new SimpleAttributeSet();
        StyleConstants.setForeground(aset, c);
    
        int len = getText().length();
        setCaretPosition(len); // place caret at the end (with no selection)
        setCharacterAttributes(aset, false);
        replaceSelection(s); // there is no selection, so inserts at caret
    }
    

    and

    public void append(Color c, String s) { // better implementation--uses StyleContext
    
        StyleContext sc = StyleContext.getDefaultStyleContext();
        AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY,
                                        StyleConstants.Foreground, c);
    
        int len = getDocument().getLength(); // same value as getText().length();
        setCaretPosition(len);  // place caret at the end (with no selection)
        setCharacterAttributes(aset, false);
        replaceSelection(s); // there is no selection, so inserts at caret
    }
    

    Foo.TEXT_BUFFER_SIZE for me I have set to 20000.