신호 및 핸들러 이벤트 시스템
애플리케이션과 사용자 인터페이스 컴포넌트는 서로 통신해야 합니다. 예를 들어 버튼은 사용자가 버튼을 클릭했는지 알아야 합니다. 버튼은 상태를 나타내기 위해 색상을 변경하거나 일부 로직을 수행할 수 있습니다. 또한 애플리케이션은 사용자가 버튼을 클릭했는지 여부를 알아야 합니다. 애플리케이션은 이 클릭 이벤트를 다른 애플리케이션에 전달해야 할 수도 있습니다.
QML에는 신호와 핸들러 메커니즘이 있는데, 여기서 신호는 이벤트이고 신호는 신호 핸들러를 통해 응답합니다. 신호가 발생하면 해당 신호 핸들러가 호출됩니다. 핸들러에 스크립트나 기타 연산과 같은 로직을 배치하면 컴포넌트가 이벤트에 응답할 수 있습니다.
시그널 핸들러로 신호 수신하기
특정 객체에 대해 특정 신호가 발생했을 때 알림을 받으려면 객체 정의에 <신호>라는 이름의 신호 핸들러를 선언해야 하며, 여기서 <신호>는 신호의 이름이고 첫 글자는 대문자로 표시해야 합니다. 시그널 핸들러에는 시그널 핸들러가 호출될 때 실행될 자바스크립트 코드가 포함되어야 합니다.
예를 들어, Button 유형은 Qt Quick Controls 모듈의 clicked
신호에는 버튼이 클릭될 때마다 발생하는 신호가 있습니다. 이 경우 이 신호를 수신하는 시그널 핸들러는 onClicked
입니다. 아래 예시에서는 버튼을 클릭할 때마다 onClicked
핸들러가 호출되어 부모 Rectangle 에 임의의 색상을 적용합니다:
import QtQuick import QtQuick.Controls Rectangle { id: rect width: 250; height: 250 Button { anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter text: "Change color!" onClicked: { rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } }
참고: 시그널 핸들러는 자바스크립트 함수처럼 보이지만 직접 호출해서는 안 됩니다. 시그널 핸들러와 다른 기능 간에 코드를 공유해야 하는 경우 별도의 함수로 리팩터링하세요. 그렇지 않으면 신호 처리기가 호출되도록 하려면 항상 신호를 내보내야 합니다. 동일한 신호에 대해 서로 다른 범위에 여러 개의 핸들러가 있을 수 있습니다.
속성 변경 시그널 핸들러
QML 프로퍼티 값이 변경되면 자동으로 신호가 전송됩니다. 이러한 유형의 신호는 속성 변경 신호이며 이러한 신호에 대한 신호 핸들러는 <Property>Changed 형식으로 작성되며, 여기서 <Property>는 속성 이름이며 첫 글자는 대문자로 표시됩니다.
예를 들어 MouseArea 유형에는 pressed 프로퍼티가 있습니다. 이 프로퍼티가 변경될 때마다 알림을 받으려면 onPressedChanged
라는 이름의 신호 처리기를 작성합니다:
import QtQuick Rectangle { id: rect width: 100; height: 100 TapHandler { onPressedChanged: console.log("taphandler pressed?", pressed) } }
TapHandler 문서에는 onPressedChanged
이라는 이름의 시그널 핸들러가 문서화되어 있지 않지만 pressed
속성이 존재한다는 사실에 의해 암시적으로 시그널이 제공됩니다.
신호 매개변수
신호에는 매개변수가 있을 수 있습니다. 이러한 매개변수에 액세스하려면 핸들러에 함수를 할당해야 합니다. 화살표 함수와 익명 함수 모두 작동합니다.
다음 예제에서는 오류 발생 신호가 있는 Status 컴포넌트를 살펴봅니다(QML 컴포넌트에 신호를 추가하는 방법에 대한 자세한 내용은 사용자 지정 QML 유형에 신호 추가하기를 참조하세요).
// Status.qml import QtQuick Item { id: myitem signal errorOccurred(message: string, line: int, column: int) }
Status { onErrorOccurred: (mgs, line, col) => console.log(`${line}:${col}: ${msg}`) }
참고: 함수의 공식 매개변수 이름이 신호의 이름과 일치할 필요는 없습니다.
모든 매개변수를 처리할 필요가 없는 경우 후행 매개변수를 생략할 수 있습니다:
Status { onErrorOccurred: message => console.log(message) }
관심 있는 선행 매개변수를 생략할 수는 없지만, 플레이스홀더 이름을 사용하여 독자에게 중요하지 않음을 표시할 수 있습니다:
Status { onErrorOccurred: (_, _, col) => console.log(`Error happened at column ${col}`) }
참고: 함수를 사용하는 대신 일반 코드 블록을 사용하는 것도 가능하지만 권장하지 않습니다. 이 경우 모든 신호 매개변수가 블록의 범위에 삽입됩니다. 하지만 이렇게 하면 매개변수의 출처가 불분명해 코드를 읽기 어렵고 QML 엔진에서 조회 속도가 느려질 수 있습니다. 이러한 방식으로 매개변수를 주입하는 것은 더 이상 사용되지 않으며, 매개변수가 실제로 사용되는 경우 런타임 경고가 발생합니다.
연결 유형 사용
어떤 경우에는 신호를 방출하는 객체 외부에서 신호에 액세스하는 것이 바람직할 수 있습니다. 이러한 목적을 위해 QtQuick
모듈은 임의의 객체의 신호에 연결하기 위한 Connections 유형을 제공합니다. Connections 객체는 지정된 target 으로부터 모든 신호를 수신할 수 있습니다.
예를 들어, 앞의 예제에서 onClicked
핸들러는 target 가 button
로 설정된 Connections 객체에 onClicked
핸들러를 배치하여 루트 Rectangle 에서 대신 수신할 수 있었습니다:
import QtQuick import QtQuick.Controls Rectangle { id: rect width: 250; height: 250 Button { id: button anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter text: "Change color!" } Connections { target: button function onClicked() { rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1); } } }
첨부된 신호 핸들러
첨부된 시그 널 핸들러는 핸들러가 선언된 객체가 아닌 첨부된 유형으로부터 시그널을 수신합니다.
예를 들어 Component.onCompleted 는 첨부된 시그널 핸들러입니다. 이는 종종 생성 프로세스가 완료되면 일부 자바스크립트 코드를 실행하는 데 사용됩니다. 다음은 예시입니다:
import QtQuick Rectangle { width: 200; height: 200 color: Qt.rgba(Qt.random(), Qt.random(), Qt.random(), 1) Component.onCompleted: { console.log("The rectangle's color is", color) } }
onCompleted
핸들러는 Rectangle 유형의 completed
신호에 응답하지 않습니다. 대신 completed
신호가 있는 Component
첨부 유형의 객체가 QML 엔진에 의해 Rectangle 객체에 자동으로 첨부되었습니다. 엔진은 직사각형 객체가 생성될 때 이 신호를 방출하여 Component.onCompleted
신호 처리기를 트리거합니다.
첨부된 신호 처리기를 사용하면 각 개별 개체에 중요한 특정 신호에 대해 개체에 알림을 보낼 수 있습니다. 예를 들어 Component.onCompleted
연결된 시그널 핸들러가 없는 경우, 어떤 특별한 객체에서 특별한 신호를 등록하지 않으면 객체가 이 알림을 받을 수 없습니다. 첨부된 신호 처리기 메커니즘을 사용하면 추가 코드 없이도 객체가 특정 신호를 수신할 수 있습니다.
첨부된 시그널 핸들러에 대한 자세한 내용은 첨부된 속성 및 첨부된 시그널 핸들러를 참조하세요.
사용자 지정 QML 유형에 신호 추가하기
signal
키워드를 통해 사용자 지정 QML 유형에 신호를 추가할 수 있습니다.
새 시그널을 정의하는 구문은 다음과 같습니다:
signal <name>[([<type> <parameter name>[, ...]])]
시그널을 메서드로 호출하면 시그널이 방출됩니다.
예를 들어 아래 코드는 SquareButton.qml
라는 파일에 정의되어 있습니다. 루트 Rectangle 객체에는 activated
신호가 있으며, 이 신호는 자식 TapHandler 이 tapped
일 때마다 방출됩니다. 이 예제에서는 활성화된 신호가 마우스 클릭의 x 및 y 좌표와 함께 방출됩니다:
// SquareButton.qml import QtQuick Rectangle { id: root signal activated(real xPosition, real yPosition) property point mouseXY property int side: 100 width: side; height: side TapHandler { id: handler onTapped: root.activated(root.mouseXY.x, root.mouseXY.y) onPressedChanged: root.mouseXY = handler.point.position } }
이제 SquareButton
의 모든 객체는 onActivated
신호 처리기를 사용하여 activated
신호에 연결할 수 있습니다:
// myapplication.qml SquareButton { onActivated: (xPosition, yPosition) => console.log(`Activated at {xPosition}, ${yPosition}`) }
사용자 정의 QML 유형에 대한 신호 작성에 대한 자세한 내용은 신호 속성을 참조하세요.
메서드 및 신호에 신호 연결하기
신호 객체에는 신호를 메서드나 다른 신호에 연결하는 connect()
메서드가 있습니다. 신호가 메서드에 연결되면 신호가 방출될 때마다 메서드가 자동으로 호출됩니다. 이 메커니즘을 사용하면 신호 핸들러 대신 메서드가 신호를 수신할 수 있습니다.
아래에서는 messageReceived
신호가 connect()
메서드를 사용하여 세 개의 메서드에 연결되어 있습니다:
import QtQuick Rectangle { id: relay signal messageReceived(string person, string notice) Component.onCompleted: { relay.messageReceived.connect(sendToPost) relay.messageReceived.connect(sendToTelegraph) relay.messageReceived.connect(sendToEmail) relay.messageReceived("Tom", "Happy Birthday") } function sendToPost(person: string, notice: string) { console.log(`Sending to post: ${person}, ${notice}`) } function sendToTelegraph(person: string, notice: string) { console.log(`Sending to telegraph: ${person}, ${notice}`) } function sendToEmail(person: string, notice: string) { console.log(`Sending to email: ${person}, ${notice}`) } }
대부분의 경우 connect() 함수를 사용하지 않고 시그널 핸들러를 통해 신호를 수신하는 것으로 충분합니다. 하지만 connect
메서드를 사용하면 앞서 설명한 것처럼 하나의 신호를 여러 메서드로 수신할 수 있는데, 신호 핸들러는 고유한 이름을 지정해야 하므로 불가능합니다. 또한 connect
메서드는 동적으로 생성된 객체에 신호를 연결할 때 유용합니다.
연결된 신호를 제거하기 위한 disconnect()
메서드도 있습니다:
Rectangle { id: relay //... function removeTelegraphSignal() { relay.messageReceived.disconnect(sendToTelegraph) } }
신호 대 신호 연결
connect()
메서드는 신호를 다른 신호에 연결하여 서로 다른 신호 체인을 형성할 수 있습니다.
import QtQuick Rectangle { id: forwarder width: 100; height: 100 signal send() onSend: console.log("Send clicked") TapHandler { id: mousearea anchors.fill: parent onTapped: console.log("Mouse clicked") } Component.onCompleted: { mousearea.tapped.connect(send) } }
TapHandler 의 tapped
신호가 전송될 때마다 send
신호도 자동으로 전송됩니다.
output: MouseArea clicked Send clicked
참고: 함수 객체에 대한 연결은 신호 발신자가 살아 있는 한 계속 유지됩니다. 이 동작은 C++의 QObject::connect()의 3인자 버전과 유사합니다.
Window { visible: true width: 400 height: 400 Item { id: item property color globalColor: "red" Button { text: "Change global color" onPressed: { item.globalColor = item.globalColor === Qt.color("red") ? "green" : "red" } } Button { x: 150 text: "Clear rectangles" onPressed: repeater.model = 0 } Repeater { id: repeater model: 5 Rectangle { id: rect color: "red" width: 50 height: 50 x: (width + 2) * index + 2 y: 100 Component.onCompleted: { if (index % 2 === 0) { item.globalColorChanged.connect(() => { color = item.globalColor }) } } } } } }
위의 고안된 예제에서 목표는 모든 짝수 사각형의 색을 뒤집어 어떤 전역 색을 따르도록 하는 것입니다. 이를 위해 모든 짝수 사각형에 대해 globalColorChanged 신호와 사각형의 색을 설정하는 함수를 연결합니다. 사각형이 살아있는 동안에는 예상대로 작동합니다. 그러나 지우기 버튼을 누르면 직사각형은 사라지지만 신호를 처리하는 함수는 신호가 나올 때마다 계속 호출됩니다. 이는 전역 색상을 변경할 때 백그라운드에서 실행하려는 함수가 던지는 오류 메시지에서 확인할 수 있습니다.
현재 설정에서는 globalColor를 보유한 항목이 파괴될 때만 연결이 파괴됩니다. 연결이 계속 유지되는 것을 방지하기 위해 직사각형이 파괴될 때 명시적으로 연결을 끊을 수 있습니다.
© 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.