QML имеет механизм сигналов и обработчиков, аналогичный сигналам и слотам. Типы QML также могут определять сигналы, которые еще называются событиями. Для обработки события
для сигнала определяется обработчик в виде свойства. Обработчик определяет действия, выполняемые при генерации сигнала. Причем сигнал и свойство-обработчик определяются в одном и том же классе.
сигналу осуществуляется через специальное свойство. Обычно между наименованиями сигналов и свойств-обработчиков существует связь: свойство называется по имени сигнала + приставка on
("clicked" - "onClicked").
Например, простеший код приложения на QML:
import QtQuick import QtQuick.Controls Window { width: 250 height: 200 visible: true title: "METANIT.COM" Column{ padding: 5 Button{ text: "Click Me" onClicked: { header.text = "Button clicked!" } } Text { id: header font.pixelSize: 18 } } }
Для кнопок определен сигнал clicked, который генерируется при нажатии на кнопку. Чтобы установить обработчик этого сигнала, у типа Button определено свойство onClicked. В данном случае обработчик представляет блок кода, где устанавливается текст элемента header. То есть по нажатию на кнопку генерируется сигнал clicked, обработчик onClicked получит этот сигнал и будет выполняться:
Действия обработчика события можно вынести в отдельную функцию JavaScript:
import QtQuick import QtQuick.Controls Window { width: 250 height: 200 visible: true title: "METANIT.COM" function setText(){ header.text = "Signal clicked" } Column{ padding: 5 Button{ text: "Click Me" onClicked: setText() } Text { id: header font.pixelSize: 18 } } }
В данном случае в качестве обработчика применяется функция setText.
При необходимости мы можем сами определять свои сигналы в элементах QML. Для добавления сигнала внутри элемента QML применяется ключевое слово signal:
signal имя_сигнала[([параметр_1, параметр_2, ... параметр_N)]
После слова signal
идет имя сигнала, затем в скобках перечисление параметров через запятую. Для каждого параметра указывается тип и имя. Если сигнал не принимает параметров,
то указываются пустые скобки. Например:
import QtQuick import QtQuick.Controls Window { width: 250 height: 200 visible: true title: "METANIT.COM" Rectangle { id: rect signal sendMessage() // определяем сигнал anchors.fill: parent Column{ anchors.fill: parent Button { id:sendButton text: "Send" onClicked: rect.sendMessage() } Text{ id: content } } onSendMessage: { // определяем обработчик сигнала sendMessage() content.text += "SendMessage Signal Received\n" } } }
Здесь для элемента Rectangle определен сигнал sendMessage
signal sendMessage()
Этот сигнал не имеет никаких параметров. Для обработки этого сигнала определен обработчик onSendMessage:
onSendMessage: { // определяем обработчик сигнала sendMessage() content.text += "SendMessage Signal Received\n" }
В этом обработчике просто изменяем текст элемента content. Обратите внимание на соответствие по имени между сигналом и обработчиком.
Теперь нам надо сгенерировать сигнал. Для этого у элемента Button определен следующий обработчик onClicked:
onClicked: rect.sendMessage()
То есть по нажатию на кнопку генерируется сигнал sendMessage, который затем обрабатывается обработчиком onSendMessage.
Если сигнал должен принимать какие-то параметры, то для его обработки можно определить функцию JavaScript, которая будет принимать соответствующий параметр:
import QtQuick import QtQuick.Controls Window { width: 250 height: 200 visible: true title: "METANIT.COM" function printMessage(message){ content.text += message + "\n" } Rectangle { id: rect signal sendMessage(string message) // определяем сигнал anchors.fill: parent Column{ anchors.fill: parent Button { id:sendButton text: "Send" onClicked: rect.sendMessage("Hello World") } Text{ id: content } } Component.onCompleted: { rect.sendMessage.connect(printMessage) } } }
Здесь сигнал sendMessage принимает один параметр - message, который представляет строку - отправляемое сообщение.
signal sendMessage(string message)
Для обработки сигнала определяем функцию printMessage, которая по сигнатуре соответствует сигналу - принимает один параметр и которая выводит полученное через параметр сообщение в текстовое поле.
function printMessage(message){ content.text += message + "\n" }
Далее чтобы связать функцию с сигналом, у сигнала вызывается функция connect, в которую передается имя функции:
Component.onCompleted: { rect.sendMessage.connect(printMessage) }
В зависимости от конкретного приложения место установки связи между функцией и сигналом может отличаться. В данном случае это производится в функции Component.onCompleted, которая вызывается при завершении инициализации компонентам.
Сигнал по прежнему генерируется в обработчике onClicked кнопки
onClicked: rect.sendMessage("Hello World")
только теперь в сигнал передается строка, которую получит функция printMessage через параметр message:
Подобным образом мы можем связать один сигнал с другим, чтобы при вызове одного сигнала автоматически генерировался другой. Например:
import QtQuick import QtQuick.Controls Window { width: 250 height: 200 visible: true title: "METANIT.COM" function printMessage(){ // обработчик сигнала content.text += "Hello World\n" } Rectangle { id: rect signal sendMessage() // определяем сигнал anchors.fill: parent Column{ anchors.fill: parent Button { id: sendButton text: "Send" } Text{ id: content } } Component.onCompleted: { rect.sendMessage.connect(printMessage) sendButton.clicked.connect(sendMessage) } } }
Здесь при возникновении сигнала clicked кнопки (по нажатию на кнопку) генерируется сигнал sendMessage
sendButton.clicked.connect(sendMessage)
А при генерации сигнала sendMessage вызывается функция printMessage.
rect.sendMessage.connect(printMessage)
Стоит отметить, что в данном случае сигнатура обоих сигналов - clicked и sendMessage совпадает.