Best Practice Eigene GUI programmieren | MouseMotion Detection

Times

Bekanntes Mitglied
Einen schönen guten Abend :)

Für mein Spiel welches ich zur Zeit in Java programmiere habe ich nun angefangen meine komplett eigene GUI zu programmieren (Von Grund auf!).

Nun an sich nimmt das ganze von Tag zu Tag immer mehr Form an, aber ich bin nun schon seit geraumer Zeit im Bereich der MouseMotion Event's und stoße immer wieder auf dasselbe Problem:

Das MouseMotion Event soll nur für die untereste / oberste (je nachdem wie man es sieht) aufgerufen werden. Wenn ich also einen Container A habe, auf diesem sich ein Container B befindet und auf B ein Button dann sollen die MouseMotion Events, wenn ich mich mit der Maus über den Button bewege, nur für den Button aufgerufen werden und nicht für Container A und Container B (Denn die Bounds der Container A und B liegen auch im Bereich der Maus).

Programmierung im Überblick (Kurzfassung)
  1. Aufruf von handleMouseMotion im Spielezyklus (max. 60* pro Sekunde) mit dem obersten Container (Screen).
  2. Um das Event "MouseExited" zu erkennen, speichere ich mir die letzte Komponente in welcher ein MouseMotionEvent ausgelöst wurde ab. Wenn diese null ist (zu Beginn des Spiels) wird diese direkt auf den Screen gesetzt um NullPointer abzufangen.
  3. MouseMotion Event nur dann auslösen wenn die letzte Mausposition ungleich der jetzigen ist.
  4. Ist die linke Maustaste gedrückt? Löse das MouseDragged Event für die letzte Komponente aus > Ende! || Andernfalls fahre mit Schritt 5 fort.
  5. Befindet sich die Mausposition innerhalb der Bounds der Komponente? Weiter, ansonsten Abbruch!
  6. Wenn sich die Bounds der letzten Komponente außerhalb der jetzigen befinden, dann loese fuer die letzte Komponente das Event "MouseExited" aus.
  7. Wenn sich die letzte Mausposition außerhalb der Bounds der aktuellen Komponente befindet, dann loese fuer die aktuelle Komponente das Event "MouseEntered" aus.
  8. Event ausloesen: MouseMoved fuer aktuelle Komponente
  9. Letzte Komponente auf aktuelle Komponente setzen.
  10. handleMouseMotion fuer jede weiter Unterkomponente aufrufen (Fuer Container!).

