Java JScrollPane 和 JList 自动滚动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2132444/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JScrollPane and JList auto scroll
提问by dododedodonl
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?
它会自动向下滚动。但是,如果我尝试向上滚动以重新阅读消息,则会强制向下滚动。我怎样才能解决这个问题?
采纳答案by trashgod
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.
当添加新的消息时,调用scrollRectToVisible()
所述上JList
使用Rectangle
具有相同尺寸作为邮件窗格的最佳尺寸。给定垂直取向,它可方便地使的优选尺寸JScrollPane
的JViewport
邮件面板的高度的整数倍。另请参阅:如何使用滚动窗格。
Addendum: This compelling discussion of Text Area Scrollingmay be helpful, too.
附录:这个关于文本区域滚动的引人入胜的讨论也可能会有所帮助。
回答by Chad Okere
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:
我认为您想要做的是在向 messageList 添加内容时向下滚动,而不是进行调整。所以你的代码可能是这样的:
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.
否则,您需要判断调整是由模型更改还是由鼠标引起的,并查看 API 文档我不确定是否有办法轻松做到这一点。尽管您可以查看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.
您可以尝试的另一件事是在某处设置一个布尔变量,当您向列表中添加内容时,该变量会被设置。然后,在您的处理程序中,您检查是否设置了变量。如果是这样,您进行调整(并取消设置变量),否则,您将忽略它。这样,每个添加到列表中的项目只会向下滚动一次。
回答by Gene De Lisa
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());
回答by mohsenof
I found this really useful:
http://forums.sun.com/thread.jspa?threadID=623669(post by 'inopia')
It works perfectly
我发现这真的很有用:http:
//forums.sun.com/thread.jspa?threadID=623669('inopia' 发布)
它工作得很好
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 都更新后,找到触发的事件会变得有点困难。”
回答by Jay Dharmendra Solanki
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++);
/*
*
*/
}
回答by Any Body
@question enquirer. Please change your code from
@question 询问者。请更改您的代码
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.
即更改 getMaximum()
为getValue()
然后它按需要工作。getMaximum()
将滚动条调到最大;getValue()
无论事件发生在哪里,while都会带它。
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.
这类似于add(component)
jList 并获得其固有行为。
回答by user9999
I used JScrollPane
with JTextArea
. I avoided force scroll down by scrolling only when JScrollBar max
value changed:
我用JScrollPane
用JTextArea
。我通过仅在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.
我想,有更好的解决方案来过滤没有额外变量的事件,如果有人发布它会很感激。