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





Вы могли бы что-то вроде этого. Имейте свойство, которое проверяет, определен ли 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). Меня не полностью устраивает этот метод, поскольку каждый раз, когда пользователь помещает кнопку в свое приложение, приходится добавлять много кода. Я оставлю тему нерешенной на мгновение, чтобы посмотреть, есть ли у кого-нибудь более компактный и удобный трюк!
Я только что заметил, что вы использовали "undefined" в качестве строки; разве это не должно быть просто undefined?
Да вы правы. Спасибо, я обновил свой ответ.
В настоящее время я не могу воспроизвести точное состояние, поскольку проблема возникает в 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 работают оба. Я предпочитаю ваш из-за его читабельности. Спасибо за вашу помощь.
Обновлено: решение @iam_peter генерирует предупреждение во время выполнения: Предупреждение: file:///C:/Users/[...]/PushButtonPage.qml:57: Ошибка: невозможно назначить несуществующему свойству «вариация». Но оно по-прежнему позволяет приложению отображать компонент.
@LucasTerrier, что-то не так с кодом @iam_peter, что я только что заметил: AFAIK, undefined === "undefined" не равны. "undefined" — это строка, которая не должна быть равна undefined, который является примитивом JavaScript. Возможно, предупреждение исчезнет, если вы используете undefined или Object(...).hasOwnProperty('variation'), которые лучше всего подходят для проверки существования свойства или его отсутствия.
Вы можете смоделировать привязку, клонировав свойство, а затем отреагировав на событие изменения свойства клона:
QtObject {
property int v: comboBox.currentIndex
onVChanged: if ("variation" in button) button.variation = v
}
Вы можете Попробовать онлайн!
с тем же подходом, я полагаю, я мог бы сделать это прямо в описании комбобокса: ComboBox { onCurrentIndexChanged: if ("variation" in button) button.variation = currentIndex }
Да, но вышеизложенное было написано таким образом, что при желании вы могли бы скомпоновать его в макет компонента, подобного привязке.
Как насчет использования компонента Binding?