JScrollPane和JList自动滚动

我有下一个代码:

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

它会自动向下滚动。 但是,如果我尝试向上滚动以重新阅读邮件,则会强制向下滚动。 我怎样才能解决这个问题?

添加新消息时,使用与消息窗格的首选大小具有相同维度的RectangleJList上调用scrollRectToVisible() 。 给定垂直方向,可以方便地使JScrollPaneJViewport的首选大小成为消息窗格高度的整数倍。 另请参阅: 如何使用滚动窗格

附录:这个引人注目的文本区域滚动讨论也可能有所帮助。

我发现这非常有用: http ://forums.sun.com/thread.jspa?threadID = 623669(由’inopia’发布)
它完美地运作

正如他所说的那样:“问题在于,在ListModel,JList和JScrollPane都得到更新之后,找到一个触发的事件会变得有点困难。”

 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询问者。 请更改您的代码

 messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { e.getAdjustable().setValue(e.getAdjustable().getMaximum()); } }); 

 messageScrollList.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { e.getAdjustable().setValue(e.getAdjustable().getValue()); } }); 

这是将getMaximum()更改为getValue()然后它根据需要工作。 getMaximum()使滚动条达到最大值; 而getValue()在事件发生的任何地方都可以使用它。

如果你放一行,你可以完全避免使用这段代码

 messageScrollList.setViewportView(messageList); 

这类似于为jList add(component)并获得其固有行为。

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

我使用JScrollPaneJTextArea 。 当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(); }); 

我想,有更好的解决方案来过滤没有额外变量的事件,并且如果有人发布它会很感激。

我想你想要做的就是当你向messageList添加东西时向下滚动,而不是调整。 所以你的代码看起来像这样:

 Adjustable sb = messageScrollList.getVerticalScrollBar() boolean onBottom = sb.getValue() == sb.getMaximum(); // // add your message to the JList. // if(onBottom) sb.setValue(sb.getMaximum()); 

否则你需要判断调整是由模型更改还是鼠标引起的,并查看API文档我不确定是否有办法轻松完成。 虽然您可以看到AdjustmentEvent.getAdjustmentType()在这些情况下是否返回不同的值,但如果这是真的,那么您可以在匿名内部类中使用if语句。

你可以尝试的另一件事是在你向列表添加内容时设置一个布尔变量。 然后,在您的处理程序中,检查是否设置了变量。 如果是,则进行调整(并取消设置变量),否则忽略它。 这样,每个项目只会向列表中添加一个向下滚动。