खोज…


C ++ से QtQuick व्यू बनाना

C ++ से सीधे QtQuick दृश्य बनाना और QML C ++ परिभाषित गुणों को उजागर करना संभव है। C ++ प्रोग्राम के नीचे दिए गए कोड में एक QtQuick व्यू बनाता है और QML के रूप में गुणों की ऊंचाई और चौड़ाई को उजागर करता है।

main.cpp

#include <QApplication>
#include <QQmlContext>
#include <QQuickView>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // Creating the view and manually setting the QML file it should display
    QQuickView view;
    view.setSource(QStringLiteral("main.qml"));
    
    // Retrieving the QML context. This context allows us to expose data to the QML components
    QQmlContext* rootContext = view.rootContext();

    // Creating 2 new properties: the width and height of the view
    rootContext->setContextProperty("WINDOW_WIDTH", 640);
    rootContext->setContextProperty("WINDOW_HEIGHT", 360);

    // Let's display the view
    view.show();

    return app.exec();
}

main.qml

import QtQuick 2.0

Rectangle {
    // We can now access the properties we defined from C++ from the whole QML file
    width: WINDOW_WIDTH
    height: WINDOW_HEIGHT

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}

C ++ से एक QtQuick विंडो बनाना

Qt 5.1 और बाद में आप QML स्क्रिप्ट को लोड और रेंडर करने के लिए QQuickView के बजाय QQmlApplicationEngine का उपयोग कर सकते हैं।

QQmlApplicationEngine के साथ आपको अपने मूल तत्व के रूप में एक QML विंडो प्रकार का उपयोग करने की आवश्यकता है।

आप इंजन से रूट संदर्भ प्राप्त कर सकते हैं जहां आप QML लिपियों को संसाधित करते समय इंजन द्वारा उस संदर्भ तक वैश्विक गुणों को जोड़ सकते हैं, जिसे इंजन द्वारा एक्सेस किया जा सकता है।

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    QQmlContext* rootContext = engine.rootContext();
    rootContext->setContextProperty("WINDOW_WIDTH", 640);
    rootContext->setContextProperty("WINDOW_HEIGHT", 360);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

main.qml

import QtQuick 2.5
import QtQuick.Window 2.2