Nun nochmal zu meinem Problem:

  • MouseMoved soll nur bei der untersten Komponente ausgeführt werden.
  • MouseExited soll ebenfalls aufgerufen wenn sich die Maus auf einer Komponente innerhalb der vorherigen Komponente befindet (Im obigen Beispiel, wenn ich mit der Maus ueber den Button gehe, soll MouseExited fuer Container B ausgelöst werden.

Hier nochmal mein bisheriger Code:

Java:
    /**
     * MouseMotion Event Erkennung.
     * @param component Komponente welche geprueft werden soll.
     * @param delta Zeit vergangen seit letztem Aufruf (in ms).
     * @param mouseX Mausposition Pixel X-Achse (Links: 0).
     * @param mouseY Mausposition Pixel Y-Achse (Oben: 0).
     * @param glX Bereits umgerechnete Mauspotion im OpenGL Koordinatensystem X - Achse (Links: -1, Rechts: +1).
     * @param glY Bereits umgerechnete Mauspotion im OpenGL Koordinatensystem Y - Achse (Oben: +1, Unten: -1).
     */
    private void handleMouseMotion(Component component, float delta, float mouseX, float mouseY, float glX, float glY) {
        if (this.cmpMouseMotion == null){
            this.cmpMouseMotion = component;
        }
 
        // MouseMotion Events koennen nur dann auftreten
        // wenn sich die Maus bewegt
        if (mouseX != this.lastMouseX && mouseY != this.lastMouseY) {

            MouseMotionEvent mmEventComponent = new MouseMotionEvent(component, delta, mouseX, mouseY);
            MouseMotionEvent mmEventComponentLast = new MouseMotionEvent(this.cmpMouseMotion, delta, mouseX, mouseY);
          
            MouseMotionListener[] mmListenerComponent = component.getMouseMotionListeners();
            MouseMotionListener[] mmListenerComponentLast = this.cmpMouseMotion.getMouseMotionListeners();

            // Pruefung auf Linksklick, wodurch ein MouseDragged Event
            // auf der bestehenden letzten Componente durchgefuehrt wird
            if (Mouse.isButtonDown(0)){
                if (mmListenerComponentLast != null){
                    for(MouseMotionListener mml : mmListenerComponentLast){
                        mml.mouseDragged(mmEventComponentLast);
                    }
                }
            }else{
              
                // Befindet sich die Maus in der uebergebenen Componente?
                if (component.getBounds().inGlBounds(glX, glY)){
                  
                    // Wenn sich die letzte Componente außerhalb der aktuellen
                    // Mausposition befindet, dann loese fuer diese Componente
                    // das Event "MouseExited" auf.
                    if (!this.cmpMouseMotion.getBounds().inGlBounds(glX, glY)){
                        // Eventausloeser: MouseExited bei der letzten Componente
                        if (mmListenerComponentLast != null){
                            for(MouseMotionListener mml : mmListenerComponentLast){
                                mml.mouseExited(mmEventComponentLast);
                            }
                        }
                    }
                  
                    // Wenn die letzte Mausposition außerhalb der Bounds der
                    // uebergebenen Componente war, dann loese fuer diese
                    // Componente das Event "MouseEntered" auf.
                    if (!component.getBounds().inGlBounds(this.lastMousePosGlX, this.lastMousePosGlY)){
                        if (mmListenerComponent != null){
                            for (MouseMotionListener mml : mmListenerComponent){
                                System.out.println("Enter");
                                mml.mouseEntered(mmEventComponent);
                            }
                        }
                    }
                 
              
                    // Eventausloeser: MouseMoved bei der uebergebenen Componente
                    if (mmListenerComponent != null){
                        for (MouseMotionListener mml : mmListenerComponent){
                            mml.mouseMoved(mmEventComponent);
                        }
                    }
                  
                    // Die uebergebene Componente ist nun die letzte
                    this.cmpMouseMotion = component;
                  
                    if (component.getComponents() != null){
                        // Pruefe weiter fuer Unterkomponenten
                        for (Component subComponent : component.getComponents()) {
                            handleMouseMotion(subComponent, delta, mouseX, mouseY, glX, glY);
                        }
                    }
                  
                }

            }

        }

    }


Ich hoffe jemand versteht mein Anliegen und kann mir einen Tipp geben :)

Edit: Manchmal ... öfters kommt es vor, das ich hier was schreibe nachdem ich stundenlang nach einer Lösung suche und ungefährt 5 Minuten später fällt mir eine super einfache Lösung ein.
Einfach von Beginn an eine Methode schreiben welche die unterste Komponente ermittelt... ich probiere das ganze nun aus und gebe noch Rückmeldung... xD
 
Zuletzt bearbeitet:

Times

Bekanntes Mitglied
So,

da bin ich nochmal.
Tut mir Leid hier einen unnötigen Beitrag gepostet zu haben, kann den oben liegenden leider nicht mehr editieren und ein "Solved" dazu-schreiben.

Also die Lösung war wie bereits im Edit geschrieben, eine Methode welche mir direkt die unterste Komponente ermittelt. So brauche ich den recursiven Aufruf von handleMouseMotion nicht mehr und damit hat sich mein Problem in Luft aufgelöst.

Grüße Times :)

Hier noch eine aktualisierte Version des Codes, welcher nun einfache Uberpruefungen enthält und den Code wesentlich eleganter macht :)


