如果你有以下GUI界面文本框输出的问题,都能在下面找到答案(亲测)。

1、处理部分比较复杂且耗时,阻塞swing线程,导致swing线程中JTextArea组件对象的内容不能实时刷新:当处理部分的代码运行结束时,JTextArea的内容会一下子刷新。
现象问题:提示信息不是一条一条显示的,而是在界面卡一段时间之后,一下全部显示。建议另外开启线程来进行复杂的处理。
核心处理:处理和显示部分直接放到同一个线程中,单独append()即可。)
2、追加的内容过多,将JTextArea放在了JScrollPane中,超出的部分可通过拖动垂直或水平的滑块观察到。
出现问题:JTextArea矩形框大小内的信息是实时更新的,超出部分是在窗口卡住一段时间后,同时添加的。
3、在开启多线程打印、使用paintImmediately()立刻渲染和scrollBar()没达到效果的情况下。

完整测试程序如下:
package org.example;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class JscollTest extends JFrame{
    private JButton jButton1; //选择文件按钮
    private JButton jButton2; //开始访问按钮

    private JTextArea showResult;  //底层文本框显示区
    private JScrollPane scrollPane;
    private JScrollBar scrollBar;

    public JscollTest(String title){
            this.setTitle(title);
            this.setSize(550, 500);//设置窗体大小
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //关闭事件触发
            this.setLocationRelativeTo(null); //窗口初始化定位
            this.setLayout(null); //组件绝对定位

            //jButton1点击开启非线程打印日志
            jButton1 = new JButton("非线程打印");
            jButton1.setFont(new Font("宋体", Font.PLAIN, 18));
            jButton1.setBounds(50, 30, 150, 70);

            //jButton2点击开启线程打印日志
            jButton2 = new JButton("线程打印");
            jButton2.setFont(new Font("宋体", Font.PLAIN, 20));
            jButton2.setBounds(350, 30, 150, 70);

            //showResult为打印输出框JTextArea
            showResult = new JTextArea();
            showResult.setFont(new Font( "宋体",Font.PLAIN,14));
            showResult.setMargin( new Insets( 5 , 5 , 5 , 5 ));
            showResult.setEditable(false);

            //* 设置编辑框为滚动面板 *//
            scrollPane = new JScrollPane(showResult);
            scrollPane.setBounds(20, 190, 500, 220);

            add(scrollPane);
            add(jButton1);
            add(jButton2);

            setVisible(true);        //使界面可视化
            setResizable(false);     //固定界面的大小

            //将按钮加入监听器监听事件。
            MyClickListener listener = new MyClickListener();
            jButton1.addActionListener(listener);
            jButton2.addActionListener(listener);

            /**
             * 在构造函数中的进行主线程的打印
             *
             *测试其他两种按钮点击情况时最好先关闭mainTreadPrint
             * */
           // mainTreadPrint();//仅是文本框内打印效果
    }
    /**
     * 放在构造函数中,加载程序时直接主线程开启打印。
     * */
    public void mainTreadPrint() {
        scrollBar = scrollPane.getVerticalScrollBar();
        for (int i = 0; i <= 1000000; i++) {
            showResult.append("你好呀,mainTreadPrint!\n" + i);
            /**
             * 注意:主线程中的打印直接JTextArea的append函数,GUI界面就能够正常显示
             *此时paintImmediately()和scrollBar.setValue()加不加都不影响效果
             *
             * */
            //showResult.paintImmediately(showResult.getBounds());//开启立即打印
            //scrollBar.setValue(scrollBar.getMaximum());//每次滚动至最后一条数据
        }
    }
    /**
     *点击按钮1,开启非线程下日志打印。
     * */
    public void nullThreadPrint() {
        for (int i = 0; i <= 1000000; i++) {
            /**
             * 注意:点击事件jButton1开启非线程打印,GUI界面都不会正常显示,两种显示效果
             * 第一种:
             * 仅仅append()追加数据,界面完全卡主,之后一次打印
             *
             * 第二种:
             * 仅仅添加showResult.paintImmediately(showResult.getBounds());
             * 页面打印也是实时打印出来,但只会实时打印一页,然后页面卡住,滚轮卡住,最后一次性打印
             *原因:showResult.getBounds()超范围,空指针异常
             *
             * 第三种:
             * 添加showResult.paintImmediately(showResult.getBounds());
             * 添加scrollBar.setValue(scrollBar.getMaximum());
             *其实也是直接报空指针异常,表现就是卡死。
             * Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
             * */
            showResult.append("你好呀,nullThreadPrint!\n" + i);
/*            showResult.paintImmediately(showResult.getBounds());
            scrollBar.setValue(scrollBar.getMaximum());//拉到最后一行*/
            jButton2.setEnabled(true);
        }
    }

    /**
     *点击按钮2,开启线程下日志打印。
     * */
    public void ThreadPrint () {
        /**
         * 这里只是打印功能,如果是比较耗时的计算,有文章讲,数据处理用一个线程,数据打印用一个线程
         * (亲测没必要,只要区别于主线程,计算和打印同时放在一个多线程中即可)
         * */
        for (int i = 0; i <= 1000000; i++) {

            /**
             * 这里开启多线程的打印,效果与在主线程中执行     
             * 特别不一致!!!!
             * 主线程中append()追加就能够正常显示,而主线程中添加
             * showResult.paintImmediately(showResult.getBounds());
             * scrollBar.setValue(scrollBar.getMaximum());//拉到最后一行
             * 也是可以正常显示的。
             *
             *但是在非主线程中,即使开启了多线程,单独地append()追加,GUI界面正常显示!
             * 一旦同时添加了
             * showResult.paintImmediately(showResult.getBounds());
             * scrollBar.setValue(scrollBar.getMaximum());
             *直接行完毕报空指针异常!!!!!。
             *
             * 单独添加showResult.paintImmediately(showResult.getBounds());
             * GUI界面反复刷新,界面显示稀碎!!!!
             *
             * 单独添加scrollBar.setValue(scrollBar.getMaximum());
             * 还是直接报java.lang.NullPointerException
             * */
            showResult.append("你好呀,ThreadPrint!\n" + i);
            //showResult.paintImmediately(showResult.getBounds());
            //scrollBar.setValue(scrollBar.getMaximum());//拉到最后一行
            jButton2.setEnabled(true);
        }
    }

    /**
     * 实现ActionListener监听方法,进行对两个按钮的事件监听
     * */
    private class MyClickListener implements ActionListener{
        private int value = 0;
        @Override
        public void actionPerformed(ActionEvent e) {
            if(e.getSource() == jButton1) {value = 1;}
            else if(e.getSource() == jButton2) {value = 2;}
            switch (value) {
                case 1:
                    showResult.setText("");
                    jButton1.setEnabled(false);
                    nullThreadPrint();  //Buttton1点击,开始不开启线程打印*/
                    break;
                case 2:
                    //这里不包裹一个线程,点击按钮2就先会卡住,像按钮1一样
                    new Thread(()-> {
                        try {
                            showResult.setText("");
                            jButton2.setEnabled(false);
                            ThreadPrint();  //Button2点击,开始进行线程打印(或者是别的功能中存在打印,同样适用)
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }).start();
                    break;
            }
        }
    }

    public static void main(String[] args) {
        new JscollTest("日志输出");
    }
}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