MouseMotionListener - wie Mausverfolgung und Neuzeichnen realisieren?

affot

Mitglied
Hallo,

ich wollte mir eben eine Art "Vektorfeld" erzeugen in dem irgendwelche Punkte, Linien (wie auch immer) der Maus folgen, d.h. in deren Richtung zeigen oder sie "umzingeln". Um das konkrete Aussehen soll es hier nicht gehen, deswegen nicht weiter präzisiert...
Da kam in mir die Frage auf, wie man sowas mit dem MouseMotionListener üblicherweise realisiert. Das Feld soll ja neu gezeichnet werden sobald sich die Maus bewegt.
Da allerdings im Gegensatz zu bestimmten Aktionen wie neuskalierung etc. eine Mausbewegung ja nicht automatisch repaint() aufruft war mein erster Ansatz in der main()-Methode repaint in einer Dauerschleife auszuführen und sich in der paintComponent-Methode jedes Mal die Mausposition zu besorgen. Das funktioniert auch aber erscheint mir in vielerlei Hinsicht als sehr unelegante Lösung.
Eine Idee wäre hier in einer Dauerschleife die Mausposition abzufragen und repaint aufzurufen, wenn sich die Mausposition im Vergleich zu ihrer vorherigen Position verändert hat. Ist das der normale Weg für so etwas, oder geht man hier normalerweise ganz anders vor?

Also meine Idee:
Java:
public class PositionDetector implements MouseMotionListener {
    int x, y, xOld, yOld;
    boolean positionChanged;

    @Override
    public void mouseMoved(MouseEvent e) {
        this.x = e.getX();
        this.y = e.getY();
        if (this.xOld != x || this.yOld != y) {
            this.positionChanged = true;
            System.out.println("Position changed");
            this.xOld = x;
            this.yOld = y;
        } else {
            positionChanged = false;
            System.out.println("---");
        }
    }

Zugegeben, auch das halte ich für vollkommen unelegant, da die mouseMoved Methode ja eigentlich genau das aufzeigt, da muss ich ja nicht nochmal prüfen ob die position eine neue ist... Allerdings wollte ich noch ein boolean flag erzeugen, mit dem ich von außen abfragen kann ob sich was getan hat.

Java:
public class MouseDetectionTest {

    public static void main(String[] args) {
        DetectionPanel detectionPanel = new DetectionPanel();
        JFrame f = new JFrame("Fenster");
        f.setLayout(new GridLayout(2, 2));
        f.add(detectionPanel);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocation(200, 200);
        f.setSize(300, 300);
        f.setVisible(true);
        while (true) {
            if (detectionPanel.positionDetector.positionChanged == true) {
                detectionPanel.repaint();
            }
        }

    }

}

Der Übersichtlichkeit wegen habe ich jetzt die Klasse DetectionPanel, abgeleitet von JPanel weggelassen. Hier wird einfach ein Panel erzeugt, an diesem der Positiondetector (Typ MouseMotionlistener) angemeldet und die paintComponent(Graphics g) Methode definiert, die einfach abhängig von der Mausposition Elemente einzeichnet.
Mit der (denke ich) uneleganten Lösung (repaint() in Dauerschleife) funktioniert es im Prinzip auch, diese zweite Lösung hier funktioniert nicht und ich verstehe gar nicht warum.
In der Konsole wird mir angezeigt wenn ich die Maus bewege, wenn ich das Fenster neu skaliere, dann wird auch neu gezeichnet. Wenn ich aber die positionChanged Variable auslese und dann manuell repaint() aufrufe funktioniert es nicht... Kann mir jemand sagen warum es nicht funktioniert? Und außerdem wie man so ein Szenario üblicherweise realisiert, ohne dass sich einem Java Entwickler die Nackenhaare aufstellen? :)
 

affot

Mitglied
Verrückt, wenn ich vor die While Schleife ein Thread.sleep(1) einfüge, dann funktioniert es wie ich es mir gedacht habe - wieso das? Was macht das für einen Unterschied? 🤯
Java:
        while (true) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (detectionPanel1.positionDetector.positionChanged) {
                detectionPanel1.repaint();
            }
        }
 

Thallius

Top Contributor
Ganz einfach. Weil sonst deine Schleife ohne Unterbrechung läuft und der Thread welcher das Neuzeichnen macht überhaupt nicht dran kommt. Du must sowas immer asynchron machen
 