Java:
  /**
     * MouseMotion Event Erkennung.
     *
     * @param screen Oberste Komponente welche geprueft werden soll (Screen).
     * @param delta Zeit vergangen seit letztem Aufruf (in ms).
     * @param mouseX Mausposition Pixel X-Achse (Links: 0).
     * @param mouseY Mausposition Pixel Y-Achse (Oben: 0).
     * @param glX Bereits umgerechnete Mauspotion im OpenGL Koordinatensystem X
     * - Achse (Links: -1, Rechts: +1).
     * @param glY Bereits umgerechnete Mauspotion im OpenGL Koordinatensystem Y
     * - Achse (Oben: +1, Unten: -1).
     */
    private void handleMouseMotion(Component screen, float delta, float mouseX, float mouseY, float glX, float glY) {

        // MouseMotion Events koennen nur dann auftreten
        // wenn sich die Maus bewegt
        if (mouseX != this.lastMouseX && mouseY != this.lastMouseY) {

            Component component = getLowestComponent(screen, glX, glY);

            if (this.cmpMouseMotionLast == null) {
                // NullPointer abfangen (Erster Aufruf)
                this.cmpMouseMotionLast = component;
            }

            MouseMotionEvent mmEventComponent = new MouseMotionEvent(component, delta, mouseX, mouseY);
            MouseMotionEvent mmEventComponentLast = new MouseMotionEvent(this.cmpMouseMotionLast, delta, mouseX, mouseY);

            MouseMotionListener[] mmListenerComponent = component.getMouseMotionListeners();
            MouseMotionListener[] mmListenerComponentLast = this.cmpMouseMotionLast.getMouseMotionListeners();

            // Pruefung auf Linksklick, wodurch ein MouseDragged Event
            // auf der bestehenden letzten Componente durchgefuehrt wird
            if (Mouse.isButtonDown(0)) {
                if (mmListenerComponentLast != null) {
                    for (MouseMotionListener mml : mmListenerComponentLast) {
                        mml.mouseDragged(mmEventComponentLast);
                    }
                }
            } else {
              
                // Wenn die letzte Komponente ungleich der aktuellen ist, loese
                // fuer die letzte Komponente das Event "MouseExited" aus und fuer
                // die aktuelle Komponente das Event "MouseEntered".
                if (this.cmpMouseMotionLast != component){
                    if (mmListenerComponentLast != null) {
                        for (MouseMotionListener mml : mmListenerComponentLast) {
                            mml.mouseExited(mmEventComponentLast);
                        }
                    }
                  
                    if (mmListenerComponent != null) {
                        for (MouseMotionListener mml : mmListenerComponent) {
                            mml.mouseEntered(mmEventComponent);
                        }
                    }
                }

                // Eventausloeser: MouseMoved bei der aktuelle Componente
                if (mmListenerComponent != null) {
                    for (MouseMotionListener mml : mmListenerComponent) {
                        mml.mouseMoved(mmEventComponent);
                    }
                }

                // Die aktuelle Componente ist nun die letzte
                this.cmpMouseMotionLast = component;

            }

        }

    }

    /**
     * Ermittelt die unerste Komponente innerhalb der ubergebenen Komponente.
     * @param component Komponente von welche die unterste Komponente ermittelt werden soll.
     * @param glX Bereits umgerechnete Mauspotion im OpenGL Koordinatensystem X
     * - Achse (Links: -1, Rechts: +1).
     * @param glY Bereits umgerechnete Mauspotion im OpenGL Koordinatensystem Y
     * - Achse (Oben: +1, Unten: -1).
     * @return Unterste Komponente an Mausposition. Wenn Maus außerhalb der Bounds
     * liegt, wird null zurueckgegeben.
     */
    private Component getLowestComponent(Component component, float glX, float glY) {
        if (component.getBounds().inGlBounds(glX, glY)) {
            Component lowest = component;
            if (component.getComponents() != null) {
                for (Component subComponent : component.getComponents()) {
                    Component tmp = getLowestComponent(subComponent, glX, glY);
                    if (tmp != null) {
                        lowest = tmp;
                    }
                }
            }
            return lowest;

        }
        return null;
    }
 
Zuletzt bearbeitet:

stg

Top Contributor
Da du dein Problem ja offenbar schon selbst gelöst hast nur noch eine kleine Anmerkung:

