Есть несколько вопросов на эту тему, которые не связаны с моим вопросом и они не дали мне никаких результатов.
Представьте, что у меня есть заставка с AnimatedImage в QML, которую я хочу отображать, когда мои тяжелые компоненты загружаются в фоновом режиме, поэтому я использую загрузчик для загрузки ресурсов в фоновом режиме, но когда загрузчик начинает загружать мой пользовательский интерфейс зависает (то есть AnimatedImage), я вижу, что BusyIndicator не зависает.
Я предоставил полный исходный код в репозитории github, чтобы вам было легче его протестировать.
мои вопросы:
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts
Window {
id:mainWindow
y:100
width: 640
height: 480
visible: true
flags: Qt.FramelessWindowHint
//splash screen
Popup {
id: popup
width: mainWindow.width
height: mainWindow.height
modal: false
visible: true
Overlay.modeless: Rectangle {
color: "#00000000"
}
//Splash loader
Loader{
id: splash
anchors.fill: parent
source: "qrc:/Splashscreen.qml"
}
}
// Timer that will start the loading heavyObjects
Timer {
id: timer
interval: 2000
repeat: false
running: true
onTriggered: {
loader.source = "qrc:/heavyObjects.qml"
loader.active = true
}
}
//write a loader to load main.qml
Loader {
id: loader
anchors.fill: parent
asynchronous: true
active: false
//when loader is ready, hide the splashscreen
onLoaded: {
popup.visible = false
}
visible: status == Loader.Ready
}
}
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
Item {
Rectangle {
id: splashRect
anchors.fill: parent
color: "white"
border.width: 0
border.color: "black"
AnimatedImage {
id: splash
source: "qrc:/images/Rotating_earth_(large).gif"
anchors.fill: parent
}
}
}
import QtQuick
Item {
function cumsum() {
for(var j=0;j<100;j++){
var p = 0
for (var i = 0; i < 1000000; i++) {
p *= i
}
}
return ""
}
// show dummy text that this is the main windows
Text {
text: "Main Window" + String(cumsum())
anchors.centerIn: parent
}
}
Большинство вещей, которые вы делаете в QML, обрабатываются в потоке движка QML. Если вы сделаете что-то тяжелое в этом потоке, он заблокирует все остальное. Я не проверял ваш исходный код, но с точки зрения тяжелой инициализации мы можем разбить его с помощью Qt.callLater() или аналогичного, чтобы поток механизма QML мог наверстать упущенное в событиях UI/UX.
Например, в следующем:
cumsum
с функции на свойствоcalcStep
для расчета за одну j
итерациюQt.callLater
для создания следующей итерацииComponent.onCompleted
property string cumsum
function calcStep(j) {
if (j >= 100) {
cumsum = new Date();
return;
}
for (var i = 0; i < 1000000; i++) {
p *= i
}
Qt.callLater(calcStep, j+1);
}
Component.onCompleted: calcStep(0)
}
Если ваша инициализация более сложная, вы можете попробовать Promises. Это позволяет вам писать асинхронные подпрограммы синхронным способом, например.
property string cumsum
function calc() {
_asyncToGenerator(function*() {
for(var j=0;j<100;j++){
var p = 0
status = "j: " + j;
yield pass();
for (var i = 0; i < 1000000; i++) {
p *= i
}
}
cumsum = new Date();
})();
}
function pass() {
return new Promise(function (resolve, reject) {
Qt.callLater(resolve);
} );
}
Component.onCompleted: calc()
В приведенном выше расчете cumsum
использовалась производная от шаблона async/await. Для этого я использую _asyncToGenerator
, предоставленный транспайлером на babeljs.io. Это необходимо, поскольку QML/JS не поддерживает шаблон async/await до версии Qt6.6.
Функция pass()
работает аналогично передаче Python, но моя реализация Qt.callLater
заключена в промис. Вызов его с помощью yield pass();
ничего не делает, но позволяет вашей функции на мгновение отпустить управление, чтобы события UI/UX могли наверстать упущенное.
import QtQuick
import QtQuick.Controls
Page {
property string cumsum
property string status
// show dummy text that this is the main windows
Text {
text: "Main Window: " + cumsum
anchors.centerIn: parent
}
Text {
text: status
anchors.horizontalCenter: parent.horizontalCenter
y: parent.height * 3 / 4
}
function calc() {
_asyncToGenerator(function*() {
for(var j=0;j<100;j++){
var p = 0
status = "j: " + j;
yield pass();
for (var i = 0; i < 1000000; i++) {
p *= i
}
}
cumsum = new Date();
})();
}
function pass() {
return new Promise(function (resolve, reject) {
Qt.callLater(resolve);
} );
}
function _asyncToGenerator(fn) {
return function() {
var self = this,
args = arguments
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args)
function _next(value) {
_asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value)
}
function _throw(err) {
_asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err)
}
_next(undefined)
})
}
}
function _asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg)
var value = info.value
} catch (error) {
reject(error)
return
}
if (info.done) {
resolve(value)
} else {
Promise.resolve(value).then(_next, _throw)
}
}
Component.onCompleted: calc()
}
Вы можете Попробовать онлайн!
Если вам интересна часть работы, которую я проделал с асинхронностью и обещаниями QML, обратитесь к следующим проектам GitHub:
@SaeedMasoomi хорошо, я посмотрел ваш репозиторий на GitHub. Анимационный gif маленький и не является причиной проблемы. Единственная причина, по которой анимация зависает, заключается в том, что HeavyObject.qml также работает в том же потоке QML Engine, поэтому он блокирует пользовательский интерфейс. Это, как я упоминал ранее. Вы должны дать нам некоторое представление о том, что делает HeavyObject.qml, чтобы мы могли видеть, есть ли способы, которыми мы можем заставить его отступить от потока механизма QML. Если нет, то такие элементы UI/UX, как щелчки мышью, анимированные GIF-файлы и т. д., будут заблокированы.
Предоставленную вами информацию трудно получить в таком структурированном виде, поэтому спасибо за любезную помощь и время, которое вы уделили.
Хотя это не то, что я имел в виду, ваши предложения продуманы и высоко ценятся. Я работаю с MCU, который не очень находчив. Как я тестировал, мой экран-заставка зависает при загрузке большого изображения, и я хотел бы исправить эту проблему. Этот фиктивный цикл for можно рассматривать как имитацию этого большого изображения, мне не нравится видеть это зависание на моем экране-заставке, у вас есть какие-либо идеи для этого? Спасибо