Как связать необязательное свойство в QML?

Я разрабатываю собственный стиль QtQuick (согласно этой документации), и столкнулся с проблемой.

Реализация шаблона My Button предоставляет дополнительное свойство пользователя.

MyCustomStyle/Button.qml

import QtQuick
import QtQuick.Controls
import QtQuick.Templates as T

T.Button {
    id: control

    enum ButtonVariations {
        Giant,
        Regular,
        Small
    }

    property int variation : Button.ButtonVariations.Regular

    //...
}

Проблема в том, что когда я использую Button в своем приложении, оно загружает либо это определение шаблона кнопки, либо другое, в зависимости от стиля, выбранного для приложения. Это приводит к ошибке в qml

MyApp/SomePage.qml

    ComboBox {
        id: comboBox
        width: 140
        height: 25

        model: ["Giant", "Regular", "Small"]
    }

    Button {
        Layout.alignment: Qt.AlignRight | Qt.AlignTop
        text: "Normal"
        implicitWidth: 100

        variation : comboBox.currentIndex    //error : Invalid property name "variation" (M16)
    }

Когда я запускаю приложение, оно работает отлично, и кнопка реагирует в соответствии со свойством. Но из-за этой ошибки Qt Design Studio не может проанализировать файл и адаптировать представления.


Вопрос: Можно ли назначить это свойство как «необязательное» в QML?


Я уже пробовал это, но безуспешно:

1 - Проверить наличие недвижимости (согласно этой теме)

    variation ? variation : comboBox.currentIndex //Do not works

-> этот синтаксис, похоже, не существует

2. Повторно объявить свойство в экземпляре (чтобы оно могло переопределить или сначала объявить свойство).

Button {
    id: myButton

    property int variation : comboBox.currentIndex //Do not works
}

-> Эта компиляция не генерирует ошибку, но это похоже на то, что свойство внутри T.Button больше не привязано. Ничего не реагирует

РЕДАКТИРОВАТЬ : 3. Попробуйте использовать простой тип привязки, как показано ниже (спасибо комментарию smr)

Binding {
    variation: comboBox.currentIndex
}

-> Генерировать ошибку во время выполнения. Компонент не может быть загружен

Как насчет использования компонента Binding?

smr 09.07.2024 18:00

Спасибо, это то, что я искал! Мне удалось заставить его работать с помощью следующего кода: Binding { when: button2.variation !== "undefined"; button2.variation: comboBox.currentIndex}. Я пытался написать это без идентификатора или, по крайней мере, используя parent, если Binding является дочерним элементом кнопки, но безуспешно. Могу ли я позволить вам использовать этот фрагмент кода в качестве ответа, чтобы я мог его принять?

Lucas Terrier 10.07.2024 09:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
87
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы могли бы что-то вроде этого. Имейте свойство, которое проверяет, определен ли variation, и если это так, назначьте ему привязку в обработчике Component.onCompleted.

Button {
    id: button
    Layout.alignment: Qt.AlignRight | Qt.AlignTop
    text: "Normal"
    implicitWidth: 100

    property bool __variationAvailable: button.variation !== undefined

    Component.onCompleted: {
        if (button.__variationAvailable)
            button.variation = Qt.binding(function() { return comboBox.currentIndex })
    }
}

Большое спасибо, это работает (по крайней мере, если я не использую файл .ui.qml, который не поддерживает функции js). Меня не полностью устраивает этот метод, поскольку каждый раз, когда пользователь помещает кнопку в свое приложение, приходится добавлять много кода. Я оставлю тему нерешенной на мгновение, чтобы посмотреть, есть ли у кого-нибудь более компактный и удобный трюк!

Lucas Terrier 09.07.2024 11:47

Я только что заметил, что вы использовали "undefined" в качестве строки; разве это не должно быть просто undefined?

smr 11.07.2024 21:20

Да вы правы. Спасибо, я обновил свой ответ.

