JScrollPane and JList auto scroll

a 夏天 提交于 2019-11-27 17:41:19

问题


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 adjustmentValueChanged(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?


回答1:


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.




回答2:


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."




回答3:


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());



回答4:


@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.




回答5:


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++);
     /*
     *
     */


    }



回答6:


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.




回答7:


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.



来源:https://stackoverflow.com/questions/2132444/jscrollpane-and-jlist-auto-scroll

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