Window { // Must be this type to be loaded by QQmlApplicationEngine.
    visible: true
    width: WINDOW_WIDTH   //Accessing global context declared in C++
    height: WINDOW_HEIGHT //Accessing global context declared in C++
    title: qsTr("Hello World")
    Component.onCompleted: {
        // We can access global context from within JavaScript too.
        console.debug( "Width: " + WINDOW_WIDTH )
        console.debug( "Height: " + WINDOW_HEIGHT )
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}

TreeView के लिए एक सरल मॉडल बनाना

क्यूटी 5.5 के बाद से हमारे पास एक नया अद्भुत ट्री व्यू है , एक नियंत्रण जिसे हम सभी इंतजार कर रहे हैं। एक ट्री व्यू एक मॉडल से वस्तुओं के एक पेड़ प्रतिनिधित्व को लागू करता है। सामान्य तौर पर यह अन्य QML विचारों की तरह दिखता है - ListView या TableView । लेकिन ट्री व्यू का डेटा स्ट्रक्चर अधिक जटिल है।

ListView या TableView में एक डेटा नोड्स के एक आयामी सरणी द्वारा दर्शाया गया है। TreeView में प्रत्येक नोड में नोड्स की अपनी सरणी हो सकती है। इसलिए, निर्दिष्ट नोड प्राप्त करने के लिए ट्री व्यू में दूसरों के विचारों के विपरीत, हमें मूल नोड को जानना चाहिए, न कि केवल पंक्ति या स्तंभ का तत्व।

एक और बड़ा अंतर यह है कि TreeView ListModel का समर्थन नहीं करता है। एक डेटा प्रदान करने के लिए हमें QAbstractItemModel को उप-वर्ग करना होगा। Qt में QFileSystemModel जैसी मॉडल कक्षाओं का उपयोग करने के लिए तैयार हैं जो स्थानीय फ़ाइल सिस्टम, या QSqlTableModel तक पहुँच प्रदान करता है जो डेटा बेस तक पहुँच प्रदान करता है।

निम्नलिखित उदाहरण में हम QAbstractItemModel से प्राप्त ऐसे मॉडल का निर्माण करेंगे। लेकिन उदाहरण को और अधिक यथार्थवादी बनाने के लिए मैं मॉडलमॉडल जैसा मॉडल बनाने का सुझाव देता हूं, लेकिन पेड़ों के लिए निर्दिष्ट है ताकि हम क्यूएमएल से नोड्स जोड़ सकें। यह स्पष्ट करना आवश्यक है कि मॉडल में स्वयं कोई डेटा नहीं है, लेकिन केवल उस तक पहुंच प्रदान करता है। इसलिए डेटा प्रदान करना और संगठन बनाना पूरी तरह से हमारी जिम्मेदारी है।

चूंकि मॉडल डेटा को एक पेड़ में सबसे सरल नोड संरचना में आयोजित किया जाता है, इसलिए इसे छद्म कोड में देखा जाता है:

Node {
    var data;
    Node parent;
    list<Node> children;
}

C++ में नोड घोषणा निम्नानुसार होनी चाहिए:

class MyTreeNode : public QObject
{
    Q_OBJECT
public:
    Q_PROPERTY(QQmlListProperty<MyTreeNode> nodes READ nodes)
    Q_CLASSINFO("DefaultProperty", "nodes")
    MyTreeNode(QObject *parent = Q_NULLPTR);

    void setParentNode(MyTreeNode *parent);
    Q_INVOKABLE MyTreeNode *parentNode() const;
    bool insertNode(MyTreeNode *node, int pos = (-1));
    QQmlListProperty<MyTreeNode> nodes();
    
    MyTreeNode *childNode(int index) const;
    void clear();

    Q_INVOKABLE int pos() const;
    Q_INVOKABLE int count() const;

private:
    QList<MyTreeNode *> m_nodes;
    MyTreeNode *m_parentNode;
};

हम से हमारी कक्षा निकाले जाते हैं QObject में एक नोड बनाने के लिए सक्षम होने के लिए QML । सभी बच्चों के नोड्स को nodes संपत्ति में जोड़ा जाएगा ताकि अगले 2 कोड कोड समान हों:

TreeNode {
    nodes:[
        TreeNode {}
        TreeNode {}
    ]
}

TreeNode {
    TreeNode {}
    TreeNode {}
}

डिफ़ॉल्ट संपत्ति के बारे में अधिक जानने के लिए यह एक्टिकल देखें।

नोड वर्ग कार्यान्वयन:

MyTreeNode::MyTreeNode(QObject *parent) :
    QObject(parent),
    m_parentNode(nullptr) {}

void MyTreeNode::setParentNode(MyTreeNode *parent)
{
    m_parentNode = parent;
}

MyTreeNode *MyTreeNode::parentNode() const
{
    return m_parentNode;
}

QQmlListProperty<MyTreeNode> MyTreeNode::nodes()
{
    QQmlListProperty<MyTreeNode> list(this,
                                      0,
                                      &append_element,
                                      &count_element,
                                      &at_element,
                                      &clear_element);
    return list;
}

MyTreeNode *MyTreeNode::childNode(int index) const
{
    if(index < 0 || index >= m_nodes.length())
        return nullptr;
    return m_nodes.at(index);
}

void MyTreeNode::clear()
{
    qDeleteAll(m_nodes);
    m_nodes.clear();
}

bool MyTreeNode::insertNode(MyTreeNode *node, int pos)
{
    if(pos > m_nodes.count())
        return false;
    if(pos < 0)
        pos = m_nodes.count();
    m_nodes.insert(pos, node);
    return true;
}

int MyTreeNode::pos() const
{
    MyTreeNode *parent = parentNode();
    if(parent)
        return parent->m_nodes.indexOf(const_cast<MyTreeNode *>(this));
    return 0;
}

int MyTreeNode::count() const
{
    return m_nodes.size();
}

MyTreeNode *MyTreeModel::getNodeByIndex(const QModelIndex &index)
{
    if(!index.isValid())
        return nullptr;
    return static_cast<MyTreeNode *>(index.internalPointer());
}

QModelIndex MyTreeModel::getIndexByNode(MyTreeNode *node)
{
    QVector<int> positions;
    QModelIndex result;
    if(node) {
        do
        {
            int pos = node->pos();
            positions.append(pos);
            node = node->parentNode();
        } while(node != nullptr);


        for (int i = positions.size() - 2; i >= 0 ; i--)
        {
            result = index(positions[i], 0, result);
        }
    }
    return result;
}

bool MyTreeModel::insertNode(MyTreeNode *childNode, const QModelIndex &parent, int pos)
{
    MyTreeNode *parentElement = getNode(parent);
    if(pos >= parentElement->count())
        return false;
    if(pos < 0)
        pos = parentElement->count();

    childNode->setParentNode(parentElement);
    beginInsertRows(parent, pos, pos);
    bool retValue = parentElement->insertNode(childNode, pos);
    endInsertRows();
    return retValue;
}

MyTreeNode *MyTreeModel::getNode(const QModelIndex &index) const
{
    if(index.isValid())
        return static_cast<MyTreeNode *>(index.internalPointer());
    return m_rootNode;
}

QQmlListProperty के माध्यम से QML के लिए सूची जैसी संपत्ति का खुलासा करने के लिए हमें अगले 4 फ़ंक्शन की आवश्यकता है:

void append_element(QQmlListProperty<MyTreeNode> *property, MyTreeNode *value)
{
    MyTreeNode *parent = (qobject_cast<MyTreeNode *>(property->object));
    value->setParentNode(parent);
    parent->insertNode(value, -1);
}

int count_element(QQmlListProperty<MyTreeNode> *property)
{
    MyTreeNode *parent = (qobject_cast<MyTreeNode *>(property->object));
    return parent->count();
}

MyTreeNode *at_element(QQmlListProperty<MyTreeNode> *property, int index)
{
    MyTreeNode *parent = (qobject_cast<MyTreeNode *>(property->object));
    if(index < 0 || index >= parent->count())
        return nullptr;
    return parent->childNode(index);
}

void clear_element(QQmlListProperty<MyTreeNode> *property)
{
    MyTreeNode *parent = (qobject_cast<MyTreeNode *>(property->object));
    parent->clear();
}

अब हम मॉडल वर्ग की घोषणा करते हैं:

class MyTreeModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    Q_PROPERTY(QQmlListProperty<MyTreeNode> nodes READ nodes)
    Q_PROPERTY(QVariantList roles READ roles WRITE setRoles NOTIFY rolesChanged)
    Q_CLASSINFO("DefaultProperty", "nodes")

    MyTreeModel(QObject *parent = Q_NULLPTR);
    ~MyTreeModel();

    QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE;
    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
    Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
    QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
    int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
    int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
    QQmlListProperty<MyTreeNode> nodes();

    QVariantList roles() const;
    void setRoles(const QVariantList &roles);

    Q_INVOKABLE MyTreeNode * getNodeByIndex(const QModelIndex &index);
    Q_INVOKABLE QModelIndex getIndexByNode(MyTreeNode *node);
    Q_INVOKABLE bool insertNode(MyTreeNode *childNode, const QModelIndex &parent = QModelIndex(), int pos = (-1));

protected:
    MyTreeNode *getNode(const QModelIndex &index) const;

private:
    MyTreeNode *m_rootNode;
    QHash<int, QByteArray> m_roles;

signals:
    void rolesChanged();
};

चूंकि हम अमूर्त QAbstractItemModel से मॉडल वर्ग प्राप्त करते हैं, इसलिए हमें अगले फ़ंक्शन: डेटा () , फ़्लैग () , इंडेक्स () , पैरेंट () , कॉलमकाउंट () और rowCount () को फिर से परिभाषित करना होगा। हमारे मॉडल QML साथ काम कर सकते हैं हम रोलनेम () को परिभाषित करते हैं। इसके अलावा, साथ ही नोड क्लास में हम QML में मॉडल में नोड्स जोड़ने में सक्षम होने के लिए डिफ़ॉल्ट संपत्ति को परिभाषित करते हैं। roles संपत्ति भूमिका नामों की एक सूची रखेगी।

कार्यान्वयन:

MyTreeModel::MyTreeModel(QObject *parent) :
    QAbstractItemModel(parent)
{
    m_rootNode = new MyTreeNode(nullptr);
}
MyTreeModel::~MyTreeModel()
{
    delete m_rootNode;
}

QHash<int, QByteArray> MyTreeModel::roleNames() const
{
    return m_roles;
}

QVariant MyTreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    MyTreeNode *item = static_cast<MyTreeNode*>(index.internalPointer());
    QByteArray roleName = m_roles[role];
    QVariant name = item->property(roleName.data());
    return name;
}

