fanbondi
fanbondi

Reputation: 1047

JScrollPane and JTextArea scrolling

I am outputting some logs into the a JTextArea enclosed in JScrollPane but the auto scrolling functionality when the output reaches the bottom of the textArea is not working. I have attempted several methods that I saw online but none works. Below is my part of my code so far.

JTextArea ouputLogPane = new JTextArea();
JScrollPane outputPane = new JScrollPane(ouputLogPane);
outputPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
outputPane.setBounds(75, 501, 746, 108);
contentPane.add(outputPane);

Now I in another class am reading from a source file and appending log details to the textArea using the code below.

public void readFile(JTextArea outputLog, JScrollPane scrollPane){
    count = 0;
    while(moreLinesToRead){
       if(count % 100 == 0){
       outputLog.update(outputLog.getGraphics());
       outputLog.append("Completed Reading"+ count + " Records "\n");
       DefaultCaret caret = (DefaultCaret)outputLog.getCaret();
       caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
       outputLog.update(outputLog.getGraphics());
       //tried the one below but did not work either
       //outputLog.setCaretPosition(outputLog.getDocument().getLength());
    }
    count++;
    }
}

Finally I am calling this method in the when a button is clicked as below.

JButton btnNewButton = new JButton("Start Reading");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
        migrationUtil.readFile(ouputLogPane,outputPane);
    }
});

So basically the complete output prints only after the execution finished. I read that I might have to use a separate thread to handle it but not very sure on how to proceed.

EDIT

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

public class ReadingExample extends JFrame {

    private JPanel contentPane;


    private Connection conn;


    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ReadingExample frame = new ReadingExample();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public ReadingExample() {
        //setResizable(false);
        setFont(new Font("Dialog", Font.BOLD, 13));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 936, 720);
        setLocationRelativeTo(null);
        contentPane = new JPanel();
        contentPane.setBorder(new LineBorder(new Color(0, 0, 0), 2));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        final JTextArea ouputLogPane = new JTextArea();
        final JScrollPane outputPane = new JScrollPane(ouputLogPane);
        //outputPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        outputPane.setBounds(67, 189, 746, 108);
        contentPane.add(outputPane);


        JButton btnNewButton = new JButton("Start Reading");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File file = new File("file.txt");
                FileReader fileReader = null;
                try {
                    fileReader = new FileReader(file);
                } catch (FileNotFoundException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                BufferedReader bufferedReader = new BufferedReader(fileReader);

                String line;
                try {
                    while((line = bufferedReader.readLine()) != null) {
                        ouputLogPane.append(line + "\n");
                        ouputLogPane.setCaretPosition(ouputLogPane.getDocument().getLength());
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException ee) {
                            ee.printStackTrace();
                        }
                    }
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }

            }
        });
        btnNewButton.setFont(new Font("Tahoma", Font.BOLD, 14));
        btnNewButton.setBounds(358, 620, 167, 29);
        contentPane.add(btnNewButton);

        //JPanel panel_3 = new JPanel();
        //panel_3.setBorder(new TitledBorder(null, "Process Log", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        //panel_3.setBounds(57, 173, 769, 132);
        //contentPane.add(panel_3);

    }
}

Upvotes: 1

Views: 129

Answers (2)

explv
explv

Reputation: 2759

What you want to do is read the file in a separate thread, so that your Swing thread is not blocked by it, allowing you to update the text area at the same time.

You still need to update the GUI on the Swing thread however, so you do this by calling SwingUtilities.invokeLater(runnable).

Here is a working example (Note I added a Thread.sleep(200) so you can see it being updated):

import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class ReadingExample {

    public static void main(String[] args) {

        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jFrame.setLocationRelativeTo(null);

        JPanel mainPanel = new JPanel(new BorderLayout());

        JTextArea jTextArea = new JTextArea();

        JScrollPane scrollPane = new JScrollPane(jTextArea);
        scrollPane.setPreferredSize(new Dimension(300, 300));
        mainPanel.add(scrollPane, BorderLayout.CENTER);

        JButton btnNewButton = new JButton("Start Reading");
        mainPanel.add(btnNewButton, BorderLayout.SOUTH);

        jFrame.setContentPane(mainPanel);

        jFrame.pack();
        jFrame.setVisible(true);

        btnNewButton.addActionListener(e -> {

            new Thread(() -> {

                File file = new File("file.txt");

                try (FileReader fileReader = new FileReader(file);
                     BufferedReader bufferedReader = new BufferedReader(fileReader)) {

                    String line;
                    while((line = bufferedReader.readLine()) != null) {

                        final String fLine = line;

                        SwingUtilities.invokeLater(() -> {
                            jTextArea.append(fLine + "\n");
                            jTextArea.setCaretPosition(jTextArea.getDocument().getLength());
                        });

                        Thread.sleep(200);
                    }

                } catch (Exception e1) {
                    e1.printStackTrace();
                }

            }).start();
        });
    }
}

Upvotes: 1

VGR
VGR

Reputation: 44293

There are two ways to scroll to the bottom. You can manipulate the scroll bar:

JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
scrollBar.setValue(scrollBar.getMaximum());

Or, you can use the more reliable scrollRectToVisible method:

try {
    textArea.scrollRectToVisible(
        textArea.modelToView(
            textArea.getDocument().getLength()));
} catch (BadLocationException e) {
    throw new RuntimeException(e);
}

Upvotes: 0

Related Questions