이 페이지에서

신호 및 핸들러 이벤트 시스템

애플리케이션과 사용자 인터페이스 구성 요소는 서로 통신해야 합니다. 예를 들어, 버튼은 사용자가 버튼을 클릭했다는 사실을 알아야 합니다. 버튼은 상태를 나타내기 위해 색상을 변경하거나 특정 로직을 실행할 수 있습니다. 또한 애플리케이션은 사용자가 버튼을 클릭하고 있는지 여부를 파악해야 합니다. 애플리케이션은 이 클릭 이벤트를 다른 애플리케이션에 전달해야 할 수도 있습니다.

QML에는 신호와 핸들러 메커니즘이 있으며, 여기서 신호는 이벤트를 의미하고 신호 핸들러를 통해 신호에 응답합니다. 신호가 발산되면 해당 신호 핸들러가 호출됩니다. 핸들러에 스크립트나 기타 작업과 같은 로직을 배치하면 컴포넌트가 이벤트에 대응할 수 있습니다.

신호 핸들러를 통한 신호 수신

특정 객체에 대해 특정 신호가 발신될 때 알림을 수신하려면, 객체 정의에서 on<Signal>이라는 이름의 신호 핸들러를 선언해야 합니다. 여기서 <Signal> 은 신호의 이름이며, 첫 글자는 대문자로 표기합니다. 신호 핸들러에는 신호 핸들러가 호출될 때 실행될 JavaScript 코드가 포함되어야 합니다.

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 속성의 값이 변경되면 신호가 자동으로 발송됩니다. 이러한 유형의 신호를 속성 변경 신호라고 하며, 해당 신호의 핸들러는 on<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 속성이 존재한다는 사실 자체로 인해 해당 신호가 암시적으로 제공됩니다.

신호 매개변수

신호에는 매개변수가 있을 수 있습니다. 이러한 매개변수에 접근하려면 핸들러에 함수를 할당해야 합니다. 화살표 함수와 익명 함수 모두 사용할 수 있습니다.

다음 예제에서는 errorOccurred 시그널을 가진 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 엔진에서 조회 속도가 느려질 수 있습니다. 이러한 방식으로 매개변수를 주입하는 것은 더 이상 권장되지 않으며, 매개변수가 실제로 사용될 경우 런타임 경고가 발생합니다.

arguments 특수 객체 사용

자바스크립트에서는 ` arguments ` 특수 객체를 참조할 수 있습니다. 이 객체가 사용 가능한 경우, 화살표 함수가 아닌 함수에 전달된 인자의 값을 배열과 유사한 객체로 접근할 수 있습니다.

이 객체는 일반적으로 함수 본문이나 신호 핸들러에 할당된 코드 블록 내에서 사용할 수 있습니다.

신호 핸들러에 코드 블록이나 익명 함수가 할당되면, 특수 객체인 ` arguments `가 신호를 통해 전달된 인자들을 제공합니다.

예를 들어, 다음 두 코드 모두 ` [object Arguments] world undefined`를 출력합니다:

import QtQml

QtObject {
    id: root

    signal hello(message: string)

    onHello: { console.log(arguments, arguments[0], arguments[1]) }

    Component.onCompleted: root.hello("world")
}
import QtQml

QtObject {
    id: root

    signal hello(message: string)

    onHello: function () { console.log(arguments, arguments[0], arguments[1]) }

    Component.onCompleted: root.hello("world")
}

신호 핸들러에 화살표 함수를 할당하면 동작이 달라집니다. 이 경우에도 arguments 특수 객체에 접근할 수는 있지만, 해당 객체는 빈 배열과 유사한 객체가 됩니다.

예를 들어, 다음 코드는 ` [object Arguments] undefined undefined`를 출력합니다:

import QtQml

QtObject {
    id: root

    signal hello(message: string)

    onHello: () => { console.log(arguments, arguments[0], arguments[1]) }

    Component.onCompleted: root.hello("world")
}

이러한 동작의 차이는 arguments 특수 객체가 화살표 함수와 상호작용하는 방식에서 기인하지만, 바인딩에 대한 일반적인 동작과는 일관성을 유지합니다.

사양에 따르면, 화살표 함수는 자체적인 ` arguments ` 특수 객체를 보유하지 않습니다. 화살표 함수는 여전히 외곽 컨텍스트로부터 값을 차용하므로, ` arguments ` 특수 객체가 사용 가능한 경우 이를 차용할 수 있습니다.

