QML and C ++ Data Binding tutorials and qml binding tutorials

Source: Internet
Author: User
Tags custom name

QML and C ++ Data Binding tutorials and qml binding tutorials
QML and C ++ Data Binding tutorial

Use the View-Model, QML as the View, and objects in C ++ as the Model to separate the business logic from the interface.

Expose attributes of a single C ++ class

In this way, QML can directly access the C ++ class instance registered in the context and register it to the global QML (specifically to register a QQuickView or engine ). Use a custom Name class, which includes a data attribute as an example.

Class Definition

Classes that need to be exposed to QML access need to have special definitions:

/* Name. h */# include
 
  
Class Name: public QObject // inherited from QObject {Q_OBJECT // QObject macro Q_PROPERTY (QString data READ data WRITE setData permission y 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 (not required) private: QString m_data; // private Attribute };
 

You can right-click the project and choose Create File> C ++ Class to add a new Class, inherit from the QObject, and automatically add the file to the project.

Warning: do not define classes directly in the cpp file. Because the Q_OBJECT macro must be processed by moc, non-. H files are not processed by moc, and the "unrecognizable symbol" error occurs during compilation.

Q_PROPERTY(QString data READ data WRITE setData NOTIFY dataChanged)

This line of code defines the interface exposed to QML access. The object we provide here is a QString, the READ interface is a function named data, and the WRITE interface is a function named setData, the NOTIFY interface is used to bind notifications. Only when the NOTIFY interface is set can QML automatically synchronize with properties in C ++. The naming method here should be consistent with the default one.

Class implementation
/* Name. cpp */# include "name. h "Name: Name (QObject * parent): QObject (parent) {// default constructor} Name: Name (QString _ data): m_data (_ data) {// custom constructor, initialize private object m_data} QString Name: data () const {return m_data; // READ interface implementation, return private object} void Name :: setData (const QString & _ data) {if (_ data! = M_data) {// WRITE interface implementation, update m_data and send the signal m_data = _ data; emit dataChanged ();}}

In setData, you must determine whether the data is updated. The signal is sent only when the data actually changes. Otherwise, there is an infinite recursion risk.

Register to context

A Name class is instantiated and registered to the context. Registration must be completed before the. qml file is read.

/* Main. cpp */Name a_name ("test"); QQmlApplicationEngine; QQmlContext * rootContex = engine. rootContext (); // get the engine's root context rootContex-> setContextProperty ("name", QVariant: fromValue (a_name); // register the engine. load (QUrl (QStringLiteral ("qrc:/main. qml ")));
Read in QML

QML can read the attributes returned by the interface, assign values to the attributes directly, and listen to attribute changes.

