JScrollPane and JList auto scroll
I've got the next code:
listModel = new DefaultListModel();
listModel.addElement(dateFormat.format(new Date()) + ": Msg1");
messageList = new JList(listModel);
messageList.setLayoutOrientation(JList.VERTICAL);
messageScrollList = new JScrollPane(messageList);
messageScrollList.setPreferredSize(new Dimension(500, 200));
messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueCh开发者_如何学编程anged(AdjustmentEvent e) {
e.getAdjustable().setValue(e.getAdjustable().getMaximum());
}
});
It auto scrolls down. But, if I try to scroll back up to re-read a message, it forces a scroll down. How can I fix this?
When adding a new message, invoke scrollRectToVisible()
on the JList
using a Rectangle
having the same dimensions as your message pane's preferred size. Given a vertical orientation, it may be convenient to make the preferred size of the JScrollPane
's JViewport
an integral multiple of the message pane's height. See also: How to Use Scroll Panes.
Addendum: This compelling discussion of Text Area Scrolling may be helpful, too.
this.list = blah blah...
this.list.setSelectedValue(whatever);
final JScrollPane sp = new JScrollPane(this.list); // needs to be after the parent is the sp
this.list.ensureIndexIsVisible(this.list.getSelectedIndex());
I found this really useful:
http://forums.sun.com/thread.jspa?threadID=623669 (post by 'inopia')
It works perfectly
As he says: "The problem here is that it can become a bit difficult to find an event that fires after both the ListModel, JList and JScrollPane have been updated."
@question enquirer. Please change your code from
messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
e.getAdjustable().setValue(e.getAdjustable().getMaximum());
}
});
to
messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
e.getAdjustable().setValue(e.getAdjustable().getValue());
}
});
That is change getMaximum()
to getValue()
Then it works as required. getMaximum()
takes the scroller to its maximum; while getValue()
takes it wherever event happens.
You can avoid using this piece of code altogether if you put one line
messageScrollList.setViewportView(messageList);
That works like add(component)
for jList and gets its inherent behaviour.
I used JScrollPane
with JTextArea
. I avoided force scroll down by scrolling only when JScrollBar max
value changed:
JScrollPane scrollPane = new JScrollPane(jTextArea);
verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum();
scrollPane.getVerticalScrollBar().addAdjustmentListener(
e -> {
if ((verticalScrollBarMaximumValue - e.getAdjustable().getMaximum()) == 0)
return;
e.getAdjustable().setValue(e.getAdjustable().getMaximum());
verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum();
}
);
I suppose, there is better solution to filter events without extra variables, and would appreciate if somebody post it.
I think what you want to do is have it scroll down when you add stuff to your messageList, rather then on adjustment. So your code could look like this:
Adjustable sb = messageScrollList.getVerticalScrollBar()
boolean onBottom = sb.getValue() == sb.getMaximum();
//
// add your message to the JList.
//
if(onBottom) sb.setValue(sb.getMaximum());
Otherwise you would need to tell if the adjustment was caused by a model change, or by the mouse, and looking through the API docs I'm not sure if there's a way to do that easily. Although you could see if the AdjustmentEvent.getAdjustmentType()
returns different values in those cases, if that's true then you could just have an if statement in your anonymous inner class.
Another thing you could try would be to have a boolean variable somewhere that gets set when you add something to the list. Then, in your handler you check to see if the variable is set. If so, you do the adjustment (and unset the variable) otherwise, you ignore it. That way, there will be only one scroll-down per item being added to the list.
To auto scroll I am using a very simple concept of static variable and list.makeVisible(int index)
public class autoScrollExample
{
static int index=0;
private void someFunction()
/*
*
*/
list1.add("element1");
list1.makeVisible(index++);
/*
*
*/
private void someOtherFunction()
/*
*
*/
list1.add("element2");
list1.makeVisible(index++);
/*
*
*/
}
精彩评论