您当前的位置: 首页 > 

龚建波

暂无认证

  • 3浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

QML处理[文件保存提示框]中的任务链问题

龚建波 发布时间:2021-10-24 22:20:58 ,浏览量:3

在做文件保存提示框需求时,发现很多地方都会判断文件是否保存,未保存时就需要弹框提示,但是操作完又需要根据调用时的情况做后续处理。保存要提示,保存方式覆盖还是另存要提示,另存命名要编辑,命名后有重命名检测,以此等等,所以我叫他任务链,要根据当前任务上下文来做不同的操作。一开始我就在对话框中放一个枚举变量,弹出时设置对应的值,操作结束后根据这个枚举做后续操作。如下:

    Connections{
        target: warn_save
        onAccepted: {
            edit_save.show();
        }
        onRejected: {
            switch(type){ //根据枚举值来判断后续操作
            case 1: editor.saveFile(arg); break;
            case 2: editor.saveAse(arg); break;
            case 3: root.close(); break;
            }
            root.editDoing = false;
        }
    }

这里存在一个很明显的问题,就是组件的封装性不足,每次增加新的需求就需要扩充枚举,然后修改这个 switch 逻辑,甚至还可能把已有的逻辑改出问题。而且变动一个弹框的接口,可能前后相关的弹框都要跟着变更。 

这时我就想到注册回调函数,将变化点转移到调用者,不去变动封装好的组件。即弹框的确认、取消等每一个操作都对应一个回调函数。

    //询问是否保存文件
    //未保存时退出,或者手动点保存都会弹出
    MessageDialog {
        id: quit_warn
        title: "警告"
        text: "文件已编辑,是否保存?(不要点关闭按钮,没处理)"
        standardButtons: MessageDialog.Yes | MessageDialog.Cancel
        //确认之后需要执行的任务
        property var yesTask: null
        //取消之后需要执行的任务
        property var cancelTask: null
        //执行任务
        function doing(yes = null, cancel = null)
        {
            yesTask = yes;
            cancelTask = cancel;
            open();
        }
        onYes: {
            //选择保存
            visible = false;
            if(yesTask){
                yesTask();
            }else{
                //默认操作
            }
        }
        onRejected: {
            //取消
            visible = false;
            if(cancelTask){
                cancelTask();
            }else{
                //默认操作
            }
        }
    }

很明显,如果操作链上有多个弹框,那么就成了回调地狱的样子:

        //模拟点击退出程序
        Button {
            text: "退出"
            font.family: "SimSun"
            font.pixelSize: 16
            onClicked: {
                if(root.fileEdited){
                    //未保存就提示保存
                    quit_warn.doing(function(){
                        //确认保存就弹保存选择
                        save_warn.doing(function(){
                            //覆盖保存
                            root.close();
                        },function(){
                            //另存为
                            save_name.doing(function(){
                                //另存确认
                                root.close();
                            },function(){
                                //另存取消
                                save_warn.visible = true;
                            });
                        },function(){
                            //取消保存,退出
                            root.close();
                        });
                    },function(){
                        //不保存,退出
                        root.close();
                    });
                }else{
                    //未编辑,直接退出
                    root.close();
                }
            }
        }

对于回调地狱,Web 中的 JS 还可以用 Promise 或者 async / await,但是目前 Qt5 中的 QML 应该还不支持,需要等新的版本。可以先拆分成多个函数,这样比怼在一起更有条理。等想到更好的方案再来补充。

完整测试代码:

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Dialogs 1.2

