2010-08-02 25 views
6

Je tente d'impliquer smart autoscrolling sur un JScrollPane contenant un JTextPane. Le JTextPane est utilisé pour la connexion de mon application en couleur. Cependant, je cours dans un mur en essayant de faire un auto-défilement intelligent. Par autoscrolling intelligent, je ne veux pas dire aveuglément autoscrolling chaque fois que quelque chose change, je veux dire vérifier pour voir si vous avez fait défiler tout le chemin, puis autoscroll. Cependant, peu importe ce que je fais soit autoscrolls toujours ou ne pas du toutSmart JScrollPane autoscrolling

En tant que script de test, voici la configuration (la JFrame a été laissé)

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

Et voici l'auto laid ajouter essai boucle

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

Ce n'est pas joli, mais cela fait l'affaire.

est ici que le chèque correspondant

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

thats la partie des thats été de me donner du mal. Il y a d'abord un contrôle pour voir si la barre est visible mais inutilisable (pas assez de texte, faisant de la barre toute la longueur), puis si le bas de la barre est égal au maximum. En théorie, cela devrait fonctionner. Cependant, rien, y compris le déplacement du chèque, n'a obtenu les résultats que je voudrais.

Des suggestions?

PAS UN DUPLICATA de this ou this, comme ils le veulent toujours faire défiler, pas seulement parfois.

+0

Avez-vous trouvé l'erreur? J'ai exactement la même tâche, et, vraiment, je n'arrive toujours pas à trouver la solution. –

Répondre

7

Edit:

j'ai remplacé le code suivant avec une version plus souple qui fonctionnera sur un composant dans un JScrollPane. Départ: 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

Lien est cassé, pouvez-vous fournir un autre? –

+0

Bon exemple. J'ai essayé d'inventer la solution pour la même chose mais je n'ai pas réussi à le faire :( – Dragon

+0

Une excellente solution - merci beaucoup pour le partage. –