Как включить дочерние события наведения мыши в родительской MouseArea с помощью QML?

Я хочу реализовать в QML следующий сценарий.

Сценарий


Вот пример / упрощенный делегат для элемента ListView:

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...
                 ]
             }
         }
    }
}

Но у меня проблема с MouseArea.
Внутренний MouseArea (actionButton) не работает должным образом для события entered. Когда мышь входит в кнопку действия, внешний MouseArea запускает событие exited.

Есть ли ошибка в моем коде? В более общем плане, как я могу реализовать такой сценарий в QML?


person S.M.Mousavi    schedule 08.08.2013    source источник


Ответы (4)


Я столкнулся с той же проблемой и нашел ответ в Документация QtQuick 5.0 для MouseArea. Ответ на этот вопрос довольно прост.

Если вы хотите включить дочерние события наведения указателя мыши в родительский MouseArea, сделайте своего ребенка MouseArea дочерним по отношению к родительскому MouseArea:

MouseArea {
    id: parent

    MouseArea {
        id: child
    }
}

Поскольку у меня есть собственный тип Widget, который будет использоваться в качестве родительского представления, в итоге свойство default было дочерним элементом MouseArea:

Item {
    default property alias children: mouseArea.data

    MouseArea {
        id: mouseArea
    }
}
person iBelieve    schedule 28.01.2014
comment
Не знаю почему! Вы можете видеть, что мой пример кода использовал этот шаблон, но не работает !! Однако теперь он работает с Qt5.2.0 :) Для других заинтересованных пользователей просто держите внутренний MouseArea внутри внешнего. Дважды проверьте hoverEnabled: true, и он будет работать. - person S.M.Mousavi; 09.02.2014
comment
Я не понимаю полностью ни одну из частей ответа. Первая часть: вы имели в виду If you want to include descendant mouse hover events in your ancestor MouseArea, make you child MouseArea a direct child of the parent MouseArea? И если да, то как работает ваш второй пример, учитывая, что он содержит только одну MouseArea? - person Stefan Monov; 16.05.2017
comment
У меня был случай использования, когда CheckBox был в строке списка, где строка списка выделялась при наведении курсора. Сначала у меня были CheckBox и MouseArea на одном уровне, но как только CheckBox был вложен в MouseArea и hoverEnabled: true был применен к охватывающему MouseArea, это включило эффекты наведения для CheckBox, этот ответ работает с Qt5.9. - person Kasheen; 05.06.2017
comment
могу подтвердить, что это работает с Qt 5.11.1. Вероятно, вы захотите иметь базовый класс с родительской областью мыши и свойством по умолчанию, как показано во втором примере. Таким образом, все элементы в его потомках будут дочерними по отношению к основной области мыши. - person rsht; 08.10.2018
comment
Отлично. Работал как шарм в 5.12 QQC2 - person Croll; 29.07.2019

Я пробовал несколько вещей, но, похоже, невозможно навести курсор на два MouseArea одновременно. preventStealing и propagateComposedEvents, похоже, работают только тогда, когда у вас есть событие щелчка. Но из внутреннего MouseArea вы можете вызвать entered() сигнал другого. Что-то вроде этого:

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();
                }
            }
        }
    }
}

Проблема в том, что сигнал exited() из содержащего MouseArea будет вызываться перед повторным вызовом entered(). Таким образом, вам может потребоваться «отложить» изменение состояния в exited(), чтобы убедиться, что вы действительно хотите скрыть свои кнопки действий. Другое решение - сохранить текущее положение мыши и скрыть кнопки, ТОЛЬКО если exited() вызывается с помощью мыши на одной из его границ.

person koopajah    schedule 09.08.2013
comment
Хорошо, но не полностью. Как я могу реализовать второе предложение? Является ли это возможным? - person S.M.Mousavi; 09.08.2013
comment
В onExited() вы можете использовать mouseX и mouseY, чтобы определить текущее положение мыши и угадать, находитесь ли вы на границе своей большой области мыши (на основе собственных x, y, height и width). Я пробовал, но есть некоторые проблемы, когда mouseX не горит при быстром перемещении мыши. Тем не менее это первый шаг - person koopajah; 09.08.2013
comment
Да, я попробовал ваше предложение. Но при быстром выводе мыши mouseX неверна (например, onExited запущен, но позиция мыши равна (14,57)). Также такая же проблема с использованием onPositionChanged. - person S.M.Mousavi; 09.08.2013
comment
Я сообщил об этой проблеме группе разработчиков bugreports.qt-project.org/browse/QTBUG-32909 - person S.M.Mousavi; 09.08.2013
comment
Я исследовал немного больше, и кажется, что как только вы выходите из MouseArea, значения для mouseX и mouseY неверны (это написано в документации). Вы можете попробовать получить позицию мыши в C ++ вместо QML, поскольку перекрывающиеся MouseArea не работают для событий наведения - person koopajah; 10.08.2013

создавать состояния для каждого состояния элементов в представлении, тогда вы можете использовать такие вещи, как операторы if или операторы case для изменения этих свойств. Другими словами, старайтесь не настраивать свои элементы для работы с MouseArea, а со свойствами. И установите для свойств Elements значение поработайте над заданными свойствами, я надеюсь, что это поможет, если нет, вот пример:

РЕДАКТИРОВАТЬ Я добавил цвет, чтобы он был прозрачным. если нет ни мыши ни чего. Если бы я использовал изображение, я бы использовал непрозрачность, а затем добавил бы кучу поведений. Но это рабочий

пример

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"
                }
            }
        }
    }
}
person guest    schedule 28.09.2013

Попробуй это:

  • добавить сигнал во внутреннюю область, который испускается при вводе мыши.
  • Подключите сигнал к внешней области.
  • Сигнал заставляет внешнюю область переходить в состояние зависания.

Выход мыши на обоих по-прежнему отменяет состояние зависания. Когда вы убираете указатель мыши с элементов управления, он должен работать правильно без лишнего кода.

person Jay    schedule 23.08.2013
comment
Я уже тестировал это, но не с помощью сигнала. Я использовал сигнал onEntered на внутреннем MouseArea. Если мышь войдет во внутренний MouseArea, внешний будет зависать. НО, есть еще одна проблема! Сигнал onExited сработает раньше, чем сигнал onEntered! onExited граница находится внутри, чем onEnter граница. - person S.M.Mousavi; 24.08.2013
comment
Я тоже подумал об этом и решил, что если сигналы пойдут в неправильном порядке, это тоже не сработает. Возможно, добавить код во внешний элемент, чтобы отслеживать наведение курсора на дочерние элементы? - person Jay; 24.08.2013
comment
Спасибо @Jay. Не успех - person S.M.Mousavi; 25.08.2013