Qt::ItemFlags MyTreeModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    return QAbstractItemModel::flags(index);
}

QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    MyTreeNode *parentItem = getNode(parent);
    MyTreeNode *childItem = parentItem->childNode(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex MyTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    MyTreeNode *childItem = static_cast<MyTreeNode*>(index.internalPointer());
    MyTreeNode *parentItem = static_cast<MyTreeNode *>(childItem->parentNode());

    if (parentItem == m_rootNode)
        return QModelIndex();

    return createIndex(parentItem->pos(), 0, parentItem);
}

int MyTreeModel::rowCount(const QModelIndex &parent) const
{
    if (parent.column() > 0)
        return 0;
    MyTreeNode *parentItem = getNode(parent);
    return parentItem->count();
}

int MyTreeModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 1;
}

QQmlListProperty<MyTreeNode> MyTreeModel::nodes()
{
    return m_rootNode->nodes();
}

QVariantList MyTreeModel::roles() const
{
    QVariantList list;
    QHashIterator<int, QByteArray> i(m_roles);
    while (i.hasNext()) {
        i.next();
        list.append(i.value());
    }

    return list;
}

void MyTreeModel::setRoles(const QVariantList &roles)
{
    static int nextRole = Qt::UserRole + 1;
    foreach(auto role, roles) {
        m_roles.insert(nextRole, role.toByteArray());
        nextRole ++;
    }
}

MyTreeNode *MyTreeModel::getNodeByIndex(const QModelIndex &index)
{
    if(!index.isValid())
        return nullptr;
    return static_cast<MyTreeNode *>(index.internalPointer());
}

QModelIndex MyTreeModel::getIndexByNode(MyTreeNode *node)
{
    QVector<int> positions;
    QModelIndex result;
    if(node) {
        do
        {
            int pos = node->pos();
            positions.append(pos);
            node = node->parentNode();
        } while(node != nullptr);


        for (int i = positions.size() - 2; i >= 0 ; i--)
        {
            result = index(positions[i], 0, result);
        }
    }
    return result;
}


bool MyTreeModel::insertNode(MyTreeNode *childNode, const QModelIndex &parent, int pos)
{
    MyTreeNode *parentElement = getNode(parent);
    if(pos >= parentElement->count())
        return false;
    if(pos < 0)
        pos = parentElement->count();

    childNode->setParentNode(parentElement);
    beginInsertRows(parent, pos, pos);
    bool retValue = parentElement->insertNode(childNode, pos);
    endInsertRows();
    return retValue;
}

MyTreeNode *MyTreeModel::getNode(const QModelIndex &index) const
{
    if(index.isValid())
        return static_cast<MyTreeNode *>(index.internalPointer());
    return m_rootNode;
}

सामान्य तौर पर, यह कोड मानक कार्यान्वयन से बहुत अलग नहीं है, उदाहरण के लिए सरल पेड़ उदाहरण

C++ में भूमिकाओं को परिभाषित करने के बजाय हम QML से ऐसा करने का एक तरीका प्रदान करते हैं। ट्री व्यू इवेंट और तरीके मूल रूप से QModelIndex के साथ काम करते हैं। मैं व्यक्तिगत रूप से उस को qml पास करने के लिए ज्यादा समझदारी नहीं देखता, केवल एक चीज जो आप इसके साथ कर सकते हैं वह है इसे वापस मॉडल में पास करना।

वैसे भी, हमारी कक्षा सूचकांक को नोड और इसके विपरीत में परिवर्तित करने का एक तरीका प्रदान करती है। QML में अपनी कक्षाओं का उपयोग करने में सक्षम होने के लिए हमें इसे पंजीकृत करना होगा:

