【问题标题】:JScrollPane and JTextArea scrollingJScrollPane 和 JTextArea 滚动
【发布时间】:2016-06-28 15:58:25
【问题描述】:

我正在将一些日志输出到包含在 JScrollPane 中的 JTextArea 中,但是当输出到达 textArea 底部时,自动滚动功能不起作用。我尝试了几种我在网上看到的方法,但都没有奏效。到目前为止,以下是我的部分代码。

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

现在我在另一堂课中正在读取源文件并使用下面的代码将日志详细信息附加到 textArea。

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++;
    }
}

最后我在单击按钮时调用此方法,如下所示。

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

所以基本上只有在执行完成后才会打印完整的输出。我读到我可能必须使用单独的线程来处理它,但不太确定如何进行。

编辑

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

    }
}

【问题讨论】:

    标签: java jscrollpane jtextarea


    【解决方案1】:

    你要做的是在一个单独的线程中读取文件,这样你的Swing线程就不会被它阻塞,让你同时更新文本区域。

    但是,您仍然需要在 Swing 线程上更新 GUI,因此您可以通过调用 SwingUtilities.invokeLater(runnable) 来完成此操作。

    这是一个工作示例(注意,我添加了 Thread.sleep(200),因此您可以看到它正在更新):

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

    【讨论】:

    • 我有几乎相同的代码并查看我的编辑。我不知道为什么它不起作用。
    • 所以基本上它就像 textArea 更新被主线程阻止了。
    【解决方案2】:

    有两种方法可以滚动到底部。您可以操纵滚动条:

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

    或者,您可以使用更可靠的scrollRectToVisible 方法:

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

    【讨论】:

    • 你能检查我的编辑吗,我提供了完整的源代码,因为我有你的方法,但它不起作用。
    • 您在 cmets 中对另一个答案的结论是正确的:您正在阻塞事件调度线程,这会阻止任何组件绘制。见Concurrency in Swing
    猜你喜欢
    • 2014-06-11
    • 2018-01-25
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 2022-11-03
    • 2016-05-28
    • 2011-01-09
    相关资源
    最近更新 更多