/* Main. qml */Rectangle {Text {text: name. data // call name. data () This interface Connections {// establish a connection to the NOTIFY interface target: name onDataChanged: {// corresponds to the NOTIFY interface console. log ("data has beed changed! ") ;}} Button {text:" changeData "onClicked: {name. data =" hasChanged! ";}}}

When you click the button, the Text of the Text changes, and the console outputs "data has beed changed !", Closed-Loop fulfillment.

Connections is used to listen to events. The target of the listener is the object that defines NOTIFY (note the name of onDataChanged event handler during the hump naming method and the name of the original NOTIFY definition.

Use QList as Model

A more common requirement is to expose the attributes of a group of objects and automatically render them through views in QML. For example, we put the Name class into a QList list and pass it as a Model to the ListView in QML.

/* Main. cpp */QList
 
  
NameList; NameList. append (new Name ("name1"); NameList. append (new Name ("name2"); // Add two Name objects in the array: QQmlApplicationEngine engine; QQmlContext * rootContex = engine. rootContext (); // get the engine's root context rootContex-> setContextProperty ("nameList", QVariant: fromValue (NameList); // register the 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 the data () method of each object color: "# FFFFFF" Connections {target: model // listen to this object onDataChanged: {console. log ("changed! ");}}}}}

In this way, a list rendering is obtained. The rendered list is determined when it is registered to the context. The dynamic modification of the list item Name will be reflected on the interface, however, the dynamic addition and deletion of array elements will not change (because the QList itself does not have the NOTIFY interface ).

Register the type in the QML Context

The current Name class has fully implemented the interface registered to the QML context, so it can be called in C ++

QmlRegisterType
 
  
("Com. myapp. name", 1, 0, "Name"); // package name, major version number, minor version number, type Name
 

After adding a reference to the QML file, you can directly use the Name class and its attributes.

import com.myapp.name 1.0Name {    data: "Foo"}
Encapsulate a set of data exposed to QML

Different from directly placing a QList, you can use more advanced encapsulation to dynamically bind a list for rendering. Avoid using the QQmlListProperty method. If there is a problem with the documentation and there is less relevant information

Linear table encapsulated as abstract list type

Simple C ++ linear table types (arrays or Vector Template classes) can be directly accessed by QML through encapsulation. The encapsulated class can be inherited from qiniactlistmodel or more complex qiniacttablemodel. The key lies in the implementation of several virtual functions as the QML call interface after inheritance (complete virtual function table reference document ):

/* Required virtual functions */int rowCount (const QModelIndex & parent) const; // number of returned data rows QVariant data (const QModelIndex & index, int role) const; // return the QHash data requested by index and role.
 
  
RoleNames () const; // returns the data alias
 

By implementing more virtual functions, you can complete more complex QML-oriented functions.

Abstract Type Definition

Assume that each element in a QList is of the Name type. Note that Name has completed the encapsulation required for QML access. Therefore, the length of a Name-Type Linear table encapsulated into a class in QML should be as follows:

/* Namelist. h */# include
 
  
# Include
  
   
# Include
   
    
# Include "name. h "class NameList: public q1_actlistmodel {Q_OBJECTpublic: enum datatype {type1 = 0}; NameList (QObject * parent); NameList () {addName (" test1 "); addName ("test2");}/* required virtual functions for the QML engine to call */int rowCount (const QModelIndex & parent) const; // return the number of data rows QVariant data (const QModelIndex & index, int role) const; // return the QHash of the expected data
    
     
RoleNames () const; // returns the data alias/* Other interfaces */Q_INVOKABLE bool pushData (QString a_name); private: QList
     
      
_ NameList; // encapsulated array };
     
    
   
  
 

First, an enumeration type is defined in the class. Each type corresponds to an attribute accessed in the data item. The Name class has only one data attribute, so only one type is defined.

Then there is rowCount (const QModelIndex & parent). This function is used to obtain the number of list items when the QML engine queries the list.

QVariant data (const QModelIndex & index, int role) is an interface used by the QML engine to access each list item. The index indicates the index during access, role indicates the property to be searched (corresponding to the enumerated type datatype ).

QHash RoleNames () returns the role alias (not particularly important at the moment ).

Abstract type implementation
/* Namelist. cpp */# include
 
  
# Include
  
   
# Include "namelist. h "NameList: NameList (QObject * parent) {} int NameList: rowCount (const QModelIndex & parent) const {return _ NameList. count (); // returned data volume in the private list} QVariant NameList: data (const QModelIndex & index, int role) const {qDebug () <role; int row = index. row (); // index contains. row () and. return QVariant: fromValue (_ NameList. at (row); // data items packaged into QVariant return} QHash
   
    
NameList: roleNames () const {QHash
    
     
D; d [datatype: type1] = "Foo"; // set the alias return d For tpye1;} bool NameList: pushData (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 must call beginInsertRows (QModelIndex, int, int) before adding or deleting the list. The first parameter corresponds to the Model data and the virtual rootItem of the Model is obtained through QModelIndex; the last two parameters represent the range of modified rows. For example, if three data entries are added to the second row, the two parameters are \ (2, 4 )\). after the modification, you must call endInsertRows () to complete the modification.

Register to context
/* Main. cpp */NameList theList; // instantiate a class QQmlApplicationEngine; QQmlContext * rootContex = engine. rootContext (); rootContex-> setContextProperty ("namelist", & theList); // register with the context engine. load (QUrl (QStringLiteral ("qrc:/main. qml ")));
Read in QML
/* Main. qml */ListView {width: parent. width height: 300 model: namelist // use the abstract class as model delegate: Rectangle {height: 30 width: parent. width color: "#999999" Text {text: model. modelData. name // name is the attribute color of each item: "# FFFFFF"} Button {anchors. right: parent. right width: 50 height: 30 font. family: "FontAwesome" font. pixelSize: 24 text: "\ uf019" onClicked: {model. modelData. name = textField. text; // attributes can be directly modified for the item }}}}

Related Article

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.