키보드 포커스 인 Qt Quick
키를 누르거나 놓으면 키 이벤트가 생성되어 포커스가 지정된 Qt Quick Item 으로 전달됩니다. 재사용 가능한 컴포넌트의 구성을 용이하게 하고 유동적인 사용자 인터페이스에 고유한 몇 가지 경우를 처리하기 위해 Qt Quick 항목은 Qt의 기존 키보드 포커스 모델에 범위 기반 확장을 추가합니다.
키 처리 개요
사용자가 키를 누르거나 놓으면 다음과 같은 일이 발생합니다:
- Qt는 키 동작을 수신하고 키 이벤트를 생성합니다.
- QQuickWindow 가 애플리케이션의 focus window 인 경우 키 이벤트가 전달됩니다.
- 키 이벤트는 씬에서 활성 포커스가 있는 Item 로 전달됩니다. 활성 포커스가 있는 항목이 없는 경우 키 이벤트는 무시됩니다.
- 활성 포커스가 있는 QQuickItem 에서 키 이벤트를 수락하면 전파가 중지됩니다. 그렇지 않으면 이벤트가 수락되거나 루트 항목에 도달할 때까지 이벤트가 항목의 부모로 전송됩니다.
다음 예의
Rectangle
유형에 활성 포커스가 있는 상태에서A
키를 누르면 이벤트가 더 이상 전파되지 않습니다.B
키를 누르면 이벤트가 루트 항목으로 전파되어 무시됩니다.Rectangle { width: 100; height: 100 focus: true Keys.onPressed: (event)=> { if (event.key == Qt.Key_A) { console.log('Key A was pressed'); event.accepted = true; } } }
- 루트 Item 에 도달하면 키 이벤트는 ignored 이 되고 일반 Qt 키 처리가 계속됩니다.
Keys attached property 및 KeyNavigation attached property 을 참조하십시오.
활성 포커스 항목 쿼리하기
Item::activeFocus
속성을 통해 Item 에 활성 포커스가 있는지 여부를 쿼리할 수 있습니다. 예를 들어, 여기에는 활성 포커스 여부에 따라 텍스트가 결정되는 Text 유형이 있습니다.
Text { text: activeFocus ? "I have active focus!" : "I do not have active focus" }
포커스 및 포커스 범위 가져오기
Item 는 focus
속성을 true
로 설정하여 포커스를 요청합니다.
아주 간단한 경우에는 focus
속성을 설정하는 것만으로도 충분할 때가 있습니다. 다음 예제를 qml 도구로 실행하면 keyHandler
유형에 활성 포커스가 있고 A
, B
또는 C
키를 누르면 텍스트가 적절하게 수정되는 것을 볼 수 있습니다.
Rectangle { color: "lightsteelblue"; width: 240; height: 25 Text { id: myText } Item { id: keyHandler focus: true Keys.onPressed: (event)=> { if (event.key == Qt.Key_A) myText.text = 'Key A was pressed' else if (event.key == Qt.Key_B) myText.text = 'Key B was pressed' else if (event.key == Qt.Key_C) myText.text = 'Key C was pressed' } } }
그러나 위의 예제를 재사용하거나 가져온 컴포넌트로 사용하려면 focus
속성을 이렇게 간단하게 사용하는 것만으로는 충분하지 않습니다.
이를 보여주기 위해 앞서 정의한 컴포넌트의 인스턴스를 두 개 생성하고 첫 번째 인스턴스에 포커스를 설정합니다. A
, B
, C
키를 누르면 두 컴포넌트 중 첫 번째 컴포넌트가 이벤트를 수신하고 그에 따라 응답하도록 하려는 의도입니다.
두 개의 MyWidget 인스턴스를 가져와서 생성하는 코드입니다:
//Window code that imports MyWidget Rectangle { id: window color: "white"; width: 240; height: 150 Column { anchors.centerIn: parent; spacing: 15 MyWidget { focus: true //set this MyWidget to receive the focus color: "lightblue" } MyWidget { color: "palegreen" } } }
MyWidget 코드:
Rectangle { id: widget color: "lightsteelblue"; width: 175; height: 25; radius: 10; antialiasing: true Text { id: label; anchors.centerIn: parent} focus: true Keys.onPressed: (event)=> { 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' } }
첫 번째 MyWidget
객체가 포커스를 갖기를 원하므로 focus
속성을 true
로 설정합니다. 그러나 코드를 실행하면 두 번째 위젯이 포커스를 받을 수 있습니다.
MyWidget
와 window
코드를 보면 문제가 분명해집니다. focus
속성을 true
로 설정하는 세 가지 유형이 있습니다. 두 개의 MyWidget
는 focus
를 true
로 설정하고 window
컴포넌트도 포커스를 설정합니다. 궁극적으로 하나의 유형만 키보드 포커스를 가질 수 있으며, 시스템은 포커스를 받을 유형을 결정해야 합니다. QML은 어떤 요소가 먼저 프로퍼티를 초기화할지 보장하지 않기 때문에 마지막 MyWidget
이 초기 포커스를 받을 수 있습니다.
이 문제는 가시성 때문입니다. MyWidget
컴포넌트는 포커스를 갖고 싶지만 가져오거나 재사용할 때 포커스를 제어할 수 없습니다. 마찬가지로 window
컴포넌트는 가져온 컴포넌트가 포커스를 요청하는지 여부를 알 수 없습니다.
이 문제를 해결하기 위해 QML은 포커스 범위라는 개념을 도입했습니다. 기존 Qt 사용자에게 포커스 범위는 자동 포커스 프록시와 같습니다. 포커스 범위는 FocusScope 유형을 선언하여 생성됩니다.
다음 예제에서는 컴포넌트에 FocusScope 타입을 추가하고 시각적 결과를 표시합니다.
FocusScope { //FocusScope needs to bind to visual properties of the Rectangle 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: (event)=> { 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' } } }
개념적으로 포커스 범위 는 매우 간단합니다.
- 각 포커스 범위 내에서 하나의 객체에
true
으로 설정된Item::focus
이 있을 수 있습니다. 둘 이상의 Item 에focus
속성이 설정되어 있는 경우, 포커스 범위가 없을 때와 마찬가지로 마지막으로 설정한focus
유형이 포커스를 갖게 되고 다른 유형은 설정되지 않습니다. - 포커스 범위가 활성 포커스를 받으면
focus
가 설정된 포함된 유형(있는 경우)도 활성 포커스를 받습니다. 이 유형도 FocusScope 인 경우 프록시 동작이 계속됩니다. 포커스 범위와 하위 포커스된 항목 모두activeFocus
속성이 설정됩니다.
FocusScope 유형은 시각적 유형이 아니므로 하위 항목의 속성은 FocusScope 의 부모 항목에 노출되어야 합니다. 레이아웃 및 위치 지정 유형은 이러한 시각적 및 스타일링 속성을 사용하여 레이아웃을 만듭니다. 예시에서 Column
유형은 FocusScope 자체에 시각적 속성이 없기 때문에 두 위젯을 제대로 표시할 수 없습니다. MyWidget 컴포넌트는 rectangle
속성에 직접 바인딩하여 Column
유형이 FocusScope 의 자식을 포함하는 레이아웃을 만들 수 있도록 합니다.
지금까지 예시에서는 두 번째 컴포넌트가 정적으로 선택되었습니다. 이제 이 컴포넌트를 클릭할 수 있도록 확장하고 원래 애플리케이션에 추가하는 것은 간단합니다. 여전히 위젯 중 하나는 기본적으로 초점이 맞춰진 상태로 설정되어 있습니다. 이제 내 클릭 가능 위젯 중 하나를 클릭하면 포커스가 부여되고 다른 위젯은 포커스를 잃게 됩니다.
두 개의 MyClickableWidget 인스턴스를 가져와서 생성하는 코드입니다:
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 코드:
FocusScope { id: scope //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: (event)=> { 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 } } }
QML Item 이 명시적으로 포커스를 포기하는 경우(활성 포커스가 있는 동안 focus
속성을 false
로 설정하여) 시스템은 포커스를 받을 다른 유형을 자동으로 선택하지 않습니다. 즉, 현재 활성 포커스가 없을 수도 있습니다.
FocusScope 유형을 사용하여 여러 영역 간에 키보드 초점을 이동하는 데모는 Qt Quick 예제 - 키 상호 작용을 참조하세요.
포커스 범위의 고급 사용
포커스 범위를 사용하면 포커스를 쉽게 분할하여 할당할 수 있습니다. 여러 QML 항목에서 이 기능을 사용합니다.
ListView예를 들어 , 그 자체가 포커스 범위입니다. ListView 에는 일반적으로 시각적 자식이 수동으로 추가되지 않으므로 일반적으로 눈에 띄지 않습니다. 포커스 범위가 되면 ListView 은 애플리케이션의 나머지 부분에 어떤 영향을 미칠지 걱정할 필요 없이 현재 목록 항목에 포커스를 맞출 수 있습니다. 이렇게 하면 현재 항목 델리게이트가 키 누름에 반응할 수 있습니다.
이 인위적인 예제는 이것이 어떻게 작동하는지 보여줍니다. Return
키를 누르면 현재 목록 항목의 이름이 인쇄됩니다.
Rectangle { color: "lightsteelblue"; width: 100; height: 50 ListView { anchors.fill: parent focus: true model: ListModel { ListElement { name: "Bob" } ListElement { name: "John" } ListElement { name: "Michael" } } delegate: FocusScope { width: childrenRect.width; height: childrenRect.height x:childrenRect.x; y: childrenRect.y TextInput { focus: true text: name Keys.onReturnPressed: console.log(name) } } } }
이 예는 간단하지만 그 이면에는 많은 일이 벌어지고 있습니다. 현재 항목이 변경될 때마다 ListView 은 델리게이트의 Item::focus
속성을 설정합니다. ListView 은 포커스 범위이므로 나머지 애플리케이션에는 영향을 미치지 않습니다. 그러나 ListView 자체에 활성 포커스가 있는 경우 델리게이트 자체도 활성 포커스를 받게 됩니다. 이 예제에서는 델리게이트의 루트 유형도 포커스 스코프이므로 Return
키를 처리하는 작업을 실제로 수행하는 TextInput 유형에 활성 포커스가 부여됩니다.
PathView 및 GridView 과 같은 모든 QML 뷰 클래스는 각 델리게이트에서 키 처리를 허용하는 유사한 방식으로 작동합니다.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.