在使用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.
现在,对于简单的应用程序来说这可能没问题,但对于复杂的应用程序或具有许多对话框的应用程序,这肯定是一件疯狂的事情吗?在传统的QtWidgets模型中,您可以在需要时动态创建对话框 .
我知道有一些解决方法,例如您可以使用 Loader
甚至直接在javascript中动态创建QML对象,但它们非常难看,您将失去优质QML语法的所有好处 . 你也不可能真的"unload"组件 . 那么 Loader
声称你可以,但我试过了,我的应用程序崩溃了 .
这个问题有优雅的解决方案吗?或者我只需要咬紧牙关并立即为我的应用创建所有潜在的用户界面,然后隐藏其中的大部分内容?
注意:this page有关于使用 Loader
来解决这个问题的信息,但是你可以看到它不是一个非常好的解决方案 .
编辑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中没有办法制作这样的东西 .
3 回答
动态地从JS创建QML组件与动态创建小部件一样丑陋(如果不是这样,实际上更灵活) . 没有什么可丑的,你可以在单独的文件中实现你的QML组件,使用Creator在创建时提供的每个帮助,并在你需要的地方尽可能多地实例化那些组件 . 让一切都隐藏起来是非常丑陋的,它也更加沉重,它无法预测动态组件实例化可能发生的所有事情 .
这是一个简约的自包含示例,它甚至不使用加载器,因为该对话框是本地可用的QML文件 .
Dialog.qml
main.qml
此外,上面的示例非常准确,只是为了说明,考虑使用堆栈视图,您自己的实现或自5.1库存
StackView
以来可用 .这里's a slight alternative to ddriver'的答案每次创建该组件的实例时都不会调用
Qt.createComponent()
(这将非常慢):我认为加载和卸载元素不再是实际的,因为每个用户都有超过2GB的RAM .
你认为你的应用程序甚至可以使用超过512 MB的内存吗?我对此表示怀疑 .
你应该加载qml元素,不要卸载它们,不会发生崩溃,只需存储所有指针并操纵qml帧 .
如果您只是将所有QML元素保存在RAM中并存储它们的状态,它将更快地运行并且看起来更好 .
示例是我以这种方式开发的项目:https://youtube.com/watch?v=UTMOd2s9Vkk
我已经制作了所有窗口继承的基础框架 . 这个框架确实有hide / show和resetState方法 . 基本窗口确实包含所有子帧,因此通过信号/插槽,其他帧显示/隐藏下一个所需的帧 .