Tim*_*mmm 5 qt qml qt5 qtquick2 qtquickcontrols
在使用QtQuick控件的QtQuick 2中,您可以创建复杂的桌面应用程序.然而,在我看来,必须在应用程序开始时声明整个UI并立即创建所有UI.您仍然不想使用任何您不想使用的部分(例如文件 - >打开对话框),但它们是隐藏的,如下所示:
ApplicationWindow {
FileDialog {
id: fileOpenDialog
visible: false
// ...
}
FileDialog {
id: fileSaveDialog
visible: false
// ...
}
// And so on for every window in your app and every piece of UI.
Run Code Online (Sandbox Code Playgroud)
现在,对于简单的应用程序来说这可能没问题,但对于复杂的应用程序或具有许多对话框的应用程序,这肯定是一件疯狂的事情吗?在传统的QtWidgets模型中,您可以在需要时动态创建对话框.
我知道有一些解决方法,例如你可以Loader在javascript中直接动态使用甚至创建QML对象,但它们非常难看,你会失去优秀的QML语法的所有好处.你也无法真正"卸载"组件.那么Loader声称你可以,但我尝试过了,我的应用程序崩溃.
这个问题有优雅的解决方案吗?或者我只需要咬紧牙关并立即为我的应用创建所有潜在的用户界面,然后隐藏其中的大部分内容?
注意:此页面包含有关使用Loaders来解决此问题的信息,但正如您所看到的,它不是一个非常好的解决方案.
好的,为了向您展示为什么Loader不那么令人愉快,请考虑这个开始一些复杂任务并等待结果的示例.假设 - 与人们通常给出的所有琐碎的例子不同 - 任务有很多输入和几个输出.
这是Loader解决方案:
Window {
Loader {
id: task
source: "ComplexTask.qml"
active: false
}
TextField {
id: input1
}
TextField {
id: output1
}
Button {
text: "Begin complex task"
onClicked: {
// Show the task.
if (task.active === false)
{
task.active = true;
// Connect completed signal if it hasn't been already.
task.item.taskCompleted.connect(onTaskCompleted)
}
view.item.input1 = input1.text;
// And several more lines of that...
}
}
}
function onTaskCompleted()
{
output1.text = view.item.output1
// And several more lines...
// This actually causes a crash in my code:
// view.active = false;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我没有这样做Loader,我可能会有这样的事情:
Window {
ComplexTask {
id: task
taskInput1: input1.text
componentLoaded: false
onCompleted: componentLoaded = false
}
TextField {
id: input1
}
TextField {
id: output1
text: task.taskOutput1
}
Button {
text: "Begin complex task"
onClicked: task.componentLoaded = true
}
}
Run Code Online (Sandbox Code Playgroud)
这显然是这样简单.我明确想要的是一些ComplexTask加载的方法,并在componentLoaded设置为true 时激活所有声明性关系,然后断开关系并在componentLoaded设置为false 时卸载组件.我很确定目前在Qt中没有办法制作这样的东西.
动态地从JS创建QML组件与动态创建小部件一样丑陋(如果不是那么,因为它实际上更灵活).没有什么可丑的,你可以在单独的文件中实现你的QML组件,使用Creator在创建时提供的每个帮助,并在你需要的地方尽可能多地实例化那些组件.让一切都隐藏起来是非常丑陋的,它也更加沉重,它无法预测动态组件实例化可能发生的所有事情.
这是一个简约的自包含示例,它甚至不使用加载器,因为该对话框是本地可用的QML文件.
Dialog.qml
Rectangle {
id: dialog
anchors.fill: parent
color: "lightblue"
property var target : null
Column {
TextField {
id: name
text: "new name"
}
Button {
text: "OK"
onClicked: {
if (target) target.text = name.text
dialog.destroy()
}
}
Button {
text: "Cancel"
onClicked: dialog.destroy()
}
}
}
Run Code Online (Sandbox Code Playgroud)
main.qml
ApplicationWindow {
visible: true
width: 200
height: 200
Button {
id: button
text: "rename me"
width: 200
onClicked: {
var component = Qt.createComponent("Dialog.qml")
var obj = component.createObject(overlay)
obj.target = button
}
}
Item {
id: overlay
anchors.fill: parent
}
}
Run Code Online (Sandbox Code Playgroud)
此外,上面的例子是非常准确的,只是为了说明,考虑使用堆栈视图,您自己的实现或自5.1库存以来可用StackView.