바인딩은 평가 시 자체적인 범위를 제공합니다. 특히, 기본이 되는 화살표 함수의 검색은 바인딩의 평가를 통해 제공되는 범위 내에서 수행됩니다.

바인딩의 범위 내에서는 인자가 제공되지 않으므로, 빈 ` arguments ` 특수 객체가 사용 가능하며, 화살표 함수가 이를 검색할 때 이를 차용하게 됩니다.

화살표 함수가 아닌 함수는 자체 범위 내에서 ` arguments ` 특수 객체를 제공하므로, 신호(signal)가 전달한 인자, 즉 기본 함수 자체에 제공된 인자들을 참조할 수 있습니다.

arguments 특수 객체의 사용은 일반적으로 피해야 하며, 대신 명명된 매개변수를 사용하는 것이 좋습니다. 명명된 매개변수는 더 명확하며, 화살표 함수나 일반 함수의 사용 여부와 관계없이 일관되게 작동합니다.

Connections 유형 사용

경우에 따라 신호를 발생시키는 객체 외부에서 해당 신호에 접근해야 할 수도 있습니다. 이러한 목적을 위해 QtQuick 모듈은 임의의 객체의 신호에 연결할 수 있는 Connections 타입을 제공합니다. Connections 객체는 지정된 target 로부터 어떤 신호든 수신할 수 있습니다.

예를 들어, 앞서 예시에서 onClicked 핸들러는 onClicked 핸들러를 Connections 객체에 배치하고, 이 객체의 target 를 button 로 설정함으로써, 루트 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 객체에 자동으로 부착되었습니다. 엔진은 Rectangle 객체가 생성될 때 이 신호를 방출하여 Component.onCompleted 신호 핸들러를 트리거합니다.

부착된 신호 핸들러를 통해 객체는 각 객체별로 중요한 특정 신호에 대한 알림을 받을 수 있습니다. 예를 들어, Component.onCompleted 에 부착된 신호 핸들러가 없다면, 객체는 특정 객체로부터 오는 특별한 신호를 등록하지 않고서는 이 알림을 받을 수 없습니다. 부착된 신호 핸들러 메커니즘을 통해 객체는 별도의 코드 없이도 특정 신호를 수신할 수 있습니다.

부착된 신호 핸들러에 대한 자세한 내용은 ‘부착된 속성 및 부착된 신호 핸들러’를 참조하십시오.

사용자 정의 QML 유형에 신호 추가하기

signal 키워드를 사용하여 사용자 정의 QML 유형에 신호를 추가할 수 있습니다.

새로운 신호를 정의할 때 권장되는 구문은 다음과 같습니다:

signal <name>[([<parameter name> : <type>[, ...]])]

또한 이름 앞에 타입을 표기하는 구식 구문도 있습니다:

signal <name>[([<type> <parameter name>[, ...]])]

새로운 구문을 사용해야 합니다.

신호는 메서드로서 호출함으로써 발생합니다.

예를 들어, 아래 코드는 SquareButton.qml 라는 파일에 정의되어 있습니다. 루트 Rectangle 객체에는 activated 신호가 있으며, 이 신호는 자식 TapHandler 이 tapped 될 때마다 발생합니다. 이 특정 예제에서는 활성화된 신호가 마우스 클릭의 x 및 y 좌표와 함께 발생합니다:

// SquareButton.qml
import QtQuick

Rectangle {
    id: root

    signal activated(xPosition: real, yPosition: real)
    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() ` 메서드가 있습니다. 신호가 메서드에 연결되면, 신호가 방출될 때마다 해당 메서드가 자동으로 호출됩니다. 이 메커니즘을 통해 신호는 신호 핸들러 대신 메서드에서 수신될 수 있습니다.

아래에서는 ` connect() ` 메서드를 사용하여 ` messageReceived ` 신호를 세 개의 메서드에 연결하고 있습니다:

import QtQuick

Rectangle {
    id: relay

    signal messageReceived(person: string, notice: string)

    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++의 3개 인자를 갖는 QObject::connect() 함수와 유사합니다.

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를 보관하고 있는 아이템이 소멸될 때만 연결이 끊어집니다. 연결이 잔류하는 것을 방지하려면, 사각형이 소멸될 때 명시적으로 연결을 끊을 수 있습니다.

© 2026 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.