Timer und GIF Animationen pausieren während Maus sich bewegt

Tazmo

Mitglied
Solange ich meine Maus in einem JFrame bewege, hören meine Timer (egal ob Swing Timer oder TimerTask) auf ihre Methoden aufzurufen, selbst animierte GIFs (ImageIcon in einem JLabel) hören auf zu animieren. Dies tritt nur auf unter macOS und bei Benutzung einer Gaming Maus (getestet mit der Rockat Kone XTD und einer Rauer Gaming Maus). Wenn ich z.B. mein Trackpad benutze funktioniert alles wunderbar.

Hier ein Beispielprogramm bei dem bei mir dieser Fehler auftritt:
Java:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.Timer;

public class Mouse{
    public static void main(String[] args){
        JFrame frame = newJFrame();

        frame.setSize(500, 500);
        frame.setVisible(true);

        Timer timer =newTimer(10, newActionListener(){

            @Override
            public void actionPerformed(ActionEvent e){
                System.out.println("foo");
            }
        });

        timer.start();
    }
}
So schaut das ganze bei mir dann aus:

source.gif


Während ich meine Maus in dem JFrame bewege wird die actionPerformed() Methode nichtmehr aufgerufen und somit auch kein "foo" in der Konsole mehr ausgegeben.

Woran könnte das liegen?
 
Seltsames Problem, woran das liegt weiss ich auch nicht. Ich koennte mir aber vorstellen, dass die Mausevents so haeufig sind, dass die Timer-events hinten angehaengt werden. Der javax.swing.Timer scheduled die Events auf dem EDT. Ein System.out muss aber nicht auf dem EDT ausgefuehrt werden. Probier mal diese Variante aus:

Code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.*;
import javax.swing.JFrame;
import javax.swing.Timer;

public class Mouse{
  public static void main(String[] args){
  JFrame frame = new JFrame();

  frame.setSize(500, 500);
  frame.setVisible(true);

  ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);   
  scheduledExecutorService.scheduleAtFixedRate(() -> System.out.println("foo"), 50, 10, TimeUnit.MILLISECONDS);
   
//  Timer timer =new Timer(10, new ActionListener(){
//
//  @Override
//  public void actionPerformed(ActionEvent e){
//  System.out.println("foo");
//  }
//  });

//  timer.start();
  }
}

Wenn du was machst, dessen Ergebnis die UI updated, dann musst du das halt selber an den EDT anhaengen.

Cheers,
Andy
 
Ah. Auch wenn ich mich zwar nicht gross mit AWT/Swing mehr beschäftige, aber die Erklärung klingt absolut einleuchtend: Während vom UI-Thread die Mouse-Events verarbeitet werden, ist keine Resource mehr für den Timer frei! Ich denke, das werde ich mir auch mal für JavaFX lieber merken!
 
Vielen Dank AndyJ!

Dein Post hat mich auf die Idee gebracht die Polling-Rate meiner Gaming Maus von 1000Hz auf 500Hz zu reduzieren und das hat tatsächlich geholfen, nun funktionieren alle Timer und animiere GIFs wieder wunderbar. Anscheinend waren 1000Hz Abfragerate einfach zu viel für Java.

Deine Lösung habe ich auch ausprobiert und es hat auch geklappt. Allerdings ist mir noch nicht ganz klar was du gemacht hast. Vielleicht könntest du erklären was es mit dem ScheduledExecutorService auf sich hat?

Grüße,
Tazmo
 
Der Punkt ist einfach, dass du mit Maus-Bewegungen Events auf dem UI-Thread auslöst - in deinem Fall eben bis zu 1000/s. Dein Timer läuft (oder lief) auf dem selben Thread und vermutlich wurde dieser Timer "schlafen" gelegt, um die Eingabe-Events (Maus) mit höherer Priorität zu bearbeiten.
@AndyJ hat nun mit seiner Lösung den "Timer" auf einen anderen Thread verlagert. Konkret wird der ScheduledExecutorService verwendet. Das ist vielleicht nicht ganz das selbe (kenne die Timer-API jetzt nicht so genau), sollte aber am Ende das selbe Ergebnis liefern. Wichtig ist nur, dass wenn du von dort die UI updaten möchtest, dass du dies über die Methode SwingUtilites#invokeLater tust.
 

Zurück
Oben