Как управлять фокусом с состояниями в моем пользовательском компоненте QML?

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

Компонент состоит из 2 частей:

  • «Манипулятор», который представляет собой перетаскиваемый прямоугольник с изменяемым размером.
  • Внутренний компонент, который находится в центре манипулятора

Описание поведения:

  1. Без фокуса: состояние по умолчанию, манипулятор невидим, и вы можете видеть только внутренний компонент.
  2. Focused: когда вы щелкаете компонент (или пытаетесь перетащить его), вы входите в это состояние, и манипулятор становится видимым, но вы не можете получить доступ к внутреннему компоненту. Отключено нажатие Escape или щелчок за пределами компонента (переходит в состояние 1)
  3. Внутренний фокус: когда вы дважды щелкаете по компоненту, манипулятор остается видимым, и вы по-прежнему можете изменять размер, но внутренний компонент имеет основной фокус (например, TextEdit теперь можно редактировать). Отключено нажатие Escape (переходит в состояние 2) или нажатие вне компонента (переходит в состояние 1)

Пример компонента, когда область манипулятора видна

Логика этого компонента будет аналогична логике папки в среде рабочего стола (за исключением изменения размера). Манипулятором будет сама папка, а внутренним компонентом — ее имя.

аналогия с папкой

Здесь я публикую упрощенную версию своего манипулятора, я уверен, что это поможет построить ответ, (я пробовал много вариантов в течение нескольких часов, это одна из тех нефункциональных попыток)

FocusScope{
    id: root
    width: 175; height: 25;
    focus: true

    states: [
        State {
            name: "noFocus"
            when: !manipulator.activeFocus && !innerComp.activeFocus
            PropertyChanges {
                target: innerComp
                enabled: false
            }
            PropertyChanges {
                target: manipulator
                visible: false
            }
        },

        State {
            name: "focused"
            when: manipulator.activeFocus
            PropertyChanges {
                target: innerComp
                enabled: false
            }
            PropertyChanges {
                target: manipulator
                visible: true
            }
        },
        State {
            name: "innerFocus"
            when: innerComp.activeFocus
            PropertyChanges {
                target: innerComp
                enabled: true
            }
            PropertyChanges {
                target: manipulator
                visible: true
            }
        }
    ]

    //visual area of manipulation (drag, redimension, etc)
    MouseArea{
        id: manipulator
        anchors.fill: parent

        onDoubleClicked: forceActiveFocus(innerComp) //go to state 3 "innerFocus"
        drag.target: manipulator

        Keys.onEscapePressed: forceActiveFocus(root) //I don´t think this is the correct to loose focus but I don´t know how to do that

        Rectangle {
            id: background
            anchors.fill: parent
            color: "lightsteelblue";
        }
    }
    //Inner Component (TextField for example)
    InnerComp {
        id: innerComp
        anchors.fill: parent

        Keys.onEscapePressed: forceActiveFocus(manipulator) //return state 2 "focused"
    }
}

person Lupo Dharkael    schedule 02.09.2016    source источник
comment
Я обнаружил, что встроенного фокуса катастрофически не хватает, обычно я фиксирую фокус на одном элементе, который действует как диспетчер событий для нескольких различных менеджеров выбора. Это просто мой вариант использования, ваш пробег может отличаться.   -  person dtech    schedule 03.09.2016


Ответы (1)


Наконец-то я нашел решение, как предложил кто-то на форуме qt:

Может быть, изменить зависимость, т. е. сделать так, чтобы фокус зависел от состояния, а не состояние зависело от фокуса?

Итак, я изменил свой код, и теперь он работает!

Я публикую решение здесь для тех, кому оно может быть интересно (как я уже сказал, это упрощенная версия реального кода):

Item {
    id: root
    width: 175; height: 25;

    states: [
        State {
            name: "noFocus"

            PropertyChanges {
                target: innerComp; enabled: false
            }
            PropertyChanges {
                target: background; visible: false
            }
            PropertyChanges {
                target: manipulator; focus: true
            }
        },

        State {
            name: "focused"

            PropertyChanges {
                target: innerComp; enabled: false
            }
            PropertyChanges {
                target: background; visible: true
            }
            PropertyChanges {
                target: manipulator; focus: true
            }
        },
        State {
            name: "innerFocus"

            PropertyChanges {
                target: innerComp; enabled: true
            }
            PropertyChanges {
                target: background; visible: true
            }
            PropertyChanges {
                target: manipulator; focus: true
            }
        }
    ]
    state: "noFocus"

    //visual area of manipulation (drag, redimension, etc)
    MouseArea{
        id: manipulator
        anchors.fill: parent

        onPressed: {
            root.state = "focused"
            forceActiveFocus(manipulator) //this prevents loosing focus in some especific situations
        }
        onDoubleClicked: root.state = "innerFocus"

        Keys.onEscapePressed: root.state = "noFocus"

    }
    Rectangle {
        id: background
        anchors.fill: parent
        color: "lightsteelblue";
    }
    //Inner Component (TextField for example)
    InnerComp {
        id: innerComp
        anchors.fill: parent

        Keys.onEscapePressed: root.state = "focused"
    }
}
person Lupo Dharkael    schedule 03.09.2016