简体   繁体   中英

How to continue autoscroll in JTextArea after mouse click?

I have a very useful autoscrolling JTextArea/JScrollPane that continuously appends lines of text at the bottom and scrolls up. I'd like to be able to double-click on a word and copy it to the clipboard for further processing of that word. But I'd like the autoscrolling to continue to scroll from the bottom.

However, as soon as I press the mouse in the JTextArea, the scrolling stops. The new lines are still added, but the scrolling freezes. The vertical scroll bar then starts to move up, showing that the text is being added below the view area. I can manually scroll down with the scroll bar, but it is manual only. The autoscrolling has been disabled.

I suspect the issue is with focus. Somehow, perhaps the autoscroll loses focus to the manual mouse event. I have tried all kinds of fixes but nothing works.

I am using the very useful Caret update policy to enable the scrolling from the bottom.

caret = (DefaultCaret) jTextArea1.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

Here is greatly-reduced but fully-functional Java code illustrating the issue.

package demoswingworker;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.SwingWorker;
import javax.swing.text.DefaultCaret;

public class ScrollTextArea extends javax.swing.JFrame {

String[] sentences;
Map sentenceMap = new TreeMap();

DefaultCaret caret;

public ScrollTextArea() {
initComponents();

caret = (DefaultCaret) jTextArea1.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
this.setLocation(0, 0);
this.setSize(140, 300);
this.setVisible(true);

for (int i = 0; i < 100; i++) {
    sentenceMap.put(i, i + "-abcdef");
}
scroll();
}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    jScrollPane1 = new javax.swing.JScrollPane();
    jTextArea1 = new javax.swing.JTextArea();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setBackground(new java.awt.Color(255, 153, 0));
    setFont(new java.awt.Font("Times New Roman", 1, 14)); // NOI18N

    jTextArea1.setBackground(new java.awt.Color(255, 153, 0));
    jTextArea1.setColumns(20);
    jTextArea1.setFont(new java.awt.Font("Times New Roman", 1, 22)); // NOI18N
    jTextArea1.setLineWrap(true);
    jTextArea1.setRows(5);
    jTextArea1.setWrapStyleWord(true);
    jScrollPane1.setViewportView(jTextArea1);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 974, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 249, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap())
    );

    pack();
}// </editor-fold>                        


public static void main(String args[]) {
new ScrollTextArea();
}

protected void scroll() {
SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
    @Override
    protected Void doInBackground() throws Exception {
    for (int i = 0; i < 100; i++) {
        try {
        Thread.sleep(1000);
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        jTextArea1.append(sentenceMap.get(i).toString() + "\n");
        publish(i);
    }
    return null;
    }

    @Override
    protected void process(List<Integer> chunks) {
    }

    @Override
    protected void done() {
    jTextArea1.append("Done");
    }
};
worker.execute();
}

// Variables declaration - do not modify                     
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration                   
}

This mechanism of auto-scroll relies on the cursor always being at the very end of the content of the text area. For as long as the cursor is at the end, you have auto-scrolling. The moment the cursor goes anywhere else but the end, auto-scrolling ceases.

So, in order to resume auto-scrolling, the only thing you need to do is move the cursor to the very end. You can look for a way to do this programmatically, but until then you can just hit Ctrl+End when you want auto-scrolling to resume.

Also please note that I found several warnings in your code, which means that you are programming without many useful warnings enabled, which tends to be very error-prone business.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM