0

I'm developing a Java GUI application with the Swing framework where I need to show some text in a JTextArea that simulates an LCD display.

Each character of the text is appended every 250 ms through a Swing Timer but, If I don't hover with the mouse on the JTextArea, the update is not constant.

This is when I hover

good result

This is when I don't hover

bad result

Here's an example, with a Timer based 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();
    }

}

Maybe I'm doing something wrong but I really don't know how to solve.

Thanks in advance.

dems98
  • 814
  • 3
  • 9
  • 22
  • For better help sooner, [edit] to add one [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/) (as opposed to two or more uncompileable code snippets). – Andrew Thompson Aug 17 '21 at 10:43
  • *the update is not constant.* - when I look at your second image it looks to me like sometime 2 characters are removed from display on the left side. I guess this is what you mean by not constant. I don't see this behaviour when using JDK11 on Windows 10. Swing is single threaded and all GUI code should be executed on the EDT. Code invoked from the timer is invoked on the EDT to I don't think you need all that "atomic" logic. – camickr Aug 17 '21 at 14:34
  • 1
    @camickr It looks like it's a problem with my Debian 10 installation: I tested on Windows, without the atomic logic, and It worked perfectly. Anyway, thanks for the help. – dems98 Aug 17 '21 at 18:29

1 Answers1

0

The problem was due the fact that OpenGL, by default, is disabled in Linux (while in Windows it is enabled).

Thanks to this answer, I've added the following property

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

And the problem is gone

problem solved

dems98
  • 814
  • 3
  • 9
  • 22