长琴弦挥杆很慢

时间:2016-12-07 14:22:52

标签: java swing

我构建了一个登录JTextArea组件的简单Java程序。

JTextArea _log = new JTextArea();
_log.setEditable(false);
JScrollPane scrollLog = new JScrollPane(_log);
scrollLog.setPreferredSize(getMaximumSize());
add(scrollLog);

问题是这样的记录平均需要 15ms

public void log(String info) {
    _log.append(info + "\n");
}

这比使用System.out.println记录要慢得多(!)。记录比算法的整个运行时间花费更多的时间!

为什么JTextArea这么慢?有没有办法改善它?

编辑1:

我正在为算法使用单独的线程,并使用SwingUtilities.invokeLater更新UI中的日志。

该算法平均在130ms后完成了他的工作,但JTextArea在平均6000ms后完成了他的append

编辑2:

我试图通过使用包含2500个字符的字符串的setText来测试它。在这种情况下,操作平均需要1000毫秒。 我尝试使用另一个控制器,然后使用JTextArea,我得到相同的结果。

Swing组件难以处理大字符串吗?我该怎么办呢?

编辑3:

我只是用这段代码测试:

public class Test extends JFrame {

    public Test() {
        final JTextArea log = new JTextArea();
        log.setEditable(false);
        log.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        JScrollPane scrollLog = new JScrollPane(log);
        scrollLog.setPreferredSize(getMaximumSize());

        JButton start = new JButton("Start");
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                long start = System.nanoTime();
                for (int i = 0; i < 2500; i++) {
                    log.append("a\n");
                }
                long end = System.nanoTime();
                System.out.println((end - start) / 1000000.0);
            }
        });

        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(2, 1));
        panel.add(scrollLog);
        panel.add(start);
        add(panel);
    }

    public static void main(String[] args) {
         Test frame = new Test();
         frame.setSize(600,500);
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);
    }
}

for循环的时间是平均1870毫秒。

这是我运行的唯一代码(在问题的顶部包含_log的声明)

1 个答案:

答案 0 :(得分:3)

JTextArea并不慢。

  

远离System.out.println远(!)。

System.out.println()在单独的Thread上执行。

  

日志比算法的空洞运行时间花费更多时间!

因此,您的算法可能正在Event Dispatch Thread (EDT)上执行,这与将文本附加到文本区域的逻辑相同。因此,文本区域不能重新绘制,直到算法结束。

解决方案是为长时间运行的算法使用单独的线程。

或许更好的选择是使用SwingWorker,这样您就可以运行算法并且&#34;发布&#34;结果到文本区域。

阅读Concurrency上的Swing教程中的部分,了解更多信息以及SwingWorker的工作示例。

编辑:

//log.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

以上行导致了问题。我第一次测试时得到125,当我一直点击按钮时得到45次。

不需要该属性。文本仍显示在文本窗格的左侧。如果您想要右对齐文本,则需要使用JTextPane并将文本窗格的属性设置为右对齐。

这就是为什么你应该总是张贴MCVE。我们无法从您的原始问题中猜到您正在使用该方法。

EDIT2:

使用JTextPane的对齐功能:

SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
textPane.getStyledDocument().setParagraphAttributes(0, doc.getLength(), center, false);

现在,您添加到文档中的任何新文本都应居中对齐。您可以将其更改为正确。