Statt if (mouseX != this.lastMouseX && mouseY != this.lastMouseY)
soll es sicher if (mouseX != this.lastMouseX || mouseY != this.lastMouseY)
sonst "schluckst" du vertikale bzw horizontale Bewegungen, was vermutlich nicht gewünscht ist.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Eigene Datenstruktur um eine Menge zu speichern Allgemeine Java-Themen 3
_user_q Was brauche ich, um eine eigene "Search for updates"-Funktion einzubauen? Allgemeine Java-Themen 1
pizza_dox_9999 Wie füge ich eine "eigene" ScriptEngine dem ScriptEngineManager? Allgemeine Java-Themen 3
E Input/Output Eigene Datei mit java öffnen Allgemeine Java-Themen 9
missy72 Klassen Eigene Klasse MessageWindow ähnlich der Alert Klasse Allgemeine Java-Themen 2
J Eigene Api erstellen und dann auch verwenden - Ordnerstruktur Allgemeine Java-Themen 1
RalleYTN Eigene ScriptEngine? Allgemeine Java-Themen 14
L Eigene Dependency Injections definieren? Allgemeine Java-Themen 4
K Eigene API erstellen? Allgemeine Java-Themen 13
M Eigene forEach()-Methode funktioniert nicht. Allgemeine Java-Themen 2
J eigene Java Bibliothek Allgemeine Java-Themen 2
M Output einer anderen/externen .jar in eigene JTextArea Allgemeine Java-Themen 4
B Klassen Eigene Klasse als Array benutzen Allgemeine Java-Themen 3
D Eigene/r Collection/Container Allgemeine Java-Themen 3
F Eigene .jar mit anderer .jar öffnen Allgemeine Java-Themen 7
X Eigene Annotation - mit Bedingung für ganze Klassen oder Methoden Allgemeine Java-Themen 2
H Best Practice Ideensuche: Flexibel hinzufügbare eigene Parser Allgemeine Java-Themen 6
T OOP Die eigene Bruchklasse Allgemeine Java-Themen 11
P Eigene Exception Klasse Allgemeine Java-Themen 7
J Java - Eigene DLL importieren Allgemeine Java-Themen 25
B JTable eigene Daten Add Methode Allgemeine Java-Themen 2
S OOP Problembereichsmodell: Bestehende Framework Klasse in eigene Klassenstruktur einbinden Allgemeine Java-Themen 9
E Eigene Exception Klasse erstellen Allgemeine Java-Themen 3
S Methoden Eigene Klasse als Rückgabewert Allgemeine Java-Themen 6
S eigene regEx schreiben Allgemeine Java-Themen 4
O Collections Eigene Methodenzusicherung bei Collections als Parameter Allgemeine Java-Themen 2
M Eigene Klasse verschlüsselt in Datei speichern Allgemeine Java-Themen 13
N Geodaten für eigene Routenplanung Allgemeine Java-Themen 5
M Problem beim schreiben einer eigene generische Klasse Hashtable Allgemeine Java-Themen 11
C Eigene Sounddateien schreiben Allgemeine Java-Themen 12
M Problem beim schreiben einer eigene generische Klasse LinkedList Allgemeine Java-Themen 34
M Best Practices Exception Handling für eigene library Allgemeine Java-Themen 8
M Eigene Factory Klasse Allgemeine Java-Themen 21
M eigene Klasse durch Composition mit java.io.File erweitern Allgemeine Java-Themen 3
S eigene Update Funktion Allgemeine Java-Themen 5
H2SO3- getMethods(): eigene methoden rausfinden Allgemeine Java-Themen 4
C eine eigene Javadoc erstelen Allgemeine Java-Themen 3
Kr0e Eigene RMI Implementierung Allgemeine Java-Themen 3
S Eigene Bibliothek Allgemeine Java-Themen 2
M Eigene Dateiendung? Allgemeine Java-Themen 3
M Plugins für eigene Programme Allgemeine Java-Themen 3
S Eigene Events feuern Allgemeine Java-Themen 3
S Instanz in einer Klasse erstellen, und dem Konstruktor die eigene Klasse mitgeben Allgemeine Java-Themen 4
A Eigene Java Plugins entwickeln - wie optimal? Allgemeine Java-Themen 14
R Eigene ArrayList vom Typ Short, Integer oder Double Allgemeine Java-Themen 4
U Eigene "Dining Philosopher" Interpretation weckt Philos nie auf Allgemeine Java-Themen 2
0x7F800000 Wovon eigene Events für spezialisierte JComponents ableiten? Allgemeine Java-Themen 2
SuperSeppel13 Packete der Java Bibliothek ins eigene Prjekt integrieren Allgemeine Java-Themen 4
P Eigene Klasse kopieren die auf sich selbst refferenziert Allgemeine Java-Themen 8
G Umgebungsvariabeln auslesen (Path, Temp, oder eigene) Allgemeine Java-Themen 2
T Eigene PID ermitteln! Allgemeine Java-Themen 3
D Icon für eigene Dateiendung Allgemeine Java-Themen 7
G Eigene "Speicherverwaltung" Allgemeine Java-Themen 5
H eigene Annotations Allgemeine Java-Themen 2
S eigene Klasse die JButton extended - als Liste! Allgemeine Java-Themen 6
D Performance: ArrayList vs. Array vs. "Eigene Liste&quot Allgemeine Java-Themen 8
A Eigene Wrapper-Klassen Allgemeine Java-Themen 2
J Kann eigene Klasse nicht ermitteln Allgemeine Java-Themen 4
M Wann verwendet man PropertyChangedEvents, wann eigene? Allgemeine Java-Themen 3
J OpenOffice.org Events in eigene Anwendung umleiten Allgemeine Java-Themen 4
U eigene Datenstruktur ArrayList<String> nach Object [][ Allgemeine Java-Themen 2
N Observer/Observable der JAVA-API od. eigene Implementierung Allgemeine Java-Themen 2
B eigene Klassen verkaufen Allgemeine Java-Themen 2
W eigene event-Klasse, event posten Allgemeine Java-Themen 2
reibi Eigene exception mit feld "serialVersionUID" Allgemeine Java-Themen 3
M Eigene .jar in anderes Programm importieren[eclipse] Allgemeine Java-Themen 6
T Eigene Libary Allgemeine Java-Themen 6
E Eigene Exception Allgemeine Java-Themen 11
Q Bibliotheken mit ins eigene Jar aufnehmen Allgemeine Java-Themen 4
M Eigene Exception Klasse Allgemeine Java-Themen 4
M eigene Objekte vergleichen Allgemeine Java-Themen 6
K log4j - eigene Info-Ausgaben Allgemeine Java-Themen 5
G Performance JDOM - DOM - eigene HashMap (SAX) Allgemeine Java-Themen 2
G JWindow verschieben bei mousedragged auf eigene titelleiste Allgemeine Java-Themen 3
N Methoden in eigene Dateien auslagern? Allgemeine Java-Themen 10
B Eigene Datentypen Allgemeine Java-Themen 5
G Brauche hilfe bei JMF: Wie eigene Streaming Data Source! Allgemeine Java-Themen 4
G eigene klassen die ein jar verwenden als neues jar erstellen Allgemeine Java-Themen 4
O Externe Jars in eigene JAr packen in Eclipse Allgemeine Java-Themen 5
R Updateprozedur ü. Internet fürs eigene Programm? Allgemeine Java-Themen 24
G eigene uhrzeit in einer java applikation führen Allgemeine Java-Themen 19
R Eigene Konfigurationsdatei für größere Projekte. Allgemeine Java-Themen 4
J Eigene Callback Methode? Allgemeine Java-Themen 3
S eigene evetns erstellen Allgemeine Java-Themen 5
K eigene GUI Komponente wird nicht angezeigt Allgemeine Java-Themen 3
D Eigene Classes aus anderen .java-Dateien Allgemeine Java-Themen 2
G Eigene PrintService Implementierung. Allgemeine Java-Themen 5
C Die Konsole ins eigene Programm einbauen Allgemeine Java-Themen 5
T Programmieren als Angestellter Allgemeine Java-Themen 2
NoahPillich Navigations-App und Wegfindung selber programmieren - Erfahrungen, Ideen, Anregungen Allgemeine Java-Themen 6
M Aussagenlogik in Java Programmieren Allgemeine Java-Themen 22
B hard wrap selber programmieren Allgemeine Java-Themen 9
berserkerdq2 run-methode eines Threads so programmieren, dass 30x die Sekunde etwas ausgeführt wird. Allgemeine Java-Themen 44
L Einfache Navigations-App schnell selber Programmieren? Bitte um Ideen und Anregungen. Allgemeine Java-Themen 17
Q Java-Programmieren Allgemeine Java-Themen 1
B BOT mit Java [Eclipse] programmieren Allgemeine Java-Themen 7
kanywayne Java programmieren: Polynom Klasse Allgemeine Java-Themen 4
O wie kann ich p = s · (1 + r )^t-s programmieren? Allgemeine Java-Themen 7
N Lottowebsite programmieren mittels Java, HTML,.... Allgemeine Java-Themen 7
J Vokabeltrainer programmieren Allgemeine Java-Themen 4

Ähnliche Java Themen

Neue Themen


Oben