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 }
}
}
}