2013-08-08 13 views
18

Voglio implementare il seguente scenario in QML.Come includere gli eventi di passaggio del mouse del figlio nella MouseArea principale utilizzando QML?

Scenario


Ecco un/delegato semplificata di esempio per ListView elemento:

Component { 
    Item { 
     id: container 
     MouseArea { 
     anchors.fill: parent 
     hoverEnabled: true 

     onClicked: { 
      container.ListView.view.currentIndex = index 
      container.forceActiveFocus(); 
     } 
     onEntered: { 
      actionList.state = "SHOW"; 
      myItem.state = "HOVER" 
     } 
     onExited: { 
      actionList.state = "HIDE"; 
      myItem.state = "NORMAL" 
     } 
     Rectangle { 
      id: myItem 
      color: "gray" 
      anchors.fill: parent 
      Row { 
       id: actionList 
       spacing: 5; anchors.fill: parent 
       Image { 
        id: helpAction 
        source: "" //Some image address 
        width: 16; height: 16; fillMode: Image.PreserveAspectFit 
        states: [ 
         State { 
          name: "NORMAL" 
          PropertyChanges { target: helpAction; opacity: 0.7 } 
         }, 
         State { 
          name: "HOVER" 
          PropertyChanges { target: helpAction; opacity: 1.0 } 
         } 
        ] 
        MouseArea { 
         hoverEnabled: true 
         anchors.fill: parent 

         onEntered: { 
          parent.state = "HOVER"; 
         } 
         onExited: { 
          parent.state = "NORMAL"; 
         } 
        } 
        states: [ 
         State { 
          name: "SHOW" 
          PropertyChanges { target: actionList; visible: false } 
         }, 
         State { 
          name: "HIDE" 
          PropertyChanges { target: actionList; visible: true } 
         } 
        ] 
       } 

       //Other action buttons... 

       states: [ 
        // `NORMAL` and `HOVER` states definition here... 
       ] 
      } 
     } 
    } 
} 

Ma ho un problema con MouseArea.
interno MouseArea (ActionButton) non funziona correttamente per entered evento. Quando il mouse passa sul pulsante di azione, l'esterno MouseArea genera l'evento exited.

C'è qualche errore nel mio codice? Più in generale, come posso implementare un tale scenario in QML?

risposta

22

mi trovai di fronte da questo stesso problema, e mi sono imbattuto la risposta nel QtQuick 5.0 documentation for MouseArea . La risposta a questo è in realtà abbastanza semplice.

Se si desidera includere gli eventi del mouse bambino librarsi in un genitore MouseArea, fate bambino MouseArea un figlio del genitore MouseArea:

MouseArea { 
    id: parent 

    MouseArea { 
     id: child 
    } 
} 

Dato che ho un Widget tipo personalizzato che sarebbe stato utilizzato come il genitore vista, ho finito con la proprietà default i figli dello MouseArea:

Item { 
    default property alias children: mouseArea.data 

    MouseArea { 
     id: mouseArea 
    } 
} 
+5

Non so perché! Puoi vedere che il mio codice di esempio ha usato questo modello, ma non funziona !! Tuttavia ora funziona con Qt5.2.0 :) Per altri utenti interessati, tieni semplicemente "MouseArea" interno all'interno di quello esterno. Controlla per 'hoverEnabled: true' e funzionerà. –

+0

Non capisco completamente nessuna parte della risposta. Prima parte: intendevi? Se vuoi includere eventi di passaggio del mouse discendenti nell'antenato MouseArea, rendi bambino MouseArea un figlio diretto della madre MouseArea'? E se sì, come funziona il tuo secondo esempio, considerando che contiene solo * una * MouseArea? –

+0

Avevo un caso d'uso in cui un 'CheckBox' era su una riga di un elenco, dove la riga dell'elenco si evidenziava al passaggio del mouse. Inizialmente ho avuto il 'CheckBox' e il' MouseArea' allo stesso livello, ma una volta che il 'CheckBox' è stato annidato all'interno di' MouseArea' e 'hoverEnabled: true' è stato applicato all''acclesso' MouseArea' questo ha permesso gli effetti al passaggio del mouse per 'CheckBox', questa risposta funziona con Qt5.9. – Kasheen

3

Iv'e provato un paio di cose, ma non sembra possibile librarsi oltre due MouseArea contemporaneamente. Il preventStealing e propagateComposedEvents sembrano funzionare solo quando si ha un evento click. Ma dall'interno dello MouseArea è possibile attivare il segnale entered() dell'altro. Qualcosa di simile a questo:

import QtQuick 2.1 

Rectangle { 
    width: 500 
    height: 500 

    Rectangle { 
     width:300 
     height: 300 
     color: "red" 

     MouseArea { 
      id: big 
      anchors.fill: parent 
      hoverEnabled:true 
      onEntered: { 
       console.log("ENTERED BIG mousearea"); 
      } 
      onExited: { 
       console.log("EXITED BIG mousearea"); 
      } 
     } 

     Rectangle { 
      anchors.centerIn: parent 
      height: 100 
      width: 100 
      color: "green" 

      MouseArea { 
       anchors.fill: parent 
       hoverEnabled:true 
       onEntered: { 
        console.log("ENTERED small mousearea"); 
        big.entered(); 
       } 
       onExited: { 
        console.log("EXITED small mousearea"); 
        big.exited(); 
       } 
      } 
     } 
    } 
} 

