このページでは

シグナルとハンドラによるイベントシステム

アプリケーションとユーザーインターフェースのコンポーネントは、互いに通信する必要があります。たとえば、ボタンはユーザーがそれをクリックしたことを認識する必要があります。ボタンは、その状態を示すために色を変更したり、何らかのロジックを実行したりすることがあります。同様に、アプリケーションもユーザーがボタンをクリックしているかどうかを知る必要があります。アプリケーションは、このクリックイベントを他のアプリケーションに伝達する必要がある場合があります。

QMLにはシグナルとハンドラの仕組みがあり、シグナルがイベントそのものであり、シグナルハンドラを通じてシグナルに応答します。シグナルが発信されると、対応するシグナルハンドラが呼び出されます。スクリプトやその他の操作などのロジックをハンドラ内に記述することで、コンポーネントはイベントに応答できるようになります。

シグナルハンドラによるシグナルの受信

特定のオブジェクトに対して特定のシグナルが発信された際に通知を受け取るには、そのオブジェクトの定義でon<Signal> という名前のシグナルハンドラを宣言する必要があります。ここで、<Signal>はシグナルの名前であり、最初の文字は大文字にします。シグナルハンドラには、シグナルハンドラが呼び出された際に実行される JavaScript コードを含める必要があります。

たとえば、Qt Quick の「Controls」モジュールにあるButton タイプには、ボタンがクリックされるたびに発火する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);
        }
    }
}

注: シグナルハンドラはJavaScriptの関数に少し似ていますが 、直接呼び出してはいけません。シグナルハンドラと他の機能の間でコードを共有する必要がある場合は、別の関数にリファクタリングしてください。それ以外の場合は、シグナルハンドラを呼び出したいときは常にシグナルを発行してください。同じシグナルに対して、異なるスコープに複数のハンドラが存在することがあります。

プロパティ変更シグナルハンドラ

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` の使用

JavaScript では、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 という特殊オブジェクトを提供するため、基底関数自体に渡された引数(シグナルから提供されたフォワード引数)を参照することができます。

arguments という特殊オブジェクトの使用は、一般に避けるべきです。その代わりに、より明示的で、矢印関数か非矢印関数の使用にかかわらず一貫して動作する名前付きパラメータの使用を推奨します。

Connections 型の使用

場合によっては、シグナルを発行するオブジェクトの外部からそのシグナルにアクセスしたいことがあります。このような目的のために、QtQuick モジュールでは、任意のオブジェクトのシグナルに接続するためのConnections 型を提供しています。Connections オブジェクトは、指定されたtarget からのあらゆるシグナルを受信することができます。

たとえば、前述の例におけるonClicked ハンドラは、onClicked ハンドラを、target がbutton に設定されたConnections オブジェクト内に配置することで、代わりにルート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 はアタッチされたシグナルハンドラです。これは、作成プロセスが完了した際にJavaScriptコードを実行するためによく使用されます。以下に例を示します。

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 ` シグナルを 3 つのメソッドに接続しています:

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 メソッドを使用すると、1つのシグナルを複数のメソッドで受信することが可能になります。これは、シグナルハンドラでは一意の名前を付ける必要があるため、実現できません。また、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 を保持しているアイテムが破棄されて初めて、接続も破棄されます。接続が残り続けるのを防ぐために、矩形が破棄される際に、明示的に接続を解除することができます。

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