Qt 5.12 QML,在javascript中通过var选择QML对象
Posted
技术标签:
【中文标题】Qt 5.12 QML,在javascript中通过var选择QML对象【英文标题】:Qt 5.12 QML, select QML object by var in javascript 【发布时间】:2019-02-20 10:17:41 【问题描述】:我想知道是否有一种方法可以通过 var 在 javascript 函数中选择具有特定 id
或 objectName
的已创建 QML 对象(var 是对应于 QML 对象 ID 或名称的字符串参数)。
例如:
// main.qml
ApplicationWindow
RoundButton
id: btn1
RoundButton
id: btn2
RoundButton
id: btn3
// ...
function foo(qmlObjectNameOrId)
qmlObjectNameOrId.text = "qmlObjectNameOrId is already in the document and has a property text that I want to set";
// Qt.findQmlObject(id) would have been great !
Qt.createQmlObject
不是解决方案,因为我想使用已经创建的 QML 对象。
在 C++ 中,实现这一点的方法是使用QQmlApplicationEngine
对象,然后使用 QML 根对象通过 QML 对象名称执行选择:
int main(int argc, char *argv[])
QQmlApplicationEngine engine;
QString objectName = someFunction();
QObject* qmlObject = engine.rootObjects()[0]->findChild<QObject*>(objectName);
// use your qmlObject ...
javascript 函数将在 C++ 中调用QMetaObject::invokeMethod(appWindow, "foo", Q_ARG(QVariant, "bar"));
谢谢
[编辑 1] 尝试 Roman Sverdlov 回答:
ApplicationWindow
id: appWindow
objectName: "appWindow"
// ...
Pane
id: buttonsContainer
objectName: "buttonsContainer"
property string disposition : "circular_1"
property int btnWidth : 130
property int btnHeight : 130
property int btnIconWidth : 40
property int btnIconHeight : 40
property int btnRadius : btnWidth / 2
property int btnMargin : 40
property int btnZ : 4
property int btnPressedBackground: Material.Purple
anchors.right: parent.right
anchors.left: parent.left
anchors.top: instructionContainer.bottom
anchors.bottom: parent.bottom
visible: false
Image
id: background
height: buttonsContainer.height - 100
x: (buttonsContainer.width - width) / 2
y: (buttonsContainer.height - height) / 2
source: "qrc:///images/circle_background.png"
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
fillMode: Image.PreserveAspectFit
Rectangle
id: topLeft
color: Material.color(Material.Red)
x: 0
z: 1
height: parent.height / 2
width: parent.width / 2
Rectangle
id: topRight
color: Material.color(Material.Green)
x: parent.width / 2
z: 1
anchors.top: parent.top
height: parent.height / 2
width: parent.width / 2
Label
id: backgroundTextTop
text: "MONTER"
font.pixelSize: 40
x: (parent.width - width) / 2
y: (parent.height - height) / 2 - 50
z: 2
Rectangle
id: bottomLeft
color: Material.color(Material.Green)
x: 0
z: 1
anchors.bottom: parent.bottom
height: parent.height / 2
width: parent.width / 2
Rectangle
id: bottomRight
color: Material.color(Material.Red)
x: parent.width / 2
z: 1
anchors.bottom: parent.bottom
height: parent.height / 2
width: parent.width / 2
Label
id: backgroundTextBottom
text: "PLONGER"
font.pixelSize: 40
x: (parent.width - width) / 2
y: (parent.height - height) / 2 + 200
z: 2
RoundButton
id: btnB1MB
objectName: "btnB1MB"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B1MB);
onReleased:
TestsRun.releaseButton(Buttons.B1MB);
RoundButton
id: btnB4MT
objectName: "btnB4MT"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B4MT);
onReleased:
TestsRun.releaseButton(Buttons.B4MT);
RoundButton
id: btnB3MB
objectName: "btnB3MB"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B3MB);
onReleased:
TestsRun.releaseButton(Buttons.B3MB);
RoundButton
id: btnB4PB
objectName: "btnB4PB"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B4PB);
onReleased:
TestsRun.releaseButton(Buttons.B4PB);
RoundButton
id: btnB2MT
objectName: "btnB2MT"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B2MT);
onReleased:
TestsRun.releaseButton(Buttons.B2MT);
RoundButton
id: btnB1PT
objectName: "btnB1PT"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B1PT);
onReleased:
TestsRun.releaseButton(Buttons.B1PT);
RoundButton
id: btnB2PB
objectName: "btnB2PB"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B2PB);
onReleased:
TestsRun.releaseButton(Buttons.B2PB);
RoundButton
id: btnB3PT
objectName: "btnB3PT"
width: buttonsContainer.btnWidth
height: buttonsContainer.btnHeight
radius: buttonsContainer.btnRadius
z: buttonsContainer.btnZ
display: AbstractButton.TextUnderIcon
onPressed:
TestsRun.pressButton(Buttons.B3PT);
onReleased:
TestsRun.releaseButton(Buttons.B3PT);
Component.onCompleted:
setButtonsPosition(buttonsContainer.disposition);
/**
* Get a QML element by objectName property
*
* @todo Not working
*
* @param String objectName - The QML object name to get
*/
function getQmlObjectByName(objectName)
console.log("buttonsContainer.children.length", buttonsContainer.children.length);
return getQmlObjectByNameRecursive(buttonsContainer, objectName)
/**
* Get a QML element by objectName property
*
* @todo Not working
*
* @param Object object - The QML object to find the QML element in
* @param String objectName - The QML object name to get
*/
function getQmlObjectByNameRecursive(object, objectName)
for (let child in object.children)
console.log(object.children[child].objectName);
if (object.children[child].objectName === objectName)
console.log('found');
return object.children[child];
if (typeof object.children[child].children !== 'undefined')
console.log('children', object.children[child]);
return getQmlObjectByNameRecursive(object.children[child], objectName);
输出
qml: buttonsContainer.children.length 2
qml: Pane
qml: children QQuickContentItem(0x55c4e2a145d0, "Pane")
qml:
qml: children QQuickImage(0x55c4e2a1cc80)
qml: undefined
【问题讨论】:
嗨,我不能在 js 中使用直接的 QML id,因为 id 是使用 C++ 中调用的 js 函数给出的参数构建的。 您好,很抱歉误解了您的问题。我已经清理了你的问题。 (也感谢您添加更多上下文。)此外,我发现了这些相关帖子:Find a QML Object by ID。 Find a QML Object by Object Name. 谢谢,我不认为有解决这个问题的办法,它被认为是 Qt 中的“反模式”。我只是想通过一些元编程使我的 QML 更加紧凑和简约,但 Qt 似乎不允许这样做 【参考方案1】:如果您为对象设置了objectName
属性,那么您可以使用类似
ApplicationWindow
id: appWin
RoundButton
id: btn1
objectName: "btn1"
RoundButton
id: btn2
objectName: "btn2"
// ...
function foo(objectName)
for(var child in appWin.children)
if(appWin.children[child].objectName === objectName)
appWin.children[child].text = "qmlObjectNameOrId is already in the document and has a property text that I want to set";
break
当然它看起来很丑,但是如果你非常需要它......
【讨论】:
没那么难看,我不知道我可以像 DOM 一样使用 javascript 在 html 中遍历 QML。如果可行,我将对此进行测试并更新问题。appWin
没有属性children
, console.log(appWin.children) === undefined
那么我认为只有Item可以有孩子。所以试着把你的按钮放在某个 item 里面,例如列布局和重复
似乎容器的 children 属性中没有所有子项...我将使用问题中的代码向您发布尝试解决方案【参考方案2】:
通过遍历 QML 容器解决了问题,我想通过 objectName 属性在其中找到 QML 对象。
感谢 Roman Sverdlov,“DOM 遍历”是使用 contentChildren
属性而不是 children
属性完成的。
/**
* Get a QML element by objectName property in buttonsContainer container
*
* @param String objectName - The QML object name to get
*/
function getQmlObjectByName(objectName)
for (let child in buttonsContainer.contentChildren)
if (buttonsContainer.contentChildren[child].objectName === objectName)
return buttonsContainer.contentChildren[child];
【讨论】:
哇,这个框架设计太糟糕了……以上是关于Qt 5.12 QML,在javascript中通过var选择QML对象的主要内容,如果未能解决你的问题,请参考以下文章