2010-10-28 2 views

Antwort

3

Text Area Scrolling von Interesse sein können

Ich habe keine Ahnung, wie die Scroll-Lock-Taste wirkt es mir folgendes aus der Wikipedia-Seite über Scroll Lock gefunden:

Daher Scroll Lock kann angesehen als nicht mehr existierenden Feature in fast allen modernen Programmen und Betriebssystemen.

so würde ich nicht darum kümmern.

13

ich denke, bin Ihr Programm erfüllt genau Ihre Anforderungen, mit einem möglichen Vorbehalt: Sie dürfen den Textbereich nicht eingeben. Das wäre also gut für einen Log Viewer, aber nicht für eine interaktive Konsole. Der Code läuft ein wenig lang, weil ich es zu einer Ready-to-Run-Demo des Ansatzes gemacht habe. Ich schlage vor, das Programm wie gehabt auszuführen und das Verhalten zu überprüfen. Wenn das Verhalten für Sie gut funktioniert, investieren Sie etwas Zeit in das Studium des Codes. Ich habe Kommentare in den Code eingefügt, um einige der wichtigeren Abschnitte hervorzuheben.


-Update 2013.07.17: Sie können auch weiter zufälligen Geck ‚s-Lösung in seiner separaten Antwort zu überprüfen, unten auf der Seite. Sein Ansatz ist eleganter als meiner.

Siehe auch Swing: Scroll to bottom of JScrollPane, conditional on current viewport location für eine mögliche Lösung, die die Caret-Position nicht beeinträchtigt.


SCCE Quellcode folgt:

import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import java.util.Timer; 

import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.text.*; 

public class ScrollingJTextAreaExample extends JFrame { 
    // Worker thread to help periodically append example messages to JTextArea 
    Timer timer = new Timer(); 
    // Merely informative counter, will be displayed with the example messages 
    int messageCounter = 0; 
    // GUI components 
    JScrollPane jScrollPane; 
    JTextArea jTextArea; 

    public ScrollingJTextAreaExample() { 
     initComponents(); // Boiler plate GUI construction and layout 

     // Configure JTextArea to not update the cursor position after 
     // inserting or appending text to the JTextArea. This disables the 
     // JTextArea's usual behavior of scrolling automatically whenever 
     // inserting or appending text into the JTextArea: we want scrolling 
     // to only occur at our discretion, not blindly. NOTE that this 
     // breaks normal typing into the JTextArea. This approach assumes 
     // that all updates to the ScrollingJTextArea are programmatic. 
     DefaultCaret caret = (DefaultCaret) jTextArea.getCaret(); 
     caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); 

     // Schedule a task to periodically append example messages to jTextArea 
     timer.schedule(new TextGeneratorTask(), 250, 250); 

     // This DocumentListener takes care of re-scrolling when appropriate 
     Document document = jTextArea.getDocument(); 
     document.addDocumentListener(new ScrollingDocumentListener()); 
    } 

    // Boring, vanilla GUI construction and layout code 
    private void initComponents() { 
     jScrollPane = new javax.swing.JScrollPane(); 
     jTextArea = new javax.swing.JTextArea(); 
     setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     jScrollPane.setViewportView(jTextArea); 
     getContentPane().add(jScrollPane, java.awt.BorderLayout.CENTER); 
     setSize(320, 240); 
     setLocationRelativeTo(null); 
    } 

    // ScrollingDocumentListener takes care of re-scrolling when appropriate 
    class ScrollingDocumentListener implements DocumentListener { 
     public void changedUpdate(DocumentEvent e) { 
      maybeScrollToBottom(); 
     } 

     public void insertUpdate(DocumentEvent e) { 
      maybeScrollToBottom(); 
     } 

     public void removeUpdate(DocumentEvent e) { 
      maybeScrollToBottom(); 
     } 

     private void maybeScrollToBottom() { 
      JScrollBar scrollBar = jScrollPane.getVerticalScrollBar(); 
      boolean scrollBarAtBottom = isScrollBarFullyExtended(scrollBar); 
      boolean scrollLock = Toolkit.getDefaultToolkit() 
        .getLockingKeyState(KeyEvent.VK_SCROLL_LOCK); 
      if (scrollBarAtBottom && !scrollLock) { 
       // Push the call to "scrollToBottom" back TWO PLACES on the 
       // AWT-EDT queue so that it runs *after* Swing has had an 
       // opportunity to "react" to the appending of new text: 
       // this ensures that we "scrollToBottom" only after a new 
       // bottom has been recalculated during the natural 
       // revalidation of the GUI that occurs after having 
       // appending new text to the JTextArea. 
       EventQueue.invokeLater(new Runnable() { 
        public void run() { 
         EventQueue.invokeLater(new Runnable() { 
          public void run() { 
           scrollToBottom(jTextArea); 
          } 
         }); 
        } 
       }); 
      } 
     } 
    } 

    class TextGeneratorTask extends TimerTask { 
     public void run() { 
      EventQueue.invokeLater(new Runnable() { 
       public void run() { 
        String message = (++messageCounter) 
          + " Lorem ipsum dolor sit amet, consectetur" 
          + " adipisicing elit, sed do eiusmod tempor" 
          + " incididunt ut labore et dolore magna aliqua.\n"; 
        jTextArea.append(message); 
       } 
      }); 
     } 
    } 

    public static boolean isScrollBarFullyExtended(JScrollBar vScrollBar) { 
     BoundedRangeModel model = vScrollBar.getModel(); 
     return (model.getExtent() + model.getValue()) == model.getMaximum(); 
    } 

    public static void scrollToBottom(JComponent component) { 
     Rectangle visibleRect = component.getVisibleRect(); 
     visibleRect.y = component.getHeight() - visibleRect.height; 
     component.scrollRectToVisible(visibleRect); 
    } 

    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new ScrollingJTextAreaExample().setVisible(true); 
      } 
     }); 
    } 
} 
+0

