5

我想展示一段BusyIndicator漫长的过程。问题是当我让它运行时它不显示,然后在过程完成时显示。根据文档

忙碌指示符应该用于指示正​​在加载内容或 UI 被阻止等待资源可用时的活动。

我创建了一个基于原始代码的最小代码

Window {
    id: win
    width: 300
    height: 300

    property bool run : false

    Rectangle {
        anchors.fill: parent
        BusyIndicator {
            anchors.centerIn: parent
            running: run
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                run = true
                for(var a=0;a<1000000;a++) { console.log(a) }
                run = false
            }
        }
    }
}

因此,当Rectangle单击 时,我想显示BusyIndicator计算完成之前的时间。

例如,我在这里使用了 for 循环。在实际场景中,我通过ContextProperty. 但在这种情况下,BusyIndicator也不会显示。

我做对了吗?或者最好的方法是什么?

4

3 回答 3

6

您无法查看您的BusyIndicator只是因为onClicked处理程序中的长时间操作会阻止应用程序 GUI 并且指示器不会更新。您应该在不同的线程中运行此类操作以避免冻结 GUI。简单的例子:

QML

Window {
    id: win
    width: 300
    height: 300

    property bool run : false

    Rectangle {
        anchors.fill: parent
        BusyIndicator {
            id: busy
            anchors.centerIn: parent
            running: win.run
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                win.run = true
                thread.sendMessage({run : true});
            }
        }

        WorkerScript {
            id: thread
            source: "handler.js"
            onMessage: {
                win.run = messageObject.run;
            }
        }
    }
}

处理.js

WorkerScript.onMessage = function(message) {
    if(message.run === true) {
        for(var a=0;a<1000000;a++) { console.log(a) }
    }
    WorkerScript.sendMessage({run : false});
}
于 2014-12-01T06:12:31.773 回答
3

有一种使用QQuickWindow'safterSynchronizing信号的方法:

import QtQuick 2.4
import QtQuick.Controls 1.3

ApplicationWindow {
    width: 400
    height: 400
    visible: true

    Component.onCompleted: print(Qt.formatDateTime(new Date(), "mm:ss:zzz"), "QML loaded")

    onAfterSynchronizing: {
        print(Qt.formatDateTime(new Date(), "mm:ss:zzz"), "Window content rendered")
        if (!loader.item) {
            loader.active = true
        }
    }

    Item {
        anchors.fill: parent

        BusyIndicator {
            running: !loader.item
            anchors.centerIn: parent
        }

        Loader {
            id: loader
            active: false
            anchors.fill: parent
            sourceComponent: Text {
                wrapMode: Text.Wrap

                Component.onCompleted: {
                    for (var i = 0; i < 500; ++i) {
                        text += "Hello, ";
                    }
                }
            }
        }
    }
}

这个想法是使用 aLoader来控制何时发生昂贵的操作。您还可以通过 使用动态加载的组件Qt.createQmlObject(),或者Qt.createComponent()在单独的文件中动态加载组件。

如果你运行这个例子,你会看到你得到以下输出:

qml: 58:12:356 QML 加载
qml: 58:12:608 呈现的窗口内容

我们使用QQuickWindow'afterSynchronizing信号来知道窗口的内容何时显示,并且只在第一次(通过if (!loader.item))时对其进行操作。

当信号最初发出时,我们可以确定它BusyIndicator已经开始了动画,所以用户实际上会看到一个旋转的图标。

一旦Loader完成加载文本,它的item属性将变为非 null 并且BusyIndicator将消失。

于 2014-12-02T14:07:06.630 回答
1

今天遇到同样的问题!我会假设你是BusyIndicator从一个名为busy. 而且您正在设置busytrue就在您的计算之前和false之后。这样做为我解决了这个问题。这不是一个非常优雅的解决方案,但它有效:

QML

BusyIndicator {
    running: CPPModule.busy
}

CPP

void CPPModule::setBusy(const bool &busy)
{
    m_busy = busy;
    emit busyChanged();
}
void CPPModule::InsertIntoDB()
{
    setBusy(true);
    QThread::msleep(50);
    QCoreApplication::processEvents();
    /*
    very Long Operation
    */
    setBusy(false);
}
于 2015-02-25T08:42:48.430 回答