qml中,filedialog接受dialog时如何显示busyIndi​​cator?

In qml, how to display busyIndicator when dialog is accepted in filedialog?

我想在FileDialog中用户接受文件名后应用程序正在处理任务时显示一个繁忙的指示器,但是主线程似乎被filedialog阻塞了。所以无法显示busyindicator。我该如何解决?谢谢

代码如下:

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    title: qsTr("Hello World")
    id: root
    width: 640
    height: 480

    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")
            MenuItem {
                text: qsTr("E&xit")
                onTriggered: Qt.quit();
            }
        }
    }

    MainForm {
        anchors.fill: parent
        button1.onClicked: {
            exportXlsxDialog.open()
        }
        FileDialog {
            id: exportXlsxDialog
            title: qsTr("Please choose a xslx file")
            nameFilters: [ "Excel 2007-2013 (*.xlsx)" ]
            selectExisting: false
            onAccepted: {
                busyIndicator.running = true
                sleep(10000)
                console.log(fileUrl)
                busyIndicator.running = false
            }
            function sleep(milliseconds) {
                var start = new Date().getTime();
                for (var i = 0; i < 1e7; i++) {
                    if ((new Date().getTime() - start) > milliseconds){
                        break;
                    }
                }
            }
        }
        BusyIndicator {
            id: busyIndicator
            z: 99
            anchors.centerIn: parent
            running: false
        }
    }
}

我认为问题在于您的 sleep() 函数没有给 BusyIndicator 一个显示的机会,可能是因为它没有让 Qt 的事件循环旋转。

最好的解决方案可能是使用 WorkerScript,但如果你很懒,可以使用这个:

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2

ApplicationWindow {
    title: qsTr("Hello World")
    id: root
    width: 640
    height: 480

    Timer {
        id: expensiveOperationDelay
        interval: 1
        onTriggered: sleep(2000)
    }

    function sleep(milliseconds) {
        var start = new Date().getTime();
        for (var i = 0; i < 1e7; i++) {
            if ((new Date().getTime() - start) > milliseconds){
                break;
            }
        }
        busyIndicator.running = false
    }

    Button {
        text: "Click"
        onClicked: {
            busyIndicator.running = true
            expensiveOperationDelay.start()
//            sleep(2000)
        }
    }

    BusyIndicator {
        id: busyIndicator
        z: 99
        anchors.centerIn: parent
        running: false
    }
}

我稍微简化了您的示例,因为对话框不是演示问题所必需的。

这将启动昂贵操作的责任推给了 Timer。我给了它导致事件被处理的最小可能间隔(我认为 0 的间隔会导致这种情况,但显然不是),以便显示指示器。我还必须将指标的隐藏移动到 sleep() 函数的末尾,因为如果我将它留在原处,它会在呈现之前再次隐藏。