JTextArea scroll to bottom only if text is appended

*爱你&永不变心* 提交于 2019-12-20 07:11:17

问题


I am trying to create a JTextArea which scrolls to bottom every time a text is appended to that text area. Otherwise, the user should be able to scroll top and see previous message. I used this code:

JTextArea terminalText  = new JTextArea();
JPanel terminal = new JPanel();
terminal.setLayout(new BorderLayout()); 
add(terminal);  //Adds the terminal to mother JPanel

//I added scrollbar to my JTextArea
JScrollPane scroll = new JScrollPane(terminalText);  
terminal.add(scroll, BorderLayout.CENTER);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

scroll.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {  
public void adjustmentValueChanged(AdjustmentEvent e) {  
 e.getAdjustable().setValue(e.getAdjustable().getMaximum());  
}});

So far this code seems to make my text area scroll to bottom of the terminalText text area every time I append something to terminalText using terminalText.append.

However, the user cannot use scroll bar to scroll to the top to see previous message. Is there a way to fix this? Should I be using DocumentListener to achieve this?


回答1:


Check out Smart Scrolling.

If the scrollbar is at the bottom, then as text is appended you will see the new text.

If the user has scrolled to a different position, then the viewport will stay there until the user scrolls back to the bottom.




回答2:


As a simple (and rough) proof of concept...

This basically adds a DocumentListener to the JTextArea and on any Document event, use setCaretPosition to move the caret to the end of the document.

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.WeakHashMap;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.JTextComponent;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JTextArea ta = new JTextArea(10, 20);
                ta.setWrapStyleWord(true);
                ta.setLineWrap(true);
                MoveToTheBottom.install(ta);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(ta));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                Timer timer = new Timer(500, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        ta.append(new Date().toString() + "\n");
                    }
                });
                timer.start();
            }
        });
    }

    public static class MoveToTheBottom implements DocumentListener {

        private static WeakHashMap<JTextComponent, DocumentListener> registry = new WeakHashMap<>(25);
        private JTextComponent parent;

        protected MoveToTheBottom(JTextComponent parent) {
            this.parent = parent;
            parent.getDocument().addDocumentListener(this);
        }

        public static void install(JTextComponent parent) { 
            MoveToTheBottom bottom = new MoveToTheBottom(parent);
            registry.put(parent, bottom);
        }

        public static void uninstall(JTextComponent parent) {
            DocumentListener listener = registry.remove(parent);
            if (listener != null) {
                parent.getDocument().removeDocumentListener(listener);
            }
        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            parent.setCaretPosition(e.getDocument().getLength());
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            parent.setCaretPosition(e.getDocument().getLength());
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            parent.setCaretPosition(e.getDocument().getLength());
        }

    }

}

The example demonstrates a possible re-usable API which you can use to "install" and "uninstall" the support as reqiured



来源:https://stackoverflow.com/questions/29224709/jtextarea-scroll-to-bottom-only-if-text-is-appended

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!