QML - Как создать свойства компонентов QML, чтобы их можно было устанавливать из JavaScript?
Я пытаюсь создать компонент с определенными свойствами, которые я установил. Расположение и имя звуков задаются функцией C++, которая фактически работает, потому что console.log() показывает так:
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Amsterdam.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Blip.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Mallet.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Positive.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Rhodes.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Slick.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Soft delay.ogg sound
qml: Adding /home/vitimiti/.local/share/com.ubuntu.developer.vitimiti.irc-app/sounds/Xylo.ogg sound
Проблема в том, что при попытке установить свойства для ListElement, он просто оставит ListView пустым, как если бы он не распознал свойства.
Вот мои функции JavasCript в файле:
var component;
var element;
function createElement(soundName, soundLocation) {
component = Qt.createComponent("../AlertsSettingsSounds.qml")
if (component.status === Component.Ready)
finishCreation(soundName, soundLocation)
else
component.statusChanged.connect(finishCreation)
}
function finishCreation(soundName, soundLocation) {
if (component.status === Component.Ready) {
element = component.createObject(alertsModel, {
"Name": soundName,
"Sound": soundLocation});
if (element === null)
// Error Handling
console.log("Error creating object");
} else if (component.status === Component.Error)
// Error Handling
console.log("Error loading component: ", component.errorString());
}
Вот страница, которая используется:
import QtQuick 2.0
import Ubuntu.Components 1.1
import Ubuntu.Components.ListItems 1.0 as ListItem
import Irc_App 0.1
import "../components"
// Mobile (small screen) layout
Page {
id: alertsSettingsPage
objectName: "alertSettingsPage"
title: i18n.tr("Alerts")
Row {
id: muteRow
objectName: "muteRow"
anchors {
left: parent.left
leftMargin: root.margins
top: parent.top
topMargin: root.margins
right: parent.right
rightMargin: root.margins
}
spacing: root.spacing
Label {
id: muteLabel
objectName: "muteLabel"
width: parent.width - muteCheckBox.width
text: i18n.tr("<b>Mute</b> notifications")
}
CheckBox {
id: muteCheckBox
objectName: "muteCheckBox"
checked: false
onCheckedChanged: {
if (checked === true)
soundsComponent.volume = 0
else
soundsComponent.volume = 1
}
}
}
Flickable {
id: soundsFlickable
objectName: "soundsFlickable"
anchors {
left: parent.left
leftMargin: root.margins
top: muteRow.bottom
right: parent.right
rightMargin: root.margins
bottom: parent.bottom
bottomMargin: root.margins
}
clip: true
contentHeight: soundsColumn.height
contentWidth: parent.width
flickableDirection: Flickable.VerticalFlick
Column {
id: soundsColumn
objectName: "soundsColumn"
width: parent.width
spacing: root.spacing
// One item selector for each notification there is.
ListItem.ItemSelector {
id: highlightAlertSelector
objectName: "highlightAlertSelector"
text: i18n.tr("Highlight Alert")
expanded: false
model: alertsSettingsComponent
onSelectedChanged: {
console.log(selectedIndex + " selected")
}
delegate: OptionSelectorDelegate {
text: name
onClicked: {
// This functions are local and to make the alerts
// sound as they ought to. They will write the
// configuration to the xml file and, from there,
// the program will start with those options set
// and the events will read such file to set again the
// Audio component and make it work for just the event.
if (name === "Muted") {
console.log("Muting sound for highlights")
soundsComponent.source = ""
} else {
console.log("Starting sound " + name +
" for highlights")
console.log("Setting sound option " + name +
" for highlights")
soundsComponent.source =
soundsHandler.soundsLocation + "/" + name
soundsComponent.play()
}
}
}
Component.onCompleted: {
// Set the muteCheckBox as it is in the configuration
// Set the sounds as they are in the configuration file
}
}
ListItem.ItemSelector {
id: kickedAlertsSelector
objectName: "kickedAlertsSelector"
text: i18n.tr("Kicked Alert")
expanded: false
model: alertsSettingsComponent
onSelectedChanged: {
console.log(selectedIndex + " selected")
}
delegate: OptionSelectorDelegate {
text: name
onClicked: {
if (name === "Muted") {
console.log("Muting sound for kicked event")
soundsComponent.source = ""
} else {
console.log("Starting sound " + name +
" for kicked event")
console.log("Setting sound option " + name +
" for kicked event")
soundsComponent.source =
soundsHandler.soundsLocation + "/" + name
soundsComponent.play()
}
}
}
Component.onCompleted: {
// Set the muteCheckBox as it is in the configuration
// Set the sounds as they are in the configuration file
}
}
}
}
AlertsSettingsComponent {
id: alertsSettingsComponent
objectName: "alertsSettings_component"
}
SoundsComponent {
id: soundsComponent
objectName: "sounds_component"
}
}
Вот компонент, используемый для селекторов списка, который должен работать с функциями JS:
import QtQuick 2.0
import Irc_App 0.1
import "../js/AlertsSettingsFunctions.js" as AlertsSettingsFunction
// Using the sounds from the folder
ListModel{
id: alertsModel
objectName: "alertsModel"
Component.onCompleted: {
for (var i = 0; i < soundsHandler.sounds.length; i++) {
AlertsSettingsFunction.createElement(soundsHandler.sounds[i],
soundsHandler.soundsLocation + "/"
+ soundsHandler.sounds[i])
console.log("Adding", soundsHandler.soundsLocation + "/"
+ soundsHandler.sounds[i], "sound")
}
}
}
А вот ListElement, который определяет свойства Name и Sound, используемые в файле JS:
ListElement {
id: soundsListElement
objectName: "soundsListElement"
property string Name
property string Sound
name: Name
sound: Sound
}
Поэтому моя проблема в том, что JS, похоже, не понимает, что Name и Sound являются строковыми свойствами для ListElement, и что он должен устанавливать их с заданными soundName и soundLocation в функции, присутствующей в компоненте ListView, чтобы показать его в страница. Вместо этого селекторы элементов выглядят совершенно пустыми.
Я не могу понять, что я делаю неправильно, любая помощь будет высоко ценится.
2 ответа
Я думаю, что вы следовали приведенному здесь примеру, но в вашем случае вы пытаетесь connect
к component.statusChanged
сигнал и в то же время ожидая увидеть finishCreation
обработчик для принятия аргументов. Это невозможно.
После подключения к сигналу, если испускается, он будет вызывать finishCreation
без аргументов. Я думаю, это объясняет, почему вы видите пустые предметы.
Чтобы убедиться, что при вызове обработчика сигнала у вас есть доступ к обоим soundName
а также soundLocation
Я бы сделал их глобальными, как component
а также element
в файле js (не проверено):
var component;
var element;
var _soundName;
var _soundLocation;
function createElement(soundName, soundLocation) {
component = Qt.createComponent("../AlertsSettingsSounds.qml")
_soundName = soundName
_soundLocation = soundLocation
if (component.status === Component.Ready)
finishCreation()
else
component.statusChanged.connect(finishCreation)
}
function finishCreation() {
if (component.status === Component.Ready) {
element = component.createObject(alertsModel, {
"Name": _soundName,
"Sound": _soundLocation});
if (element === null)
// Error Handling
console.log("Error creating object");
} else if (component.status === Component.Error)
// Error Handling
console.log("Error loading component: ", component.errorString());
}
Починил это. Похоже, что я не должен создавать компонент ListElement. Вместо этого ListModel должен выглядеть так:
import QtQuick 2.0
import Irc_App 0.1
import "../js/AlertsSettingsFunctions.js" as AlertsSettingsFunction
// Using the sounds from the folder
ListModel {
id: alertsModel
objectName: "alertsModel"
Component.onCompleted: {
for (var i = 0; i < soundsHandler.sounds.length; i++)
AlertsSettingsFunction.makeList(alertsModel,
soundsHandler.sounds[i],
soundsHandler.soundsLocation + "/"
+ soundsHandler.sounds[i])
}
}
И файл JavaScript должен выглядеть так:
function makeList(id, soundName, soundLocation) {
id.append({"name" : soundName, "sound" : soundLocation})
}
Это должно быть добавлено в список.