【问题标题】:Java Swing - JTextArea update in a Timer not constantJava Swing - Timer 中的 JTextArea 更新不恒定
【发布时间】:2021-08-17 10:33:18
【问题描述】:

我正在使用 Swing 框架开发 Java GUI 应用程序,我需要在模拟 LCD 显示的 JTextArea 中显示一些文本。

文本的每个字符通过 Swing Timer 每 250 毫秒附加一次,但是,如果我不将鼠标悬停在 JTextArea 上,则更新不是恒定的。

这是我悬停的时候

这是我不悬停的时候

这是一个示例,基于定时器 on this answer

public class App {

    public static class LCDisplay extends JTextArea {

        public LCDisplay() {
            super(1, 20);
            setEditable(false);
            Font font = new Font(Font.MONOSPACED, Font.PLAIN, 50);
            setFont(font);
            setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
            setForeground(Color.GREEN);
            setBackground(Color.BLUE);
        }

    }

    public static void main(String[] args) {
        LCDisplay display = new LCDisplay();
        display.setText("                    ");
        display.setBorder(BorderFactory.createLineBorder(Color.BLACK, 10, false));

        Function<String, Boolean> setLCDisplayText = text -> {
            int displayTextLength = display.getText().length();
            try {
                display.setText(display.getText(1, displayTextLength - 1));
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
            display.append(text);
            return display.getText().trim().isEmpty();
        };

        StringBuilder sb = new StringBuilder("Colore rosso");
        for(int i=0; i<20; i++) {sb.append(' ');}
        int interval = 250;
        AtomicInteger supIndex = new AtomicInteger(0);
        AtomicLong expected = new AtomicLong(Instant.now().toEpochMilli() + interval);
        Timer slideText = new Timer(0, e -> {
            int drift = (int) (Instant.now().toEpochMilli() - expected.get());

            boolean exceeded = setLCDisplayText.apply(sb.charAt(supIndex.getAndIncrement()) + "");
            if (exceeded) {
                supIndex.set(0);
            }
            Timer thisTimer = (Timer) e.getSource();

            expected.addAndGet(interval);
            thisTimer.setInitialDelay(Math.max(0, interval - drift));
            thisTimer.restart();
        });

        JFrame frame = new JFrame("app");
        frame.add(display);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        slideText.start();
    }

}

也许我做错了什么,但我真的不知道如何解决。

提前致谢。

【问题讨论】:

  • 为了尽快获得更好的帮助,edit 添加一个minimal reproducible exampleShort, Self Contained, Correct Example(相对于两个或多个无法编译的代码sn-ps)。
  • 更新不是恒定的。 - 当我查看您的第二张图片时,在我看来,有时 2 个字符会从左侧显示中删除。我想这就是你所说的不恒定的意思。在 Windows 10 上使用 JDK11 时,我没有看到这种行为。Swing 是单线程的,所有 GUI 代码都应该在 EDT 上执行。从计时器调用的代码在 EDT 上调用,我认为您不需要所有“原子”逻辑。
  • @camickr 看来这是我的 Debian 10 安装的问题:我在 Windows 上进行了测试,没有原子逻辑,它运行良好。无论如何,感谢您的帮助。

标签: java swing timer


【解决方案1】:

问题是由于默认情况下 OpenGL 在 Linux 中被禁用(而在 Windows 中它被启用)。

感谢this answer,我添加了以下属性

System.setProperty("sun.java2d.opengl", "true");

问题就解决了

【讨论】:

    猜你喜欢
    • 2014-12-20
    • 1970-01-01
    • 2012-08-03
    • 1970-01-01
    • 2011-07-09
    • 2017-07-30
    • 2013-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多