Я разрабатываю собственный стиль 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?