2010-08-02 15 views
6

Estoy tratando de implícitamente smart autoscroll en un JScrollPane que contiene un JTextPane. El JTextPane se usa para registrar mi aplicación en color. Sin embargo, estoy corriendo hacia una pared tratando de hacer autoscrols inteligentes. Por desplazamiento automático inteligente no me refiero ciegamente al desplazamiento automático cada vez que algo cambia, me refiero a verificar si se desplazó hacia abajo, y luego autodesplazamiento. Sin embargo, no importa lo que haga que sea siempre autoscrolls o no lo hace en absolutoSmart JScrollPane autoscrolling

Como un script de prueba, aquí está la configuración (JFrame se ha quedado fuera)

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

y aquí está la fea Autoañadir prueba lazo

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

No es bonito, pero hace el trabajo bien.

Aquí es cuando el cheque correspondiente

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

esa es la parte eso me ha estado dando problemas. Primero hay que verificar si la barra está visible pero no se puede usar (no hay suficiente texto, haciendo que la barra tenga la longitud completa), y luego si la parte inferior de la barra es igual al máximo. En teoría, eso debería funcionar. Sin embargo, nada, incluido mover el cheque, ha obtenido los resultados que me gustaría.

¿Alguna sugerencia?

NO es un DUPLICADO de this o this, ya que quieren que siempre se desplace, no solo algunas veces.

+0

¿resolviste esto? Tengo exactamente la misma tarea y, realmente, todavía no puedo encontrar la solución. –

Respuesta

7

Editar:

que sustituyen el siguiente código con una versión más flexible que funcionará en cualquiera de los componentes en un JScrollPane. Hora de salida: 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

El enlace está roto, ¿puede proporcionar otro? –

+0

Gran ejemplo. Traté de inventar la solución para la misma cosa, pero no logré hacerlo :( – Dragon

+0

Una excelente solución, muchas gracias por compartir. –