在命令式C ++中,我可以使用for(my.list in c("a", "b")) {
assign(my.list, `names<-`(get(my.list), c("element1", "element2")))
}
a
#$element1
#[1] 1
#$element2
#[1] 2
b
#$element1
#[1] 3
#$element2
#[1] 4
来连续询问用户几个问题。根据用户的答案(“是”,“否”,“确定”,“中止”),我可以继续前进。
但是在QML中,由于其声明性,它似乎是一项艰巨的任务。仍然可以创建一堆对话框,但依赖于答案的状态(信息)应该存储在QDialog
/ onAccepted
/ ...事件之间。如果与C ++代码(模型/单例)有很多交互,那就特别难了。
是否有任何一般的方法/技巧/习惯用法只使用一系列模态弹出窗口轻松创建类似“安装程序”的东西?
答案 0 :(得分:1)
首先,和其他人之前提到的一样,对于更长的事件链,你真的需要使用类似状态机的东西。
话虽如此,在实践中,与对话相关的大多数事情涉及最多2-3个级别的问题。 回调 非常适合:
你正在寻找的基本Api是:
g_dialogs.confirm({
title: 'Discard unsaved changes?',
message: 'You have unsaved changes here.\n' +
'Are you sure you want to open a new file?'
},
function(result){
if(result) {
g_dialogs.fileDialog({title: 'Select an Image'},
function(fileUrl){
loadFile(fileUrl)
})
}
})
其中g_dialogs指向Dialogs项的全局实例。您甚至可以使用QML单例。
<强> Dialogs.qml 强>:
import QtQuick 2.0
import QtQuick.Dialogs 1.2
Item
{
property var dialogs: []
property var callbacks: []
/**
* Creates a modal dialog pointed by the dialogSource qml file.
* For this functioanlity to work, the dialogSource MUST be an instance of Dialog component
* properties are the objects that will be passed on to the dialogSource' component
* property must not contain a key called 'dialogId'
* callback is the callback function that will be called with the result,
* once the user finishes interacting with the dialog. (eg. confirms/dismisses and event)
**/
function showDialog(dialogSource, properties, callback) {
if (properties === undefined)
properties = {}
if (properties['dialogId']) {
console.error('You cannot use the property name dialogId')
return -1
}
properties["dialogId"] = dialogs.length
var dialog
var component = Qt.createComponent(dialogSource)
var result = -1
if (component.status === Component.Ready) {
dialog = component.createObject(parent, properties)
callbacks.push(callback)
dialogs.push(dialog)
result = dialogs.length - 1
}
else {
console.error(component.errorString())
}
return result
}
/**
* Internal function used by Dialog
* to return the result to the original caller via. the callback
*/
function returnDialog(index, result) {
if (index < 0 || index >= callbacks.length)
return
var callback = callbacks[index]
var dialog = dialogs[index]
callbacks.splice(index, 1)
dialogs.splice(index, 1)
if (dialog !== undefined)
dialog.destroy()
if (callback !== undefined)
callback(result)
}
/**
* Convenience method to create a confirmation dialog where the user is presented with a yes/no question
* Asks the user whether he wants to confirm/reject an action.
* properties can be an Object of {title: 'Window title', text: 'Text', icon: ''}
* Once the user finishes interacting with dialog, the callback will be called with the result
*/
function confirm(properties, callback) {
properties["title"] = properties["title"]
? properties["title"]
: qsTr("Warning")
properties["text"] = properties["text"]
? properties["text"]
: qsTr("Are you sure?")
properties["standardButtons"] = StandardButton.Yes | StandardButton.No
return showDialog("MessageDialog.qml", properties, callback)
}
// Convenience wrapper around FileDialog.qml
function fileDialog(properties, callback) {
return showDialog("FileDialog.qml", properties, callback)
}
}
其中,每个对话框都是 Dialog.qml 的实例:
import QtQuick 2.0
Item
{
id: modalDialog
readonly property int dialogId: 0
signal done(var result)
onDone: g_dialogs.returnDialog(dialogId, result)
}
例如。的 MessageDialog.qml 强>:
import QtQuick 2.0
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import '.'
Dialog
{
property alias title: dialog.title
property alias text: dialog.text
property alias icon: dialog.icon
property alias standardButtons: dialog.standardButtons
MessageDialog
{
id: dialog
modality: Qt.ApplicationModal
standardButtons: StandardButton.Yes | StandardButton.No
icon: StandardIcon.Warning
onAccepted: done(true)
onYes: done(true)
onNo: done(false)
onDiscard: done(false)
onRejected: done(false)
}
//Variables in other windows don't seem to reflect the property changes in here.
//So show the window only after all the properties are set.
Component.onCompleted: dialog.visible = true
}
例如。的 FileDialog.qml 强>:
import QtQuick 2.0
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2
import '.'
Dialog
{
property alias title: dialog.title
property alias fileUrl: dialog.fileUrl
property alias fileUrls: dialog.fileUrls
property alias folder: dialog.folder
property alias modality: dialog.modality
property alias nameFilters: dialog.nameFilters
property alias selectExisting: dialog.selectExisting
property alias selectFolder: dialog.selectFolder
property alias selectMultiple: dialog.selectMultiple
property alias selectedNameFilter: dialog.selectedNameFilter
property alias shortcuts: dialog.shortcuts
property alias sidebarVisible: dialog.sidebarVisible
FileDialog
{
id: dialog
onAccepted: {
if (selectMultiple) done(fileUrls)
else done(fileUrl)
}
onRejected: done(null)
}
Component.onCompleted: dialog.visible = true
}
P.S关于这个api的好处是这些回调函数是很好的Javascript闭包,因此在ListView / Repeater委托中使用这种方法时,你不必传递讨厌的引用。