如何在我的自定义 QML 组件中使用状态管理焦点?

How to manage Focus with States in my custom QML component?

我创建了一个可拖动的自定义组件,以便管理各个快速控制组件的几何形状。

该组件有 2 个部分:

行为描述:

  1. 无焦点:默认状态,Manipulator不可见 而且你只能看到内部组件
  2. Focused:当您单击组件(或尝试拖动它)时,您进入 此状态和操纵器变得可见,但您无法访问 内部组件。禁用按 Escape 键或在组件外部单击(进入状态 1)
  3. Inner Focus: 当你双击组件 The Manipulator 保持可见,您仍然可以调整大小,但内部 组件具有主要焦点(例如 TextEdit 现在可以是 可编辑)。禁止按下 Escape(进入状态 2)或点击组件外(进入状态 1)

Example of the Component when the Manipulator area is visible

此组件的逻辑类似于桌面环境中文件夹的逻辑(调整大小除外)操纵器将是文件夹本身,内部组件是其名称。

analogy with folder

这里是我的 post 我的操纵器的简化版本,我相信它会帮助构建一个答案,(我尝试了几个小时的很多变体,这是那些没有功能的尝试之一)

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"
    }
}

我终于找到了解决方案,正如 qt 论坛中有人所建议的那样:

Maybe reverse the dependency, i.e. make the focus depend on the state, not the state depend on the focus?

所以我更改了我的代码,现在可以使用了!

我post这里为那些可能对此感兴趣的人提供解决方案(正如我所说,这是真实代码的简化版本):

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"
    }
}