2015-06-08 5 views
6

मैं कुछ कस्टम एनीमेशन आकर्षित करने के लिए QML Canvas.requestAnimationFrame का उपयोग करने का प्रयास कर रहा हूं। मुझे उम्मीद थी कि प्रदान किए गए कॉलबैक को प्रत्येक फ्रेम के लिए एक बार कहा जाता है, प्रति सेकंड लगभग 60 गुना। मेरे पास कोड है:QML Canvas.requestAnimationFrame विस्फोट

Canvas { 
    id: canvas 

    width: 600 
    height: 600 

    function draw() { 
    } 

    Component.onCompleted: { 
     var i = 1; 

     function drawFrame() { 
      requestAnimationFrame(drawFrame) 
      console.log("Frame callback: " + i++) 
      draw() 
     } 

     drawFrame() 
    } 

    onPaint: { 
     draw() 
    } 

} 

मुझे क्या लगता है कि कॉलबैक को अक्सर और अधिक बार कहा जाता है। काउंटर कुछ सेकंड में 70000 तक पहुंचता है, जिसके बाद एप्लिकेशन पूरी तरह उत्तरदायी नहीं होता है।

मैं क्या गलत कर रहा हूं?

+0

मुझे लगता है कि आपको कोड में रिकर्सन से बचना होगा। – folibis

+0

संबंधित: http://stackoverflow.com/q/39353234/405017 – Phrogz

उत्तर

2

आपका drawFrame() फ़ंक्शन प्रतिपादन के लिए कॉलबैक फ़ंक्शन के रूप में स्वयं को पास करता है और आप लूप में पकड़े जाते हैं। आप या तो मांग पर रेंडर करना चाहते हैं उदाहरण के लिए उदाहरण के लिए उपयोगकर्ता इनपुट को कम से कम रखने के लिए, या आपके पास कुछ तर्क है जो प्रत्येक फ्रेम को बदलता है या आपको लगातार प्रतिपादन की आवश्यकता होती है।

समय आधारित प्रतिपादन आप क्या चाहते हैं, बस का उपयोग है, तो एक Timer:

import QtQuick 2.4 

Canvas { 
    id: cvs 
    width: 600; height: 600 
    contextType: "2d" 
    property real i : 0 

    onPaint: { 
     console.timeEnd("t") 
     if (context) { 
      context.clearRect (0, 0, width, height) 
      context.fillRect(i, 50, 50, 50 + i) 
     } 
     console.time("t") 
    } 

    Timer { 
     interval: 1 
     repeat: true 
     running: true 

     onTriggered: { 
      cvs.i = (cvs.i + 0.1) % cvs.width 
      cvs.requestPaint() 
     } 
    } 
} 

संपादित करें:

onPaint कॉल प्रदर्शन फ्रेम दर करने के लिए सिंक किए गए हैं:

बस कोड अद्यतन भले ही टाइमर अंतराल 1ms पर सेट हो, जैसा कि ऊपर नमूना चलाते समय लॉग से देखा जा सकता है। वास्तव में onTriggered सिग्नल को सौंपा गया पूरा ब्लॉक हर मिलीसेकंड को निष्पादित किया जाता है लेकिन requestPaint() एचटीएमएल कैनवास के लिए requestAnimationFrame() जैसे सर्वोत्तम प्रदर्शन के लिए प्रतिपादन कॉल सिंक्रनाइज़ करना सुनिश्चित करता है।

जाहिर है, requestAnimationFrame() QML.Canvas अंदर की उम्मीद है और वहाँ बहुत प्रलेखन नहीं है के रूप में काम नहीं करता है ...

आशा इस मदद करता है!

+1

प्रतिक्रिया के लिए धन्यवाद - लेकिन ऐसा लगता है कि आपका उदाहरण वास्तव में अनुरोध एनीमेशन फ्रेम का उपयोग नहीं करता है? कम से कम एचटीएमएल कैनवास में, अनुरोध एनीमेशन फ्रेम का उपयोग करने का लाभ यह है कि आपका कोड बिल्कुल इष्टतम दर पर लगाया जाता है। क्या आप अनुरोध कर रहे हैं क्यूटी में एनीमेशन फ्रेम टूटा हुआ है और इससे बचा जाना चाहिए? –

+0

हाँ आप सही हैं। एचटीएमएल/जेएस में यह काम करता है, क्यूएमएल में यह नहीं करता है। मैंने बस इसके लिए जवाब अपडेट किया – qCring

1

इस विषय पर बस एक छोटा सा अपडेट। जब मैं अपनी परियोजना पर काम कर रहा था, तो मुझे Qt qml कैनवास और requestAnimationFrame के साथ एक ही समस्या का सामना करना पड़ा। समाधान जो मैंने पाया है वह रेंडर रणनीति को Threaded पर स्विच करना है और onPainted सिग्नल का उपयोग करना है। मेरे अपडेट के साथ qCring के कोड के उदाहरण इस प्रकार है:

import QtQuick 2.4 

Canvas { 
    id: cvs 
    width: 600; height: 600 

    //renderStrategy: Canvas.Cooperative // Will work as well but animation chops on my computer from time to time 
    renderStrategy: Canvas.Threaded 

    contextType: "2d" 
    property real i : 0 

    function animate() { 
     cvs.i = (cvs.i + 0.1) % cvs.width; 
    } 

    onPaint: { 
     console.timeEnd("t") 
     if (context) { 
      context.clearRect(0, 0, width, height) 
      context.fillRect(i, 50, 50, 50 + i) 
     } 
     console.time("t") 

     cvs.requestAnimationFrame(animate); 
    } 

    onPainted: { 
     cvs.requestPaint(); 
    } 
} 
0

एक bug with requestAnimationFrame() क्यूटी 5.9 से पहले हुई थी। इस बग को ठीक कर दिया गया है।

यह कोड अपेक्षित काम करता है और कैनवास को लगातार पुनर्निर्मित रखने के लिए वांछित काम करता है।

Canvas { 
    width:100; height:100; 
    property var ctx 
    onAvailableChanged: if (available) ctx = getContext('2d'); 
    onPaint: { 
     if (!ctx) return; 
     ctx.clearRect(0, 0, width, height); 
     // draw here 
     requestAnimationFrame(paint); 
    } 
}