qmlRegisterType<MyTreeModel>("qt.test", 1, 0, "TreeModel");
qmlRegisterType<MyTreeNode>("qt.test", 1, 0, "TreeElement");

और समापन, उदाहरण के लिए कि हम QML में QML साथ अपने मॉडल का उपयोग कैसे कर सकते हैं:

import QtQuick 2.7
import QtQuick.Window 2.2    
import QtQuick.Dialogs 1.2
import qt.test 1.0


Window {
    visible: true
    width: 800
    height: 800
    title: qsTr("Tree example")

    Component {
        id: fakePlace
        TreeElement {
            property string name: getFakePlaceName()
            property string population: getFakePopulation()
            property string type: "Fake place"
            function getFakePlaceName() {
                var rez = "";
                for(var i = 0;i < Math.round(3 + Math.random() * 7);i ++) {
                    rez += String.fromCharCode(97 + Math.round(Math.random() * 25));
                }
                return rez.charAt(0).toUpperCase() + rez.slice(1);
            }
            function getFakePopulation() {
                var num = Math.round(Math.random() * 100000000);
                num = num.toString().split("").reverse().join("");
                num = num.replace(/(\d{3})/g, '$1,');
                num = num.split("").reverse().join("");
                return num[0] === ',' ? num.slice(1) : num;
            }
        }
    }

    TreeModel {
        id: treemodel
        roles: ["name","population"]

        TreeElement {
            property string name: "Asia"
            property string population: "4,164,252,000"
            property string type: "Continent"
            TreeElement {
                property string name: "China";
                property string population: "1,343,239,923"
                property string type: "Country"
                TreeElement { property string name: "Shanghai"; property string population: "20,217,700"; property string type: "City" }
                TreeElement { property string name: "Beijing"; property string population: "16,446,900"; property string type: "City" }
                TreeElement { property string name: "Chongqing"; property string population: "11,871,200"; property string type: "City" }
            }
            TreeElement {
                property string name: "India";
                property string population: "1,210,193,422"
                property string type: "Country"
                TreeElement { property string name: "Mumbai"; property string population: "12,478,447"; property string type: "City" }
                TreeElement { property string name: "Delhi"; property string population: "11,007,835"; property string type: "City" }
                TreeElement { property string name: "Bengaluru"; property string population: "8,425,970"; property string type: "City" }
            }
            TreeElement {
                property string name: "Indonesia";
                property string population: "248,645,008"
                property string type: "Country"
                TreeElement {property string name: "Jakarta"; property string population: "9,588,198"; property string type: "City" }
                TreeElement {property string name: "Surabaya"; property string population: "2,765,487"; property string type: "City" }
                TreeElement {property string name: "Bandung"; property string population: "2,394,873"; property string type: "City" }
            }
        }
        TreeElement { property string name: "Africa"; property string population: "1,022,234,000"; property string type: "Continent" }
        TreeElement { property string name: "North America"; property string population: "542,056,000"; property string type: "Continent" }
        TreeElement { property string name: "South America"; property string population: "392,555,000"; property string type: "Continent" }
        TreeElement { property string name: "Antarctica"; property string population: "4,490"; property string type: "Continent" }
        TreeElement { property string name: "Europe"; property string population: "738,199,000"; property string type: "Continent" }
        TreeElement { property string name: "Australia"; property string population: "29,127,000"; property string type: "Continent" }
    }

    TreeView {
        anchors.fill: parent
        model: treemodel
        TableViewColumn {
            title: "Name"
            role: "name"
            width: 200
        }
        TableViewColumn {
            title: "Population"
            role: "population"
            width: 200
        }

        onDoubleClicked: {
            var element = fakePlace.createObject(treemodel);
            treemodel.insertNode(element, index, -1);
        }
        onPressAndHold: {
            var element = treemodel.getNodeByIndex(index);
            messageDialog.text = element.type + ": " + element.name + "\nPopulation: " + element.population;
            messageDialog.open();
        }
    }
    MessageDialog {
          id: messageDialog
          title: "Info"
      }
}

एक नोड जोड़ने के लिए डबल क्लिक करें, नोड जानकारी के लिए दबाए रखें।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow