QML and C + + data binding __c++

Source: Internet
Author: User
QML and C + + data bindingSCP020 2018.02.01 11:51 Word 1337

References: Exposing Attributes of C + + Types to QML overview-qml and C + + Integration embedding C + + Objects into QML with Conte XT Properties

Referring to the View-model model, QML as the object in view,c++ as model, to realize the separation of business logic and interface. exposing properties of a single C + + class

In this way, QML can directly access the C + + class instance registered to the context, and is registered to the QML Global (specifically registered to a Qquickview or engine). To customize a Name class, the class includes a data property for example. class definition

Classes that need to be exposed to QML access need to have a special definition:

/*name.h*/
#include <QObject>

class Name:public QObject//inherit from QObject
{
    q_object//qobject macros
    q_property (QString data READ data WRITE setData NOTIFY datachanged) public
:
    Name (QObject *parent = nullptr) ;//default constructor
    Name (QString _name);//constructor

    QString data () Const;//read interface
    void SetData (const qstring& _data );//write interface

signals:
    QString datachanged ()//notify signal (without implementation)

private:
    QString m_data;//Private properties
};

You can add new classes, inherit from QObject, and automatically add files to your project by right-clicking the project-> new file->c++ class.

Warning: Do not define classes directly in CPP files, because Q_object macros need to be MOC processed, non. h files will not be MOC processed, "Unrecognized symbols" error occurs at compile time

Q_property (QString data READ data WRITE setData NOTIFY datachanged)

This line of code defines the interface that is exposed to QML access, where we provide a qstring,read interface is a function named data, the WRITE interface is a function called SetData, NOTIFY interface is used to notify the binding, only set the NOTIFY , QML can automatically synchronize with attributes in C + +. The naming method here is best with the default unification. class implements

/*name.cpp*/
#include "name.h"

name::name (QObject *parent): QObject (parent)
{//default constructor
}

name: : Name (QString _data): M_data (_data)
{//custom constructor, initializing private object M_data
}

QString Name::d ata () const
{
    Return M_data;//read interface Implementation, returns private object
}

void Name::setdata (const qstring& _data)
{
    if (_data!= m_ Data) {//write interface implementation, update m_data and emit signal
        m_data = _data;
        Emit datachanged ();
    }

In SetData, it is necessary to determine whether the data is updated, and only when the data is truly changed will the signal be issued, otherwise there is the risk of infinite recursion. Register to context

It then instantiates a Name class and registers it with the context. Registration needs to be completed before the. qml file is read.

/*main.cpp*/
Name a_name ("test");

Qqmlapplicationengine engine;
qqmlcontext* Rootcontex = Engine.rootcontext ()//Get engine root context
Rootcontex->setcontextproperty ("name",  Qvariant::fromvalue (A_name));//Registered
Engine.load (Qurl (qstringliteral ("qrc:/main.qml"));

Read in QML

QML can read properties returned by the interface, assign values directly to attributes, and monitor property changes.

/*main.qml*/
Rectangle {
    Text {
        text:name.data//is equivalent to calling Name.data () this interface

        connections {// Establish a connection to the Notify interface
            target:name
            ondatachanged:{//corresponding notify interface
                Console.log ("Data has beed changed!");
            }
    }

    button {
        text: ' Changedata '
        onclicked: {
            name.data = ' haschanged! ';
        }
}}

When the button is clicked, the text will change, while the console output "data has Beed changed!", closed loop reached.
Connections is used to listen for events, and the listener's target is the object that defines NOTIFY (note ondatachanged The name of the hump and original NOTIFY definitions of this event handler. use qlist as Model

A more common requirement is to expose the attributes of a set of objects and to move the rendering through the View in QML. For example, we put the Name class into a qlist list and pass the Model to the ListView in QML.

/*main.cpp*/qlist<qobject*> NameList;
Namelist.append (New Name ("name1"));
Namelist.append (new name ("Name2"))//Adds two name objects Qqmlapplicationengine engine in the array;  qqmlcontext* Rootcontex = Engine.rootcontext ()//Get engine root context rootcontex->setcontextproperty ("NameList",
Qvariant::fromvalue (NameList));//Registered Engine.load (Qurl (qstringliteral ("qrc:/main.qml")); 
/*main.qml*/
listview{
    width:parent.width
    height:300
    model:namelist
    delegate:rectangle {
        height:30
        width:parent.width
        color: "#000000"
        Text {
            text:model.data//Call each object's data () method
            Color: "#FFFFFF"
            connections{
                Target:model//Monitor This object
                ondatachanged:{
                    console.log ("changed!");
                }
            }
        }
    }
}

So you get a list rendering. The rendered list is already determined when it is registered to the context, and the list item name dynamic changes are reflected in the interface, but the dynamic additions and deletions of the array elements do not change (because the qlist itself does not have a NOTIFY interface). register type into QML context

The current Name class is fully implemented with interfaces registered to the QML context, so it can be invoked in C + +

Qmlregistertype<name> ("Com.myapp.name", 1, 0, "Name");
Package name, large version number, minor version number, type name

To register, you can use the Name class and its properties directly after you add a reference to the QML file.

Import Com.myapp.name 1.0

name {
    data: "Foo"
}
encapsulates a set of data exposed to QML

Unlike the direct placement of qlist, dynamically bound list rendering can be achieved through a more advanced encapsulation. Avoid using the Qqmllistproperty method, documentation is problematic and the relevant information is less
Reference Qabstractitemmodel Qabstractlistmodel Model View interpretation linear table encapsulated as abstract list type

Simple C + + linear table type (array or Vector template class, etc.) can be directly accessed by QML Model by encapsulation. The encapsulated class can be inherited from Qabstractlistmodel or more complex qabstracttablemodel. The key is to implement several virtual functions as QML calling interfaces (complete virtual function table reference documents) after inheritance:

/* must implement the virtual function */
int rowcount (const qmodelindex &parent) const;//Returns the number of rows
qvariant data (const QMODELINDEX & index, int role) const;//returns the data qhash<int based on the index and role requests
, qbytearray> rolenames ()  const;//returns the data alias

More complex, QML-oriented functionality can be accomplished by implementing more virtual functions. abstract type definition

Assuming that we have a qlist inside each element is a name type, notice that name has completed the encapsulation necessary for QML access. So a class of the Name-type linear table that can be rendered in QML should be as long as this:

/*namelist.h*/#include <QAbstractListModel> #include <QVariant> #include <QDebug> #include "name.h
    "Class Namelist:public Qabstractlistmodel {q_object public:enum datatype {type1 = 0};"
    NameList (QObject *parent);
        NameList () {addname ("test1");
    AddName ("Test2"); /* * The virtual function that must be implemented for the QML engine to invoke/INT rowcount (const qmodelindex &parent) const;//Return the data row number Qvariant (const Qmodel
    Index &index, int role) const;//returns the desired data qhash<int, qbytearray> rolenames () const;//return Data alias/* Other interface * *

q_invokable bool Pushdata (QString a_name);
private:qlist<name*> _namelist;//encapsulated Array}; 

The

First class has an enumerated type, each of which corresponds to a property accessed in the data item. The Name class has only one data property, so only one type is defined. The
is then rowcount (const Qmodelindex &parent), which gets the number of list items by the QML engine when querying the list.
Qvariant data (const QMODELINDEX &index, int role) is the interface that the QML engine uses to access each list item, and the access is indexed by index, Role indicates the property of the lookup (corresponding to the enumeration type datatype).
Qhash<int, qbytearray> rolenames () returns the alias for role (temporarily not particularly important). abstract Type Implementation

/*namelist.cpp*/#include <QQmlListProperty> #include <QList> #include "namelist.h" namelist::namelist ( QObject *parent) {} int namelist::rowcount (const qmodelindex &parent) Const {return _namelist.count ();//Returns the number of private lists
    According to the volume} qvariant namelist::d ata (const qmodelindex &index, int role) const {QDEBUG () << role;

int row = Index.row ();//index contains. Row () and. Count (), and so on property return Qvariant::fromvalue (_namelist.at (row));//data items wrapped into qvariant returns}
    Qhash<int, qbytearray> namelist::rolenames () const {qhash<int, qbytearray> D;
D[datatype::type1] = "Foo";//to Tpye1 set alias return D;
    BOOL NameList::p ushdata (QString a_name) {name* cache = new name (a_name);
    Begininsertrows (Qmodelindex (), _namelist.count (), _namelist.count ());
    _namelist.append (cache);
    Endinsertrows ();
return true;
 }

After the list is encapsulated, you need to First call begininsertrows (qmodelindex, int, int), the first parameter corresponding to model data, through the Qmodelindex () to get the model of the virtual Rootitem ; the latter two parameters represent the range of rows changed: for example, by adding 3 data to the second row, the two parameters are \ ((2, 4) \). Call Endinsertrows () after the modification is complete. Register to context

/*main.cpp*/
NameList thelist;//Instantiate a class of

qqmlapplicationengine engine;
qqmlcontext* Rootcontex = Engine.rootcontext ();
Rootcontex->setcontextproperty ("NameList", &thelist);//Register to Context Engine.load Qurl (qstringliteral (
"qrc:/ Main.qml "));
Read in QML
/*main.qml*/listview{width:parent.width height:300 model:namelist//Take abstract classes as model Delegate:rectangle {height:30 width:parent.width color: "#999999" Text {text:model.modelData
            . Name//name is the property of each item color: "#FFFFFF"} button {Anchors.right:parent.right
            Width:50 height:30 font.family: "Fontawesome" font.pixelsize:24
            Text: "\uf019" onclicked: {model.modelData.name = textfield.text;//can modify attributes directly to item }
        }
    }
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.