affot

Mitglied
Ganz einfach. Weil sonst deine Schleife ohne Unterbrechung läuft und der Thread welcher das Neuzeichnen macht überhaupt nicht dran kommt. Du must sowas immer asynchron machen
Ok, angenommen ist habe nur eine scheinbare Parallelität dann macht das für mich Sinn. Aber ich habe einen Prozessor mit 8 Kernen - sollte es sich hier nicht um reale Parallelität handeln in der ich den main() Thread nicht manuell schlafen legen muss?
Und ist das etwa der übliche Weg für so etwas? Den Thread manuell schlafen zu legen? Gibt es da nichts eleganteres?
 

affot

Mitglied
Ich verstehe die Frage ehrlich gesagt nicht. Der Listener bekommt mit, wenn sich die Maus bewegt und führt aus, was gewollt ist, z. B. ein repaint().
Aber wie kann ich im MouseListener denn repaint() auf dem Panel aufrufen? Ich habe den Listener doch am Panel angemeldet, d.h. das Panel kennt den Listener aber nicht umgekehrt.
Müsste ich hierfür dem MouseListener einen Konstruktor hinzufügen der das Panel als Attribut hinzufügt, damit der panel.repaint() aufruft?
 

affot

Mitglied
Ja logisch :) ... So hab ichs jetzt umgesetzt und dann funktioniert es auch ohne diese hässliche While-Schleife in der main()-Methode die mir alles andere blockiert...
 

affot

Mitglied
Also auch wenn ich das ursprüngliche Problem gelöst habe, ich frage mich immer noch, wieso der Main Thread den Thread blockiert, welcher das Panel neuzeichnet, wenn die Threads doch eigentlich auf unterschiedlichen Kernen real parallel ablaufen können. Hat hier noch jemand eine Erklärung parat? Wo liegt mein Denkfehler?
 

Thallius

Top Contributor
Verwendet er ja auch: main-Thread und EDT.

Ich vermute ein anderes Problem: Cache. Die Variable positionChanged ist nicht volatile, so dass ggf. alte Werte gelesen werden.

wenn der Main Thread in einer Endlosschleife steckt, dann kommt der edt aber eben nicht dran. Diese Wunschvorstellung von Java macht das dann schon wenn man mehrere Prozessoren haLate ich für ein Gerücht.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
F MouseMotionListener - Objekt bewegt sich nicht Java Basics - Anfänger-Themen 1
J KeyListener,MouseListener,MouseMotionListener und static Java Basics - Anfänger-Themen 7
M mouseMotionListener zu langsam Java Basics - Anfänger-Themen 2
G MouseMotionListener spinnt(e.getX()/e.getY()) Java Basics - Anfänger-Themen 4
C MouseMotionListener und neu zeichnen Java Basics - Anfänger-Themen 2
N Problem mit MouseMotionListener Java Basics - Anfänger-Themen 4
J MouseMotionListener implementieren Java Basics - Anfänger-Themen 3
S Hilfe mit MouseMotionListener erstellen Java Basics - Anfänger-Themen 7
S Ein Bild mit dynamischer Quelle neuzeichnen Java Basics - Anfänger-Themen 12
K Swing Fenster jede sec.neuzeichnen Java Basics - Anfänger-Themen 14
U Neuzeichnen eines JPanels Java Basics - Anfänger-Themen 17
G Neuzeichnen eines Strings Java Basics - Anfänger-Themen 3
Miladriel Problem beim Neuzeichnen nach deiconify Java Basics - Anfänger-Themen 9
J punkte verschwinden beim neuzeichnen neuer punkte Java Basics - Anfänger-Themen 11
M Grafik neuzeichnen Java Basics - Anfänger-Themen 8
G JTable das ewige neuzeichnen verbieten? Java Basics - Anfänger-Themen 7
G Neuzeichnen des Rechtecks Java Basics - Anfänger-Themen 8
L Zum neuzeichnen wirklich zwingen Java Basics - Anfänger-Themen 4
M Neuzeichnen eines Dialogs Java Basics - Anfänger-Themen 2
D Neuzeichnen eines Bildes in einer Komponente Java Basics - Anfänger-Themen 3
F Neuzeichnen eines JDialoges Java Basics - Anfänger-Themen 7

Ähnliche Java Themen

Neue Themen


Oben