简体   繁体   English

JScrollPane 和 JList 自动滚动

[英]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 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?我怎样才能解决这个问题?

When adding a new message, invoke scrollRectToVisible() on the JList using a Rectangle having the same dimensions as your message pane's preferred size.添加新消息时,使用与消息窗格的首选大小具有相同尺寸的RectangleJList上调用scrollRectToVisible() 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.给定垂直方向,将JScrollPaneJViewport的首选大小设为消息窗格高度的整数倍可能会很方便。 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());

@question enquirer. @question 询问者。 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()更改为getValue()然后它按要求工作。 getMaximum() takes the scroller to its maximum; getMaximum()使滚动条达到最大值; while getValue() takes it wherever event happens.getValue()在事件发生的任何地方都会使用它。

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.这类似于 jList 的add(component)并获得其固有行为。

I found this really useful: http://forums.sun.com/thread.jspa?threadID=623669 (post by 'inopia')我发现这真的很有用: http ://forums.sun.com/thread.jspa?threadID=623669('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."正如他所说:“这里的问题是,在 ListModel、JList 和 JScrollPane 都更新后,找到触发的事件会变得有点困难。”

I used JScrollPane with JTextArea .我将JScrollPaneJTextArea I avoided force scroll down by scrolling only when JScrollBar max value changed:我仅在JScrollBar max更改时才通过滚动来避免强制向下滚动:

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.我认为您想要做的是在将内容添加到 messageList 时向下滚动,而不是进行调整。 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.否则,您需要判断调整是由模型更改还是由鼠标引起的,并查看 API 文档我不确定是否有办法轻松做到这一点。 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.虽然您可以看到在这些情况下AdjustmentEvent.getAdjustmentType()返回不同的值,但如果这是真的,那么您可以在匿名内部类中使用 if 语句。

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)要自动滚动,我使用了一个非常简单的静态变量概念和 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++);
     /*
     *
     */


    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM