2014-05-14 11 views
5

मैं क्यूटी के लिए नया हूं, और मैंने qt-project.org और अन्य स्थानों पर जो पढ़ा है उससे; QtQuick दोनों आकर्षक और स्पर्श आधारित उपकरणों पर काम करने की क्षमता के कारण एक आकर्षक विकल्प की तरह लगता है। मेरी समस्या यह सी ++ के साथ अच्छी तरह से काम करने के लिए हो रही है।QtQuick, गतिशील छवियां और सी ++

मैंने "हैलो वर्ल्ड" के बाद अगले चरण के रूप में कॉनवे गेम ऑफ लाइफ का एक प्रकार लिखने का फैसला किया। मैं पूरी तरह से रहस्यमय हूं कि कैसे "बोर्ड" - एक [ऊंचाई] [चौड़ाई] [बाइट्स-प्रति-पिक्सेल] सरणी का दृश्य - दृश्य ग्राफ में एकीकृत किया गया है।

असल में, प्रक्रिया यह है कि "लाइफबोर्ड" अपने नियमों के माध्यम से पुनरावृत्त करता है और char */image को अपडेट करता है।

class Life { 
    public: 
     QImage getImage() {} 
     // Or 
     char* getPixels(int h, int w, QImage::Format_ARGB8888) {} 
} 

मैं कोई सुराग नहीं है, और ट्यूटोरियल से जूझने घंटे नहीं था:

:::QML 
ApplicationWindow { 
    id:   life_app_window 
    visible: true 
    title: qsTr("Life") 

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

    toolBar: ToolBar { 
     id: lifeToolBar; 
     ToolButton { 
      id: toolButtonQuit 
      text: qsTr("Quit") 
      onClicked: Qt.quit() 
     } 
     ToolButton { 
      id: toolButtonStop 
      text: qsTr("Stop") 
      enabled: false 
      //onClicked: 
     } 
     ToolButton { 
      id: toolButtonStart 
      text: qsTr("Start") 
      enabled: true 
      //onClicked: //Start life. 
     } 
     ToolButton { 
      id: toolButtonReset 
      text: qsTr("Stop") 
      // onClicked: //Reset life. 
     } 
    } 

    Flow { 
     id: flow1 
     anchors.fill: parent 
     //***** 
     // WHAT GOES HERE 
     //***** 
    } 

    statusBar: StatusBar { 
     enabled: false 
     Text { 
      // Get me from number of iterations 
      text: qsTr("Iterations.") 
     } 
    } 
} 

मैं इस तरह थोड़े एक एपीआई के साथ एक वर्ग से आते हैं करने के लिए छवि के लिए चाहते हैं: मैं इस सरल QML मिल गया है मदद। एक सी *+ में char * छवि को कैसे लिंक करता है ??? क्यूएमएल में ताकि क्यूएमएल "लाइफ" लूप को शुरू/बंद कर सके और ताकि "लाइफ" लूप और चार सरणी को अपडेट कर सके और क्यूएमएल को फिर से निकालने के लिए सूचित कर सके?


नोट: मैं जानकारी here के आधार पर उपवर्गीकरण QQuickImageProvider देखा है। इस दृष्टिकोण के साथ समस्या यह है कि मैं नहीं देख सकता कि कैसे स्क्रीन छवि पर C++ "ड्राइव" को जाने दें। मैं QML से C++ पर नियंत्रण पास करना चाहता हूं और बदली गई छवि के साथ प्रदर्शन को अपडेट करने के लिए C++ को QML बताएं। क्या इस दृष्टिकोण के साथ कोई समाधान है? या पूरी तरह से एक और दृष्टिकोण।

+0

अपने सी ++ को देखे बिना बताना मुश्किल है। आप QListModel या QAbstractItemModel का उपयोग C++ से QML तक डेटा की एक सूची भेजने के लिए कर सकते हैं और उन्हें C++ से अपडेट करने में सक्षम हो सकते हैं। फिर क्यूएमएल में आप ग्रिड – koopajah

+0

@koopajah के अपने गेम का प्रतिनिधित्व करने के लिए ग्रिड व्यू में छवि {} घटक का उपयोग करते हैं, मैं चाहता हूं कि छवि मैनिपिलेशन कोड निजी कार्यों के सेट में हो। मैं चाहता हूं कि सी ++ सिग्नल क्यूएमएल है कि एक अपडेट छवि तैयार है, और क्यूएमएल उस छवि को प्रदर्शित करता है। इसके अतिरिक्त क्यूएमएल लाइफ पुनरावृत्तियों को आरंभ/रोकने के लिए कॉल "स्टॉप", "स्टार्ट" और "रीसेट" स्लॉट कॉल करने में सक्षम होना चाहिए। – justinzane

उत्तर

8

ऐसा करने का पहला तरीका QML में प्रत्येक गेम पिक्सेल के लिए Rectangle बनाना होगा, जो कि 8x8 बोर्ड के लिए फैंसी हो सकता है, लेकिन 100x100 बोर्ड के लिए नहीं, क्योंकि आपको प्रत्येक पिक्सेल के लिए मैन्युअल रूप से क्यूएमएल कोड लिखना होगा।

इस प्रकार मैं सी ++ में बनाई गई छवियों और QML के संपर्क में आने के लिए जाऊंगा। एसिंक्रोनस लोडिंग की अनुमति देने के लिए आप उन्हें image provider के माध्यम से कॉल करते हैं। Life केवल तर्क दें।

छवि इस तरह QML से कहा जाता है:

Image { 
    id: board 
    source: "image://gameoflife/board" 
    height: 400 
    width: 400 
} 

अब gameoflife छवि प्रदाता का नाम और board तथाकथित id आप बाद में उपयोग कर सकते हैं।

आप में रजिस्टर gameoflifemain.cpp

LifeImageProvider *lifeIP = new LifeImageProvider(life); 
engine.addImageProvider("gameoflife", lifeIP); 

जहां engine है आपका मुख्य QQmlApplicationEngine और life अपने Life खेल इंजन का एक उदाहरण।

LifeImageProvider आपकी कक्षा पिक्सेलटाटा बनाने के लिए है। शुरू होता है किसी भी तरह की तरह

class LifeImageProvider : public QQuickImageProvider 
{ 
public: 
    LifeImageProvider(Life *myLifeEngine); 
    QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize); 

private: 
    Life *myLifeEngine_; 
}; 

महत्वपूर्ण तरीका requestPixmap, जो QML से कहा जाता है। आपको इसे लागू करने की जरूरत है।

खेल बोर्ड ताज़ा करने के लिए Life एक stateChanged() संकेत भेजता है जब QML करने के लिए एक वैश्विक वस्तु के रूप में life बेनकाब:

context->setContextProperty("life", &life); 

आप बस मस्ती के लिए QML

Image { 
    id: board 
    source: "image://gameoflife/board" 
    height: 400 
    width: 400 
} 

Connections { 
    target: life 
    onStateChanged: { 
     board.source = "image://gameoflife/board?" + Math.random() 
     // change URL to refresh image. Add random URL part to avoid caching 
    } 
} 
+0

मैं कंट्रोल कैसे उलटा सकता हूं ताकि क्यूएमएल 'अनुरोध पिक्समैप' के माध्यम से डिस्प्ले शुरू नहीं करता है बल्कि सी ++ से सिग्नल के लिए सुनता है और डिस्प्ले अपडेट करता है ('requestPixmap' या अन्यथा के माध्यम से) जब यह संकेत मिलता है? लक्ष्य, यदि संभव हो, तो क्यूएमएल अधिकतर निष्क्रिय हो, केवल यूआई विजेट प्रदान कर रहा है जबकि समय और तर्क सी ++ में हैं। – justinzane

+0

मैंने पोस्ट किए गए 'कनेक्शन' तत्व को देखें। यह 'लाइफ' के सिग्नल 'स्टेट चेंज' को जोड़ता है और तंत्र को अपडेट करता है, जो 'requestPixmap' को कॉल करता है। –

+1