Window {
    id: root
    width: 640
    height: 480
    visible: true
    title: qsTr("Task Chain")
    property bool fileEdited: true

    function saveFile()
    {
        console.log('save file');
        //假装保存了文件,清除编辑状态
        root.fileEdited = false;
    }

    function saveAs(path)
    {
        console.log('save as',path);
        //假装保存了文件,清除编辑状态
        root.fileEdited = false;
    }

    Column {
        anchors.centerIn: parent
        spacing: 20

        //模拟点击后保存文件
        Button {
            text: "保存"
            font.family: "SimSun"
            font.pixelSize: 16
            onClicked: {
                save_warn.doing(null,null,null);
            }
        }

        //模拟点击退出程序
        Button {
            text: "退出"
            font.family: "SimSun"
            font.pixelSize: 16
            onClicked: {
                if(root.fileEdited){
                    //未保存就提示保存
                    quit_warn.doing(function(){
                        //确认保存就弹保存选择
                        save_warn.doing(function(){
                            //覆盖保存
                            root.close();
                        },function(){
                            //另存为
                            save_name.doing(function(){
                                //另存确认
                                root.close();
                            },function(){
                                //另存取消
                                save_warn.visible = true;
                            });
                        },function(){
                            //取消保存,退出
                            root.close();
                        });
                    },function(){
                        //不保存,退出
                        root.close();
                    });
                }else{
                    //未编辑,直接退出
                    root.close();
                }
            }
        }
    }

    //询问是否保存文件
    //未保存时退出,或者手动点保存都会弹出
    MessageDialog {
        id: quit_warn
        title: "警告"
        text: "文件已编辑,是否保存?(不要点关闭按钮,没处理)"
        standardButtons: MessageDialog.Yes | MessageDialog.Cancel
        //确认之后需要执行的任务
        property var yesTask: null
        //取消之后需要执行的任务
        property var cancelTask: null
        //执行任务
        function doing(yes = null, cancel = null)
        {
            yesTask = yes;
            cancelTask = cancel;
            open();
        }
        onYes: {
            //选择保存
            visible = false;
            if(yesTask){
                yesTask();
            }else{
                //默认操作
            }
        }
        onRejected: {
            //取消
            visible = false;
            if(cancelTask){
                cancelTask();
            }else{
                //默认操作
            }
        }
    }

    //提示覆盖还是另存新文件
    MessageDialog {
        id: save_warn
        title: "文件保存"
        text: "覆盖(Reset)还是另存(Save)当前文件?(不要点关闭按钮,没处理)"
        standardButtons: MessageDialog.Reset | MessageDialog.Save | MessageDialog.Cancel
        //覆盖之后需要执行的任务
        property var resetTask: null
        //另存之后需要执行的任务
        property var saveTask: null
        //取消之后需要执行的任务
        property var cancelTask: null
        //执行任务
        function doing(reset = null, save = null, cancel = null)
        {
            resetTask = reset;
            saveTask = save;
            cancelTask = cancel;
            open();
        }
        onReset: {
            root.saveFile();
            //选择覆盖
            visible = false;
            if(resetTask){
                resetTask();
            }else{
                //默认操作
            }
        }
        onAccepted: {
            //选择另存
            visible = false;
            if(saveTask){
                saveTask();
            }else{
                //默认操作
                save_name.doing(null,function(){
                    save_warn.visible = true;
                });
            }
        }
        onRejected: {
            //取消
            visible = false;
            if(cancelTask){
                cancelTask();
            }else{
                //默认操作
            }
        }
    }

    //文件命名,后面可能还有重名等提示,这里略去
    MessageDialog {
        id: save_name
        title: "文件命名"
        text: "这里懒得做编辑框(不要点关闭按钮,没处理)"
        standardButtons: MessageDialog.Yes | MessageDialog.Cancel
        //确认之后需要执行的任务
        property var yesTask: null
        //取消之后需要执行的任务
        property var cancelTask: null
        //执行任务
        function doing(yes = null, cancel = null)
        {
            yesTask = yes;
            cancelTask = cancel;
            open();
        }
        onYes: {
            root.saveAs(save_name.text);
            //选择保存
            visible = false;
            if(yesTask){
                yesTask();
            }else{
                //默认操作
            }
        }
        onRejected: {
            //取消
            visible = false;
            if(cancelTask){
                cancelTask();
            }else{
                //默认操作
            }
        }
    }

}

关注
打赏
1655829268
查看更多评论
立即登录/注册

微信扫码登录

0.0362s