当父 属性 在 QML 中更改时更改子 属性
Change children property when parent property changes in QML
我有 3 个文件。 main.qml、Guide.qml 和 ChannelViewer.qml
我的主要 class 包含 2 个组件和一个加载程序,这里是代码
main.qml
import QtQuick 2.0
Rectangle {
id:loader
color: "black"
property string channelName
property string channelURL
Component{
id:tv
ChannelViewer{}
}
Component{
id:guide
Guide{}
}
Loader
{
id: pageLoader
anchors.fill:parent
focus:true
sourceComponent: tv
}
Connections{
target:pageLoader.item
onChangeChannel:{
channelName=name
channelURL=url
}
}
Keys.onPressed: {
event.accepted = true;
if (event.key === Qt.Key_I) {
pageLoader.sourceComponent = tv;
}
else if(event.key === Qt.Key_G) {
pageLoader.sourceComponent = guide;
}
}
}
现在,如果我按 "G",我将毫无问题地移至指南文件 在我的指南页面中,我可以向 main.qml 发送信号并更新名称 属性在主要。
Guide.qml
Item {
signal changeChannel(string url, string name)
Loader {
id: pageLoader
anchors.fill:parent
sourceComponent: guide
focus:true
}
Keys.onPressed: {
if(event.key === Qt.Key_Escape) {
pageLoader.source = "main.qml";
}
event.accepted = true;
}
Component {
id:guide
Rectangle {
color:"lightblue"
Keys.onPressed: {
if(event.key === Qt.Key_Return) {
changeChannel(menuContent.currentItem.ch_url, menuContent.currentItem.ch_name)
pageLoader.source = "main.qml";
}
event.accepted = true;
}
}
}
}
但是现在当我在 Guide.qml 中按 "Return" 时,我将被带回 main.qml(Channelname 和 ChannelURL 将成功更新),而我的 main.qml现在将带我到 ChannelViewer.qml,问题是我的 ChannelViewer.qml 将不会收到更新的 channelName 和 channelURL。而且我不确定我做错了什么。
ChannelViewer.qml
import QtQuick 2.0
import VLCQt 1.0
Rectangle {
id:root
width: 640
height: 480
color: "black"
focus:true
Loader
{
id: pageLoader
anchors.fill:parent
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(channelURL)
}
}
Keys.onPressed: {
if (event.key === Qt.Key_I) {
event.accepted = true;
if(channelInfo.visible === true) {
channelInfo.visible=false;
}
else {
channelInfo.visible=true;
}
}
}
VlcVideoPlayer {
id: vidwidget
anchors.fill: parent
url:channelURL
ChannelInfo{
id:channelInfo
anchors.bottom: parent.bottom
anchors.bottomMargin: ((parent.height*5)/100)
anchors.horizontalCenter: parent.horizontalCenter
width:parent.width - ((parent.width*10)/100)
height: (parent.height*20)/100
backgroundOpacity: 0.7
radius:10
channelNameProp: channelName
channelNumberProp: "1"
headerIcon: "imgs/television_32x32.png"
}
}
}
编辑:
我的 ChannelInfo.qml
的代码
import QtQuick 2.0
Item {
id:channelinfo
property color backgroundColor: "blue"
property color headerBackgroundColor: "lightblue"
property color headerNameColor: "black"
property color borderColor: "black"
property color channelNameColor: "white"
property color channelNumberColor: "white"
property real borderWidth:0
property real radius:0
property real backgroundOpacity: 0.5
property string menuTitle : "TV Channels"
property string channelNameProp
property string channelNumberProp
property url headerIcon: "imgs/television.png"
visible:false
Rectangle{
id:root
width:channelinfo.width
height:channelinfo.height
color:channelinfo.backgroundColor
border.color:channelinfo.borderColor
border.width: channelinfo.borderWidth
radius:channelinfo.radius
opacity:channelinfo.backgroundOpacity
visible: parent.visible
Rectangle{
id:header
anchors.top:parent.top
// width:(parent.width*40)/100
width: parent.width
height: (parent.height*30)/100
radius: channelinfo.radius
color:channelinfo.headerBackgroundColor
Image{
source:channelinfo.headerIcon
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -4
}
Text{
id:headerTitle
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
width:parent.width
wrapMode: Text.WordWrap
color:channelinfo.headerNameColor
text:menuTitle
font.pixelSize: Math.round(parent.height/2)
font.bold: true
}
}
Rectangle{
id:content
anchors.bottom: parent.bottom
width:parent.width
height:parent.height-header.height
color:"transparent"
Text{
id:channelName
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
color:channelinfo.channelNameColor
text:channelNameProp
font.pixelSize: Math.round(parent.height/4)
font.bold: true
}
Text{
id:channelNumber
anchors.right: parent.right
anchors.rightMargin: 20
anchors.verticalCenter: parent.verticalCenter
color:channelinfo.channelNumberColor
text:channelNumberProp
font.pixelSize: Math.round(parent.height/4)
font.bold: true
}
}
}
}
Github VLCPlayer 页面
https://github.com/vlc-qt/
作为属性
property string channelName
property string channelURL
有更改信号,因此支持 属性 绑定,我认为最简单的方法是将第 9-17 行更改为
Component{
id:tv
ChannelViewer {
id: channelViewer
channelName: loader.channelName
channelURL: loader.channelURL
}
}
Component{
id:guide
Guide {
id: guide
channelName: loader.channelName
channelURL: loader.channelURL
}
}
如果 Guide 更改了频道名称,您需要确保在 loader
中进行更改。您可以使用 Binding
-objects 使绑定在分配 (=
) 中存活。
如此有效,您需要在 Guide.qml
和 ChannelViewer.qml
的根节点中创建属性 channelName
和 channelURL
。然后,在这些文件中的每个地方,您使用完全限定的标识符:id.propertyName
,例如 ChannelInfo.qml
中的 channelinfo.channelName
,ChannelViewer.qml
中的 root.channelName
以及您需要在 Guid.qml
-> root.channelName
.
中设置的 ID(例如再次 root)
- Usage of fully qualified identifiers for bindings, which always include the
idOfTheObject.propertyName
helps to avoid problems. In some cases (positioning, anchoring, sizing) parent
is ok, but you might not know what exactly is the parent)
- Dynamic scoping is a blessing if you know exactly how and where the code will be used, e.g. if it is essentially a partial definition of a larger object, and will never be used in another context. But here you need to know that if the parent file changes the internal api, you need to adapt the child file accordingly. If you think, the file might be for reuse, avoid dynamic scoping and only reference what is defined inside the file.
如果你要有这样一个固定的结构,为什么还要费心信号,你可以简单地:
Keys.onPressed: {
if(event.key === Qt.Key_Return) {
channelName = menuContent.currentItem.ch_name
channelURL = menuContent.currentItem.ch_url
pageLoader.source = "main.qml";
}
event.accepted = true;
}
然后去掉不需要的部分:
Connections{
target:pageLoader.item
onChangeChannel:{
channelName=name
channelURL=url
}
}
由于 channelName
和 channelURL
是在 qml 文件的根对象中声明的,因此由于动态作用域,它们应该可以从嵌套在树上更远的对象中访问。
所以在你发布相关代码后,你有一个:
Text{
id:channelName
在您的 ChannelInfo
对象中,它隐藏 channelName
属性,在 main.qml
中声明。养成一致命名约定的习惯是个好主意。例如,由于这是一个 id,我个人会使用 id: _cName
,这样可以最大限度地减少发生此类冲突的几率。
更新:
我能想到为什么它不起作用的唯一其他原因是您在某处通过执行 channelNameProp = something
.
之类的操作来破坏 channelNameProp: channelName
绑定
这里有一个简单的例子来说明动态作用域 是有效的(只要你不隐藏任何东西),即使在涉及动态更改加载器项目的情况下也是如此:
// main.qml
ApplicationWindow {
id: _cName
visible: true
width: 640
height: 480
property int value: 0
Loader {
id: loader
source: "Obj.qml"
}
}
// Rect.qml
Rectangle {
id: rectangle
width: 50; height: 100
color: "red"
Text {
anchors.centerIn: parent
text: value
}
MouseArea {
anchors.fill: parent
onClicked: {
loader.source = "Obj.qml"
}
}
}
// Obj.qml
Rectangle {
id: rectangle
width: 50; height: 100
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
value++
loader.source = "Rect.qml"
}
}
}
我有 3 个文件。 main.qml、Guide.qml 和 ChannelViewer.qml 我的主要 class 包含 2 个组件和一个加载程序,这里是代码
main.qml
import QtQuick 2.0
Rectangle {
id:loader
color: "black"
property string channelName
property string channelURL
Component{
id:tv
ChannelViewer{}
}
Component{
id:guide
Guide{}
}
Loader
{
id: pageLoader
anchors.fill:parent
focus:true
sourceComponent: tv
}
Connections{
target:pageLoader.item
onChangeChannel:{
channelName=name
channelURL=url
}
}
Keys.onPressed: {
event.accepted = true;
if (event.key === Qt.Key_I) {
pageLoader.sourceComponent = tv;
}
else if(event.key === Qt.Key_G) {
pageLoader.sourceComponent = guide;
}
}
}
现在,如果我按 "G",我将毫无问题地移至指南文件 在我的指南页面中,我可以向 main.qml 发送信号并更新名称 属性在主要。
Guide.qml
Item {
signal changeChannel(string url, string name)
Loader {
id: pageLoader
anchors.fill:parent
sourceComponent: guide
focus:true
}
Keys.onPressed: {
if(event.key === Qt.Key_Escape) {
pageLoader.source = "main.qml";
}
event.accepted = true;
}
Component {
id:guide
Rectangle {
color:"lightblue"
Keys.onPressed: {
if(event.key === Qt.Key_Return) {
changeChannel(menuContent.currentItem.ch_url, menuContent.currentItem.ch_name)
pageLoader.source = "main.qml";
}
event.accepted = true;
}
}
}
}
但是现在当我在 Guide.qml 中按 "Return" 时,我将被带回 main.qml(Channelname 和 ChannelURL 将成功更新),而我的 main.qml现在将带我到 ChannelViewer.qml,问题是我的 ChannelViewer.qml 将不会收到更新的 channelName 和 channelURL。而且我不确定我做错了什么。
ChannelViewer.qml
import QtQuick 2.0
import VLCQt 1.0
Rectangle {
id:root
width: 640
height: 480
color: "black"
focus:true
Loader
{
id: pageLoader
anchors.fill:parent
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(channelURL)
}
}
Keys.onPressed: {
if (event.key === Qt.Key_I) {
event.accepted = true;
if(channelInfo.visible === true) {
channelInfo.visible=false;
}
else {
channelInfo.visible=true;
}
}
}
VlcVideoPlayer {
id: vidwidget
anchors.fill: parent
url:channelURL
ChannelInfo{
id:channelInfo
anchors.bottom: parent.bottom
anchors.bottomMargin: ((parent.height*5)/100)
anchors.horizontalCenter: parent.horizontalCenter
width:parent.width - ((parent.width*10)/100)
height: (parent.height*20)/100
backgroundOpacity: 0.7
radius:10
channelNameProp: channelName
channelNumberProp: "1"
headerIcon: "imgs/television_32x32.png"
}
}
}
编辑: 我的 ChannelInfo.qml
的代码import QtQuick 2.0
Item {
id:channelinfo
property color backgroundColor: "blue"
property color headerBackgroundColor: "lightblue"
property color headerNameColor: "black"
property color borderColor: "black"
property color channelNameColor: "white"
property color channelNumberColor: "white"
property real borderWidth:0
property real radius:0
property real backgroundOpacity: 0.5
property string menuTitle : "TV Channels"
property string channelNameProp
property string channelNumberProp
property url headerIcon: "imgs/television.png"
visible:false
Rectangle{
id:root
width:channelinfo.width
height:channelinfo.height
color:channelinfo.backgroundColor
border.color:channelinfo.borderColor
border.width: channelinfo.borderWidth
radius:channelinfo.radius
opacity:channelinfo.backgroundOpacity
visible: parent.visible
Rectangle{
id:header
anchors.top:parent.top
// width:(parent.width*40)/100
width: parent.width
height: (parent.height*30)/100
radius: channelinfo.radius
color:channelinfo.headerBackgroundColor
Image{
source:channelinfo.headerIcon
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -4
}
Text{
id:headerTitle
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
width:parent.width
wrapMode: Text.WordWrap
color:channelinfo.headerNameColor
text:menuTitle
font.pixelSize: Math.round(parent.height/2)
font.bold: true
}
}
Rectangle{
id:content
anchors.bottom: parent.bottom
width:parent.width
height:parent.height-header.height
color:"transparent"
Text{
id:channelName
anchors.left: parent.left
anchors.leftMargin: 50
anchors.verticalCenter: parent.verticalCenter
color:channelinfo.channelNameColor
text:channelNameProp
font.pixelSize: Math.round(parent.height/4)
font.bold: true
}
Text{
id:channelNumber
anchors.right: parent.right
anchors.rightMargin: 20
anchors.verticalCenter: parent.verticalCenter
color:channelinfo.channelNumberColor
text:channelNumberProp
font.pixelSize: Math.round(parent.height/4)
font.bold: true
}
}
}
}
Github VLCPlayer 页面 https://github.com/vlc-qt/
作为属性
property string channelName
property string channelURL
有更改信号,因此支持 属性 绑定,我认为最简单的方法是将第 9-17 行更改为
Component{
id:tv
ChannelViewer {
id: channelViewer
channelName: loader.channelName
channelURL: loader.channelURL
}
}
Component{
id:guide
Guide {
id: guide
channelName: loader.channelName
channelURL: loader.channelURL
}
}
如果 Guide 更改了频道名称,您需要确保在 loader
中进行更改。您可以使用 Binding
-objects 使绑定在分配 (=
) 中存活。
如此有效,您需要在 Guide.qml
和 ChannelViewer.qml
的根节点中创建属性 channelName
和 channelURL
。然后,在这些文件中的每个地方,您使用完全限定的标识符:id.propertyName
,例如 ChannelInfo.qml
中的 channelinfo.channelName
,ChannelViewer.qml
中的 root.channelName
以及您需要在 Guid.qml
-> root.channelName
.
- Usage of fully qualified identifiers for bindings, which always include the
idOfTheObject.propertyName
helps to avoid problems. In some cases (positioning, anchoring, sizing)parent
is ok, but you might not know what exactly is the parent)- Dynamic scoping is a blessing if you know exactly how and where the code will be used, e.g. if it is essentially a partial definition of a larger object, and will never be used in another context. But here you need to know that if the parent file changes the internal api, you need to adapt the child file accordingly. If you think, the file might be for reuse, avoid dynamic scoping and only reference what is defined inside the file.
如果你要有这样一个固定的结构,为什么还要费心信号,你可以简单地:
Keys.onPressed: {
if(event.key === Qt.Key_Return) {
channelName = menuContent.currentItem.ch_name
channelURL = menuContent.currentItem.ch_url
pageLoader.source = "main.qml";
}
event.accepted = true;
}
然后去掉不需要的部分:
Connections{
target:pageLoader.item
onChangeChannel:{
channelName=name
channelURL=url
}
}
由于 channelName
和 channelURL
是在 qml 文件的根对象中声明的,因此由于动态作用域,它们应该可以从嵌套在树上更远的对象中访问。
所以在你发布相关代码后,你有一个:
Text{
id:channelName
在您的 ChannelInfo
对象中,它隐藏 channelName
属性,在 main.qml
中声明。养成一致命名约定的习惯是个好主意。例如,由于这是一个 id,我个人会使用 id: _cName
,这样可以最大限度地减少发生此类冲突的几率。
更新:
我能想到为什么它不起作用的唯一其他原因是您在某处通过执行 channelNameProp = something
.
channelNameProp: channelName
绑定
这里有一个简单的例子来说明动态作用域 是有效的(只要你不隐藏任何东西),即使在涉及动态更改加载器项目的情况下也是如此:
// main.qml
ApplicationWindow {
id: _cName
visible: true
width: 640
height: 480
property int value: 0
Loader {
id: loader
source: "Obj.qml"
}
}
// Rect.qml
Rectangle {
id: rectangle
width: 50; height: 100
color: "red"
Text {
anchors.centerIn: parent
text: value
}
MouseArea {
anchors.fill: parent
onClicked: {
loader.source = "Obj.qml"
}
}
}
// Obj.qml
Rectangle {
id: rectangle
width: 50; height: 100
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
value++
loader.source = "Rect.qml"
}
}
}