I am trying to implement a JScrollPane, containing a JTextArea, whose vertical scroll bar automatically remains as the bottom when new text is added, if it is already at the bottom, and stays in place otherwise.
I have found a solution that seems to work, except when I move the scroll bar to the bottom, it gets stuck there and can only be moved by dragging the scroll bar, pressing the scroll bar's up arrow and the mouse wheel do not work when the scroll bar is at the bottom. Both methods, up arrow on scroll bar and mouse wheel, do work to more the scroll bar if it is not at the bottom.
Since this is a small part of a larger application, I am only including relevant code snippets. Please assume all variables have been properly initialized and let me know if you need more code
//Child class of JScrollPane
public class AutoScrollPane extends JScrollPane
{
private boolean shouldScroll = false;
public AutoScrollPane(JTextArea t)
{
super(t);
}
public void setShouldScroll (boolean b)
{
shouldScroll = b;
}
public boolean getShouldScroll ()
{
return shouldScroll;
}
} //end class
//in main
JTextArea text = new JTextArea(10, 10);
AutoScrollPane scroller = new AutoScrollPane(text);
scroller.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener()
{ public void adjustmentValueChanged(AdjustmentEvent e) {onChangeScrollBarMethod(); }});
private void onChangeScrollBarMethod()
{
if (!scroller.getVerticalScrollBar().getValueIsAdjusting() && scroller.getVerticalScrollBar().getValue() + scroller.getVerticalScrollBar().getVisibleAmount() == scroller.getVerticalScrollBar().getMaximum())
scroller.setShouldScroll(true);
else
scroller.setShouldScroll(false);
}
private Thread guiThread = null;
//in main
execute(new Runnable() { public void run() { startGuiThread(); }});
private void startGuiThread()
{
if (guiThread == null)
{
guiThread = new Thread(new Runnable() { public void run() { updateGui(); }});
guiThread.setDaemon(true);
guiThread.start();
}
}
private void updateGui()
{
while(true)
{
if (scroller.getShouldScroll())
{
try { EventQueue.invokeAndWait(new Runnable() { public void run() { scroller.getVerticalScrollBar().setValue(scroller.getVerticalScrollBar().getMaximum());}}; }
catch (Exception e) { e.printStackTrace(); }
}
//append text
}