关于qt:如何将重点转移到QML中的其他项目?

How to pass the key focus to the other item in QML?

这是我的QML文件中的代码:

main.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Rectangle {
    id: window    
    color:"white"; width: 240; height: 150

    Column {
        anchors.centerIn: parent; spacing: 15

        MyClickableWidget {
            focus: true             //set this MyWidget to receive the focus
            color:"lightblue"
        }
        MyClickableWidget {
            color:"palegreen"
        }
    }    
}

MyClickableWidget.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FocusScope {
    id: scope
    //i try to set true instead of the mouse event
    //focus: true
    //FocusScope needs to bind to visual properties of the children
    property alias color: rectangle.color
    x: rectangle.x; y: rectangle.y
    width: rectangle.width; height: rectangle.height

    Rectangle {
        id: rectangle
        anchors.centerIn: parent
        color:"lightsteelblue"; width: 175; height: 25; radius: 10; antialiasing: true
        Text { id: label; anchors.centerIn: parent }
        focus: true
        Keys.onPressed: {
            if (event.key == Qt.Key_A)
                label.text = 'Key A was pressed'
            else if (event.key == Qt.Key_B)
                label.text = 'Key B was pressed'
            else if (event.key == Qt.Key_C)
                label.text = 'Key C was pressed'
        }
    }
    MouseArea { anchors.fill: parent; onClicked: { scope.focus = true } }
}

我对此代码有两个疑问:

第一。 第一个组件已设置为focus: true。 然后按键,将显示文本。 但是我不清楚为什么为什么单击任一MyClickableWidget使其具有焦点,而单击其他小部件却失去焦点? click事件是否将焦点集中在组件上? 如果是,哪个部分将获得焦点(scoperectangle)?

另外,我认为,如下所示的行是将scope.focus设置为true。 因此,我将这一行注释掉,在scope中插入一行focus = true。 但是,它不起作用,无法将重点转移到其他项目。 为什么?

1
// MouseArea { anchors.fill: parent; onClicked: { scope.focus = true } }

结果是一样的。 我不知道为什么代码需要这一行。

第二。 在焦点范围内,如果子级具有focus: true,则所有父级和根级都将自动设置为focus: true? 如果不在焦点范围内,结果是否相同?


为什么首先需要FocusScope?如果您将其删除,则可以大大简化您的代码。

要知道的重要一点是,在FocusScope中,一次只能有一个项目具有焦点。应用程序窗口的行为类似于FocusScope本身。为简单起见,如果某个项目获得了焦点,则先前具有焦点的项目会自动失去它。

FocusRect.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Rectangle {
    width: 175;
    height: 25;
    radius: 10;

    Text { id: label; anchors.centerIn: parent }

    Keys.onPressed: {
        if (event.key == Qt.Key_A)
            label.text = 'Key A was pressed'
        else if (event.key == Qt.Key_B)
            label.text = 'Key B was pressed'
        else if (event.key == Qt.Key_C)
            label.text = 'Key C was pressed'
    }

    MouseArea
    {
        anchors.fill: parent
        onClicked: parent.forceActiveFocus()
    }
}

main.qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ApplicationWindow {

    width: 960
    height: 540

    Column {
        anchors.centerIn: parent;
        spacing: 15

        FocusRect {
            focus: true             //set this MyWidget to receive the focus
            color:"lightblue"
        }
        FocusRect {
            color:"palegreen"
        }
    }
}

这里的行为是策略性的。一个项目必须具有activeFocus才能获取关键事件。若要将Item的activeFocus设置为true,必须满足两个条件

  • 项目本身的focus属性设置为true
  • 它最接近的FocusScope父级具有activeFocus或没有focusScope父级,并且应用程序窗口具有活动焦点。

在这个简单的示例中,将MyClickableWidget的焦点设置为true还将其activeFocus设置为true(没有父FocusScope),从而使其能够获取KeyEvents。

FocusScope内回答第二个问题时,将项目的焦点设置为true不会有副作用。但是,强迫它获得activeFocus(通过在其上调用forceActiveFocus())将使其所有FocusScope父级都获得activeFocus(因此,将该项的父级层次结构中的所有FocusScope的focus设置为true)

相反,如果FocusScope获得活动焦点并将子项的焦点设置为true,则子项activeFocus也将设置为true。