iam_peter 12.07.2024 13:23
Ответ принят как подходящий

В настоящее время я не могу воспроизвести точное состояние, поскольку проблема возникает в Qt Design Studio. Я попробовал удалить определенную переменную (закомментировав ее), чтобы она заработала.

Тем временем @iam_peter предложил метод инициализации свойства внутри Component.onCompleted.
Кроме того, существует альтернативный подход с использованием Binding; когда вам нужно инициализировать компонент в отложенном режиме или при выполнении определенного условия.

Начиная с Qt 6.*, существует три способа использования Binding, но в двух из этих методов переменная должна существовать во время синтаксического анализа, а один проверяется во время выполнения.

В настоящее время я не уверен, как воспроизвести условие, при котором компонент имеет свойство во время анализа, но не во время выполнения.

* Исходя из этого, я считаю, что если Binding { when: button.variation !== undefined; button.variation: comboBox.currentIndex } работает, то Binding { button.variation: comboBox.currentIndex } тоже должно работать.

Ниже приведен код, который я пробовал:

component Button: T.Button {
    // property int variation: 0
    text: "Text " + (this.variation ?? "")
}

Row {   
    Button { 
        // Run-time checking, no Error
        id: button1
        Binding {
            when: Object(button1).hasOwnProperty('variation')
            target: button1; property: 'variation'; value: 1
        }
    }

    Button { 
        // Parse-time checking
        // Error, if `variation` is not defined while parsing the file.
        id: button2
        Binding on variation {
            value: 2
            when: Object(button2).hasOwnProperty('variation')
        }
    }

    Button { 
        // Parse-time checking
        // Error, if `variation` is not defined while parsing the file.
        id: button3
        Binding {
            target: button3; property: 'variation'; value: 3
            when: Object(button3).hasOwnProperty('variation')
        }
    }
}

Ты прав ! Binding { button.variation: comboBox.currentIndex } достаточно для синтаксического анализа, но генерирует ошибку во время выполнения (если вариация не определена). То же самое, когда я добавляю when: button.variation !== "undefined". Я попробовал сочетание вашего первого примера и моего: Binding {when: Object(button).hasOwnProperty('variation'); button.variation: comboBox.currentIndex }, но это тоже не работает во время выполнения. Ваш первый пример (button1) и решения @iam_peter работают оба. Я предпочитаю ваш из-за его читабельности. Спасибо за вашу помощь.

Lucas Terrier 11.07.2024 10:22

Обновлено: решение @iam_peter генерирует предупреждение во время выполнения: Предупреждение: file:///C:/Users/[...]/PushButtonPage.qml:57: Ошибка: невозможно назначить несуществующему свойству «вариация». Но оно по-прежнему позволяет приложению отображать компонент.

Lucas Terrier 11.07.2024 10:35

@LucasTerrier, что-то не так с кодом @iam_peter, что я только что заметил: AFAIK, undefined === "undefined" не равны. "undefined" — это строка, которая не должна быть равна undefined, который является примитивом JavaScript. Возможно, предупреждение исчезнет, ​​если вы используете undefined или Object(...).hasOwnProperty('variation'), которые лучше всего подходят для проверки существования свойства или его отсутствия.

smr 11.07.2024 21:16

Вы можете смоделировать привязку, клонировав свойство, а затем отреагировав на событие изменения свойства клона:

QtObject {
    property int v: comboBox.currentIndex
    onVChanged: if ("variation" in button) button.variation = v
}

Вы можете Попробовать онлайн!

с тем же подходом, я полагаю, я мог бы сделать это прямо в описании комбобокса: ComboBox { onCurrentIndexChanged: if ("variation" in button) button.variation = currentIndex }

Lucas Terrier 11.07.2024 17:55

Да, но вышеизложенное было написано таким образом, что при желании вы могли бы скомпоновать его в макет компонента, подобного привязке.

Stephen Quan 11.07.2024 19:58

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