"प्रत्येक पिक्सेल के लिए मैन्युअल रूप से क्यूएमएल कोड लिखने" की आवश्यकता है, यह जरूरी नहीं है; मैंने एक बार "ग्रिड" तत्व का उपयोग करके क्यूएमएल में जीवन लागू किया है http://qt-project.org/doc/qt-5/qml-qtquick-grid.html सेल राज्यों को मुद्रित करने के लिए "पुनरावर्तक" के साथ http: // qt-project.org/doc/qt-5/qml-qtquick-repeater.html; यह बहुत धीमी थी (~ 20x20 व्यावहारिक सीमा थी), हालांकि कुछ अच्छे पहलू थे जैसे सेल जन्म/मृत्यु एनिमेटेड संक्रमण प्रभाव निर्दिष्ट करना आसान था। ऑल-क्यूएमएल जीवन करने का दूसरा प्रयास यह हुआ: http://stackoverflow.com/a/24467011/24283 जो बहुत तेज है। – timday

1

के संकेत बाध्य कर सकते हैं और पूरी तरह से स्पर्श करने योग्य उत्तर के लिए डाउनवॉट्स के जोखिम पर, यहां गेमऑफलाइफ पूरी तरह से क्यूएमएल में लागू किया गया है, बस इसे एक .qml फ़ाइल में डालें और इसे qmlscene के साथ चलाएं। क्यूटी 5.3.0 पर काम करता है, और एक पुराने कोर 2 डुओ lappy पर तेजी से (मेरे लिए) चलाता है। मुझे यकीन है कि यह कभी भी C++ QQuickImageProvider आधारित समाधान के रूप में तेज़/कुशल नहीं होगा, लेकिन यह सी ++ का उपयोग किए बिना QML में काफी कुछ करना संभव बनाता है।

import QtQuick 2.2 

Rectangle { 
    id: main 
    width: 640 
    height: 640 
    color: '#000088' 

    Timer { 
    interval: 1000/60 
    running: true 
    repeat: true 
    onTriggered: {advance();display();} 
    } 

    Component { 
    id: cellComponent 
    Rectangle { 
     objectName: 'cell' 
     property int row: 0 
     property int col: 0  
     x: main.width/2+width*col 
     y: main.height/2+height*row  
     width: 5 
     height: 5 
     radius: 2 
     smooth: true 
     color: '#ffcc00' 
    } 
    } 

    property var cells: null 

    Component.onCompleted: { 
    cells=[[-1, 0],[-1, 1],[ 0,-1],[ 0, 0],[ 1, 0]]; 
    display(); 
    } 

    function display() { 
    // Just completely regenerate display field each frame 
    // TODO: might be nicer to do differential updates, would allow birth/death animations 

    // Nuke all previously displayed cells 
    for (var i=0;i<children.length;i++) { 
     if (children[i].objectName=='cell') { 
     children[i].destroy(); 
     } 
    } 

    // Show current set of cells 
    for (var i=0;i<cells.length;i++) { 
     var c=cellComponent.createObject(
     main, 
     {'row':cells[i][0],'col':cells[i][1]} 
    ); 
    } 
    } 

    function advance() { 

    // Build a hash of the currently alive cells and a neighbour count (includes self) 
    var a=new Object; 
    var n=new Object; 
    for (var i=0;i<cells.length;i++) { 
     var p=cells[i] 
     var r=p[0]; 
     var c=p[1]; 
     if (!(r in a)) a[r]=new Object; 
     a[r][c]=1; 
     for (var dr=r-1;dr<=r+1;dr++) { 
     for (var dc=c-1;dc<=c+1;dc++) { 
      if (!(dr in n)) n[dr]=new Object; 
      if (!(dc in n[dr])) n[dr][dc]=0; 
      n[dr][dc]+=1; 
     } 
     } 
    } 

    // For all live cells, assess viability 
    var kill=[]; 
    var stay=[]; 
    for (var r in a) { 
     for (var c in a[r]) { 
     if (n[r][c]-1<2 || n[r][c]-1>3) 
      kill.push([Number(r),Number(c)]); 
     else 
      stay.push([Number(r),Number(c)]); 
     } 
    } 

    // For neighbours of live cells, assess potential for births 
    var born=[]; 
    for (var r in n) { 
     for (var c in n[r]) { 
     if (!((r in a) && (c in a[r]))) { 
      if (n[r][c]==3) 
      born.push([Number(r),Number(c)]); 
     } 
     } 
    } 

    cells=stay.concat(born) 
    } 
} 

और GLSL (एक पुनरावर्ती QML ShaderEffect के माध्यम से) का उपयोग कर GPU see here पर जीवन के नियमों का खेल गणना करने के लिए एक शुद्ध QML संस्करण के लिए।

संबंधित मुद्दे