2010-08-02 92 views
6

我试图在包含JTextPane的JScrollPane上自动滚动智能。 JTextPane用于以彩色记录我的应用程序。不过,我正在试图进行智能自动滚动。通过智能自动滚动,我并不是说每次有变化时都会盲目地自动滚动,我的意思是检查滚动是否一直下降,然后然后自动滚动。但是不管我做什么,要么总是autoscrolls或没有在所有智能JScrollPane自动滚动

作为测试脚本,这里的设置(JFrame中被忽略了)

final JTextPane textPane = new JTextPane(); 
textPane.setEditable(false); 
final JScrollPane contentPane = new JScrollPane(textPane); 
contentPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 

和这里的丑自动添加测试循环

while (true) 
    try { 
     Thread.sleep(1000); 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        JScrollBar scrollBar = scroll; 
        boolean preCheck = ((scrollBar.getVisibleAmount() != scrollBar.getMaximum()) && (scrollBar.getValue() + scrollBar.getVisibleAmount() == scrollBar.getMaximum())); 
        System.out.println("Value: " + scroll.getValue() 
            + " | Visible: " + scrollBar.getVisibleAmount() 
            + " | Maximum: " + scrollBar.getMaximum() 
            + " | Combined: " + (scrollBar.getValue() + scrollBar.getVisibleAmount()) 
            + " | Vis!=Max : " + (scrollBar.getVisibleAmount() != scrollBar.getMaximum()) 
            + " | Comb=Max: " + (scrollBar.getValue() + scrollBar.getVisibleAmount() == scrollBar.getMaximum()) 
            + " | Eval: " + preCheck); 
        StyledDocument doc = textPane.getStyledDocument(); 
        doc.insertString(doc.getLength(), "FAGAHSIDFNJASDKFJSD\n", doc.getStyle("")); 
        if (!preCheck) 
          textPane.setCaretPosition(doc.getLength()); 
       } catch (BadLocationException ex) { 
          ex.printStackTrace(); 
       } 
      } 
     }); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

它并不漂亮,但它完成了工作。

这里虽然该检查

boolean preCheck = ((scrollBar.getVisibleAmount() != scrollBar.getMaximum()) && (scrollBar.getValue() + scrollBar.getVisibleAmount() == scrollBar.getMaximum())); 
if (preCheck) 
    textPane.setCaretPosition(doc.getLength()); 

那部分这就是一直给我找麻烦。首先检查栏是否可见但不可用(没有足够的文本,使栏全长),然后如果栏的底部等于最大值。理论上,这应该起作用。然而没有任何东西,包括移动支票,得到了我想要的结果。

有什么建议吗?

不是重复的thisthis,因为他们希望它总是滚动,而不仅仅是有时。

+0

你解决了吗?我有完全相同的任务,实际上,仍然找不到解决方案。 – 2012-11-22 09:54:09

回答

7

编辑:

我换成下面的代码以更加灵活的版本,将在JScrollPane任何部件上工作。退房时间:Smart Scrolling

import java.awt.*; 
import java.awt.event.*; 
import java.util.Date; 
import javax.swing.*; 
import javax.swing.text.*; 

public class ScrollControl implements AdjustmentListener 
{ 
    private JScrollBar scrollBar; 
    private JTextComponent textComponent; 
    private int previousExtent = -1; 

    public ScrollControl(JScrollPane scrollPane) 
    { 
     Component view = scrollPane.getViewport().getView(); 

     if (! (view instanceof JTextComponent)) 
      throw new IllegalArgumentException("Scrollpane must contain a JTextComponent"); 

     textComponent = (JTextComponent)view; 

     scrollBar = scrollPane.getVerticalScrollBar(); 
     scrollBar.addAdjustmentListener(this); 
    } 

    @Override 
    public void adjustmentValueChanged(final AdjustmentEvent e) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       checkScrollBar(e); 
      } 
     }); 
    } 

    private void checkScrollBar(AdjustmentEvent e) 
    { 
     // The scroll bar model contains information needed to determine the 
     // caret update policy. 

     JScrollBar scrollBar = (JScrollBar)e.getSource(); 
     BoundedRangeModel model = scrollBar.getModel(); 
     int value = model.getValue(); 
     int extent = model.getExtent(); 
     int maximum = model.getMaximum(); 
     DefaultCaret caret = (DefaultCaret)textComponent.getCaret(); 

     // When the size of the viewport changes there is no need to change the 
     // caret update policy. 

     if (previousExtent != extent) 
     { 
      // When the height of a scrollpane is decreased the scrollbar is 
      // moved up from the bottom for some reason. Reposition the 
      // scrollbar at the bottom 

      if (extent < previousExtent 
      && caret.getUpdatePolicy() == DefaultCaret.UPDATE_WHEN_ON_EDT) 
      { 
       scrollBar.setValue(maximum); 
      } 

      previousExtent = extent; 
      return; 
     } 

     // Text components will not scroll to the bottom of a scroll pane when 
     // a bottom inset is used. Therefore the location of the scrollbar, 
     // the height of the viewport, and the bottom inset value must be 
     // considered when determining if the scrollbar is at the bottom. 

     int bottom = textComponent.getInsets().bottom; 

     if (value + extent + bottom < maximum) 
     { 
      if (caret.getUpdatePolicy() != DefaultCaret.NEVER_UPDATE) 
       caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); 
     } 
     else 
     { 
      if (caret.getUpdatePolicy() != DefaultCaret.UPDATE_WHEN_ON_EDT) 
      { 
       caret.setDot(textComponent.getDocument().getLength()); 
       caret.setUpdatePolicy(DefaultCaret.UPDATE_WHEN_ON_EDT); 
      } 
     } 
    } 

    private static void createAndShowUI() 
    { 
     JPanel center = new JPanel(new GridLayout(1, 2)); 
     String text = "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n"; 

     final JTextArea textArea = new JTextArea(); 
     textArea.setText(text); 
     textArea.setEditable(false); 
     center.add(createScrollPane(textArea)); 
     System.out.println(textArea.getInsets()); 

     final JTextPane textPane = new JTextPane(); 
     textPane.setText(text); 
     textPane.setEditable(false); 
     center.add(createScrollPane(textPane) ); 
     textPane.setMargin(new Insets(5, 3, 7, 3)); 
     System.out.println(textPane.getInsets()); 

     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(center, BorderLayout.CENTER); 
     frame.setSize(500, 200); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 

     Timer timer = new Timer(2000, new ActionListener() 
     { 
      public void actionPerformed(ActionEvent e) 
      { 
       try 
       { 
        Date now = new Date(); 
        textArea.getDocument().insertString(textArea.getDocument().getLength(), "\n" + now.toString(), null); 
        textPane.getDocument().insertString(textPane.getDocument().getLength(), "\n" + now.toString(), null); 
       } 
       catch (BadLocationException e1) {} 
      } 
     }); 
     timer.start(); 
    } 

    private static JComponent createScrollPane(JComponent component) 
    { 
     JScrollPane scrollPane = new JScrollPane(component); 
     new ScrollControl(scrollPane); 

     return scrollPane; 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

链接被破坏,你能提供另一个? – 2013-02-26 15:05:27

+0

很好的例子。我试图发明同样的解决方案,但没有设法做到:( – Dragon 2013-02-27 22:01:56

+0

一个很好的解决方案 - 非常感谢分享。 – 2013-03-06 11:58:17