Swing: faites Défiler vers le bas de JScrollPane, qui dépend de l'emplacement de la fenêtre actuelle

Je suis essayer de reproduire la fonctionnalité de Adium et la plupart des autres clients de chat que j'ai vu, dans lequel les barres de défilement avance vers le bas lorsque de nouveaux messages arrivent dans, mais seulement si vous êtes déjà là. En d'autres termes, si vous avez fait défiler quelques lignes, et sont en lecture, quand un nouveau message arrive, de ne pas sauter votre position au bas de l'écran; ce serait ennuyeux. Mais si vous faites défiler vers le bas, le programme, à juste titre, suppose que vous voulez voir les plus récents messages à tout moment, et donc, l'auto-rouleaux en conséquence.

J'ai eu un ours d'un temps à essayer d'imiter ce; la plate-forme semble lutter contre ce comportement à tous les coûts. Le mieux que je puisse faire est la suivante:

Dans le constructeur:

JTextArea chatArea = new JTextArea();
JScrollPane chatAreaScrollPane = new JScrollPane(chatArea);

//We will manually handle advancing chat window
DefaultCaret caret = (DefaultCaret) chatArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);

Dans la méthode qui gère nouveau texte à venir dans:

boolean atBottom = isViewAtBottom();

//Append the text using styles etc to the chatArea

if (atBottom) {
    scrollViewportToBottom();
} 


public boolean isAtBottom() {
    //Is the last line of text the last line of text visible?
    Adjustable sb = chatAreaScrollPane.getVerticalScrollBar();

    int val = sb.getValue();
    int lowest = val + sb.getVisibleAmount();
    int maxVal = sb.getMaximum();

    boolean atBottom = maxVal == lowest;
    return atBottom;
}


private void scrollToBottom() {
    chatArea.setCaretPosition(chatArea.getDocument().getLength());
}

Maintenant, cela fonctionne, mais c'est janky et n'est pas idéal pour deux raisons.

  1. Par réglage de la position du curseur, quelle que soit la sélection, l'utilisateur peut avoir dans la zone de chat est effacé. Je peux imaginer que ce serait très irritant s'il est tentant de copier/coller.
  2. Depuis la promotion de la faire défiler le volet se produit après que le texte est inséré, il y a une fraction de seconde où la barre de défilement est dans la mauvaise position, et puis visuellement sauts vers la fin. Ce n'est pas l'idéal.

Avant de vous demander, oui j'ai lu cet article de blog sur Zone De Texte Défilant, mais le défaut de défilement vers le bas de comportement n'est pas ce que je veux.

Autres (mais à mon avis, pas tout à fait utile à cet égard) questions:
Réglage de la barre de défilement sur un jscrollpane
Faire un JScrollPane automatiquement défiler tout le chemin vers le bas.

Toute aide à ce sujet serait très apprécié.

Edit:

Comme par Devon_C_Miller les conseils, j'ai une meilleure façon de défilement vers le bas, la résolution de problème #1.

private void scrollToBottom() {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
       public void run() {
           try {
               int endPosition = chatArea.getDocument().getLength();
               Rectangle bottom = chatArea.modelToView(endPosition);
               chatArea.scrollRectToVisible(bottom);
           }
           catch (BadLocationException e) {
               System.err.println("Could not scroll to " + e);
           }
       }
    });
}

J'ai encore le problème n ° 2.

InformationsquelleAutor I82Much | 2010-04-19