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})
}

Это должно быть добавлено в список.

Другие вопросы по тегам