Yup, das sieht aus wie ich es mache. – I82Much

+0

Sehr sehr cool !! Vielen Dank! –

+0

Es funktioniert nicht, wenn Sie Nachrichten an fasten (mit timer.schedule (new TextGeneratorTask(), 250, 5); zum Beispiel), wissen Sie, warum? –

9

wenig spät auf diese Frage, aber ich kam mit dieser Lösung auf.

conversationPane = new JTextPane(); 
    final JScrollPane conversationScrollPane = new JScrollPane(conversationPane); 
    conversationScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { 

    BoundedRangeModel brm = conversationScrollPane.getVerticalScrollBar().getModel(); 
    boolean wasAtBottom = true; 

    public void adjustmentValueChanged(AdjustmentEvent e) { 
     if (!brm.getValueIsAdjusting()) { 
      if (wasAtBottom) 
       brm.setValue(brm.getMaximum()); 
     } else 
      wasAtBottom = ((brm.getValue() + brm.getExtent()) == brm.getMaximum()); 

    } 
    }); 

Scheint perfekt für meine Bedürfnisse zu funktionieren. Kleine Erklärung: Wenn die Bildlaufleiste nicht von einer Person bewegt wird und der Balken zuletzt am Maximum/unten war, setzen Sie ihn auf das Maximum zurück. Wenn es manuell angepasst wird, überprüfen Sie, ob es so eingestellt wurde, dass es unten liegt.

+0

Aus irgendeinem Grund hängt brm.setValue (brm.getMaximum()) meine Methode und mein zweiter Thread (nur unter Windows. linux mac solaris funktioniert super). tat dies mit setcaret postiion auf der textpanee, aber auf windows das gleiche ergebnis. Irgendeine Idee? – Meltea

+0

@Meltea - Alle Interaktionen mit Swing/AWT-Objekten müssen im AWT-Ereignisversand-Thread durchgeführt werden. Wenn Sie einen "zweiten Thread" haben, müssen Sie mit der Benutzeroberfläche interagieren, indem Sie Runnables über SwingUtilities.invokeLater in die Warteschlange stellen. Wenn Sie eine Methode für ein Swing- oder AWT-Objekt aufrufen (z. B. brm.getMaximum()), fügen Sie vor dem Aufruf dieser Methode eine Protokollanweisung ein, die den Wert von SwingUtilities.isEventDispatchThread() in der Codezeile protokolliert. Wenn "false" gedruckt wird, verletzen Sie das Threading-Modell von Swing/AWT und müssen SwingUtilities.invokeLater (oder Ähnliches) verwenden. –

+0

Du hast meinen Tag gerettet. – MrPk

0

starten:

JTextArea txt = new JTextArea(); 
JScrollPane jsp = new JScrollPane(history, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
txt.setCaretPosition(txt.getDocument().getLength()); // do this afeter any event 

Hoffnung, die Sie

1

ich hilft benötigt, um das gleiche für eine Protokollierung Textbereich zu tun. Die Lösungen, die ich im Internet gefunden habe, funktionierten nicht für mich (sie hören entweder auf, automatisch zu scrollen, wenn sie schnell Nachrichten auflogen, oder sie blockierten die Bildlaufleiste unten, auch wenn Sie mit dem Mausrad nach oben scrollen).

Ich tat es auf diese Weise:

public static void makeTextAreaAutoScroll(JTextArea textArea) { 

    // Get the text area's scroll pane : 
    final JScrollPane scrollPane = (JScrollPane) (textArea.getParent().getParent()); 

    // Disable the auto scroll : 
    ((DefaultCaret)textArea.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); 

    // Add a listener to the vertical scroll bar : 
    scrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { 

     private int _val = 0; 
     private int _ext = 0; 
     private int _max = 0; 

     private final BoundedRangeModel _model = scrollPane.getVerticalScrollBar().getModel(); 

     @Override 
     public void adjustmentValueChanged(AdjustmentEvent e) { 

      // Get the new max : 
      int newMax = _model.getMaximum(); 

      // If the new max has changed and if we were scrolled to bottom : 
      if (newMax != _max && (_val + _ext == _max)) { 

       // Scroll to bottom : 
       _model.setValue(_model.getMaximum() - _model.getExtent()); 
      } 

      // Save the new values : 
      _val = _model.getValue(); 
      _ext = _model.getExtent(); 
      _max = _model.getMaximum(); 
     } 
    }); 
} 

einfach es auf diese Weise verwenden:

makeTextAreaAutoScroll(yourTextArea); 

Sie können mit diesem Stück Code testen:

new Timer().schedule(new TimerTask() { 

    @Override 
    public void run() { 

     javax.swing.SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 

       String line = "test " + Math.random(); 
       yourTextArea.append(yourTextArea.getText().isEmpty() ? line : "\n" + line); 
      } 
     }); 
    } 
}, 0, 5); 

nun Ihr Textbereich Wenn die Bildlaufleiste ganz unten ist, halten Sie die automatische Bildlauffunktion an, wenn Sie die Bildlaufleiste verschieben (durch Ziehen der Leiste oder durch Drücken der Taste Rad), und automatisches Scrollen, wenn Sie die Bildlaufleiste erneut unten platzieren.

0

Nachdem ich Mike Clark und zufällige Kumpel Lösung gelesen habe, habe ich am Ende mit Code-Schnipsel.

private boolean doAutoScroll = true; 
private JTextPane textPane; 
private JScrollPane scrollPane; 

public void setup() { 
    /* Left Panel */ 
    textPane = new JTextPane(); 
    textPane.setPreferredSize(new Dimension(600, 400)); // width, height 

    /* 
    * Not update the cursor position after inserting or appending text to the JTextPane. 
    * [NOTE] 
    * This breaks normal typing into the JTextPane. 
    * This approach assumes that all updates to the JTextPane are programmatic. 
    */ 
    DefaultCaret caret = (DefaultCaret) textPane.getCaret(); 
    caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); 

    scrollPane = new JScrollPane(textPane); 
    scrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { 
     BoundedRangeModel brm = scrollPane.getVerticalScrollBar().getModel(); 
     @Override 
     public void adjustmentValueChanged(AdjustmentEvent e) { 
      // Invoked when user select and move the cursor of scroll by mouse explicitly. 
      if (!brm.getValueIsAdjusting()) { 
       if (doAutoScroll) brm.setValue(brm. getMaximum()); 
      } else { 
       // doAutoScroll will be set to true when user reaches at the bottom of document. 
       doAutoScroll = ((brm.getValue() + brm.getExtent()) == brm.getMaximum()); 
      } 
     } 
    }); 

    scrollPane.addMouseWheelListener(new MouseWheelListener() { 
     BoundedRangeModel brm = scrollPane.getVerticalScrollBar().getModel(); 
     @Override 
     public void mouseWheelMoved(MouseWheelEvent e) { 
      // Invoked when user use mouse wheel to scroll 
      if (e.getWheelRotation() < 0) { 
       // If user trying to scroll up, doAutoScroll should be false. 
       doAutoScroll = false; 
      } else { 
       // doAutoScroll will be set to true when user reaches at the bottom of document. 
       doAutoScroll = ((brm.getValue() + brm.getExtent()) == brm.getMaximum()); 
      } 
     } 
    }); 
} 

Der Unterschied besteht darin, dass sie zusätzlich MouseWheelListener unter Verwendung doAutoScroll Flags auch wenn Benutzer verwenden Mausrad zu aktualisieren, um nach oben und nach unten.

Verwandte Themen