Il problema è che il segnale exited() dal contenente MouseArea sarà chiamato prima di chiamare la entered() di nuovo. Quindi potresti dover "ritardare" il cambio di stato in exited() solo per essere sicuro di voler davvero nascondere i pulsanti di azione. Un'altra soluzione potrebbe essere quella di salvare la posizione corrente del mouse e nascondere i pulsanti SOLO se exited() viene chiamato con il mouse su uno dei suoi bordi.

+0

Buono ma non completo. Come posso implementare il secondo suggerimento? È possibile? –

+0

In 'onExited()' puoi usare 'mouseX' e' mouseY' per avere la posizione corrente del mouse e indovinare se sei sul bordo della tua grande torta (basata su proprio 'x',' y', 'altezza 'e' width'). Ho provato, ma ci sono alcuni problemi in cui il 'mouseX' è disattivato quando si sposta il mouse rapidamente. Ancora è un primo passo – koopajah

+0

Sì ho provato il tuo suggerimento. Ma con il mouse veloce, mouseX non è corretto (ad esempio, 'onExited' ha sparato ma il mouse è posizionato su' (14,57) '). Anche lo stesso problema usando 'onPositionChanged'. –

1

Prova questo:

  • aggiungere un segnale per l'area interna che è emessa al passaggio del mouse entrare.
  • Collegare il segnale all'area esterna.
  • Il segnale fa sì che l'area esterna entri nello stato stazionario.

L'uscita del mouse su entrambi annullerà comunque lo stato del passaggio del mouse. Come si sposta il mouse dai controlli dovrebbe funzionare correttamente senza alcun codice aggiuntivo

+0

L'ho già provato, ma non utilizzando il segnale. Ho usato il segnale 'onEntered' su' MouseArea'. Se il mouse entra nella "MouseArea" interna, quella esterna sarà sospesa. MA, c'è un altro problema! il segnale 'onExited' si innescherà prima del segnale' onEntered'! il bordo 'onExited' è interno al bordo' onEnter'. –

+0

Ho pensato anche a questo e ho deciso se i segnali andassero nell'ordine sbagliato non funzionerebbe altrettanto bene. Forse aggiungere codice all'elemento esterno per monitorare gli elementi secondari per il passaggio del mouse? – Jay

+0

Thnks @ Jay. Non successo –

4

rendere gli stati per ogni stato degli elementi nella vista, quindi è possibile utilizzare le cose come se istruzioni o istruzioni caso per modificare queste proprietà In altre parole, Cercate di non impostare gli elementi per lavorare su MouseArea ma sulle proprietà e impostare le proprietà elementi di lavorare sulle proprietà impostate spero che questo aiuta, se non qui è l'esempio:

EDIT ho aggiunto il colore ad essere trasparente . se non c'è il topo, cosa così mai Se Io sto usando un immagine vorrei utilizzare l'opacità quindi aggiungere un po 'di comportamenti anche ma questo è un lavoro

esempio

import QtQuick 2.0 
Rectangle { 
    width: 360 
    height: 360 
    property string state1:"OutMouse" 
    property string state2: "OutMouse" 
    property string state3: "OutMouse" 
    property string state4: "OutMouse" 
    Rectangle{ 
     id:blueRec 
     width: parent.width 
     height: parent.height/6 
     color: state1 === "InMouse" ? "blue" : "green" 
     MouseArea{ 
      anchors.fill: blueRec 
      hoverEnabled: true 
      onEntered: state1 = "InMouse" 
      onExited: { 
       if (state1 === state2 || state3 || state4){ 
        state1 = "InMouse" 
       } 
       if(state1 !== state2 || state3 || state4) 
       { 
        state1 = "OutMouse" 
       } 
      } 
     } 
     Text { 
      text: state1=== "InMouse"? qsTr("foo") :"bar" 
      anchors.centerIn: blueRec 
     } 
     Row{ 
      width: parent.width 
      height: parent.height/4 

      spacing: 2 
      anchors{ 
       left: parent.left 
       verticalCenter: blueRec.verticalCenter 
       leftMargin: blueRec.width/12 
      } 
      Rectangle{ 
       id: rec1 
       height: parent.height; 
       width: height 
       color: { 
        if (state3 === "InMouse") 
         return "gray" 
        if (state1 === "OutMouse") 
         return "transparent" 
        else 
         return "white"} 
       MouseArea{ 
        id: rec1M 
        anchors.fill: parent 
        hoverEnabled: true 
        onEntered:{ 
         state1 = "InMouse" 
         state2 = "InMouse" 
        } 
        onExited: state2 = "OutMouse" 
       } 
      } 

      Rectangle{ 
       id: rec2 
       height: parent.height ; 
       width: height 
       color: { 
        if (state3 === "InMouse") 
         return "gray" 
        if (state1 === "OutMouse") 
         return "transparent" 
        else 
         return "white" 
       } 
       MouseArea{ 
        id: rec2M 
        anchors.fill: parent 
        hoverEnabled: true 
        onEntered:{ 
         state1 = "InMouse" 
         state3 = "InMouse" 
        } 
        onExited: state3 = "OutMouse" 
       } 
      } 

      Rectangle{ 
       id: rec3 
       height: parent.height; 
       width: height 
       color:{ 
        if (state4 === "InMouse") 
         return "gray" 
        if (state1 === "OutMouse") 
         return "transparent" 
        else 
         return "white" 
       } 
       MouseArea{ 
        id: rec3M 
        anchors.fill: parent 
        hoverEnabled: true 
        onEntered:{ 
         state4 = "InMouse" 
         state1 = "InMouse" 
        } 
        onExited: state4 = "OutMouse" 
       } 
      } 
     } 
    } 
} 
Problemi correlati