在使用QtQuick控件的QtQuick 2中,您可以创建复杂的桌面应用程序.然而,在我看来,必须在应用程序开始时声明整个UI并立即创建所有UI.您仍然不想使用任何您不想使用的部分(例如File-> Open对话框),但它们是隐藏的,如下所示:
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.
现在,对于简单的应用程序来说这可能没问题,但对于复杂的应用程序或具有许多对话框的应用程序,这肯定是一件疯狂的事情吗?在传统的QtWidgets模型中,您可以在需要时动态创建对话框.
我知道有一些解决方法,例如你可以使用Loader,甚至可以直接在javascript中动态创建QML对象,但是它们非常难看,你会失去优秀的QML语法的所有好处.你也无法真正“卸载”组件. Well Loader声称你可以,但我试过了,我的应用程序崩溃了.
这个问题有优雅的解决方案吗?或者我只需要咬紧牙关并立即为我的应用创建所有潜在的用户界面,然后隐藏其中的大部分内容?
注意:this page提供了有关使用Loaders解决此问题的信息,但正如您所看到的那样,这不是一个非常好的解决方案.
编辑1 – 为什么Loader不是最理想的?
好的,为了向您展示为什么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; } }
如果我在没有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 } }
这显然更简单.我明确想要的是加载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() } } }
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 } }
此外,上面的例子是非常准确的,只是为了说明,考虑使用堆栈视图,您自己的实现或自5.1库存StackView后可用.