第二卷如何更快速的放棄,注重的是C++和QML的交互
<1>記事本。。
(1) 先測試下不在QML創建C++對象,僅僅在main.cpp添加一個屬性函數供調用. 注意只使用槽函數來做到。
TextStreamLoader.h

#ifndef TEXTSTREAMLOADER_H #define TEXTSTREAMLOADER_H #include <QObject> #include <QTextStream> #include <QDebug> class TextStreamLoader : public QObject { Q_OBJECT public: explicit TextStreamLoader(QObject *parent = 0); void test2(){qDebug()<<"test 2 without slots";} signals: void signal_readFile(QString buffer); void signal_error(QString errorMsg); void signal_saveFile(QString file,QString buffer); public slots: void slot_readFile(QString file); void slot_saveFile(QString file,QString buffer); void slot_test(){qDebug() << "test C++";} QString slot_getBuffer(); private: QString _buffer; }; #endif // TEXTSTREAMLOADER_H
TextStreamLoader.cpp

#include "TextStreamLoader.h" #include <QFile> #include <QUrl> TextStreamLoader::TextStreamLoader(QObject *parent) : QObject(parent) { qDebug() << "Construct the TextStreamLoader"; connect(this,&TextStreamLoader::signal_saveFile, this,&TextStreamLoader::slot_saveFile); } void TextStreamLoader::slot_readFile(QString file) // read a file to the _buffer { QUrl url(file); QString localFile = url.toLocalFile(); QFile rfile(localFile); if(!rfile.open(QIODevice::ReadOnly)) { QString errorMsg = "Could not open " + file + "\n"; qDebug() << errorMsg; emit signal_error(errorMsg); return ; } QTextStream in(&rfile); _buffer = in.readAll(); emit signal_readFile(_buffer); rfile.close(); } void TextStreamLoader::slot_saveFile(QString file, QString buffer) { QUrl url(file); QString localFile = url.toLocalFile(); QFile wfile(localFile); if(!wfile.open(QFile::WriteOnly)) { QString errorMsg = "Could not open " + localFile + "\n"; qDebug() <<errorMsg; emit signal_error(errorMsg); return ; } QTextStream out(&wfile); out << buffer; wfile.close(); } QString TextStreamLoader::slot_getBuffer() { return _buffer; }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "TextStreamLoader.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QQmlContext *context = engine.rootContext(); // 注意對象是在C++里構建 TextStreamLoader stream_01; context->setContextProperty("stream_01",&stream_01); // 構建完C++對象 // 加載我們的QML界面,只能調用槽函數 qDebug() << "load the main.qml"; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); qDebug() <<engine.rootObjects()[0]->objectName(); // this will be debug "Houdini" return app.exec(); }
main.qml 用最簡單的測試下我們的TextStreamLoader 里面的 "test()槽函數",一定要是槽函數才能被調用。
main.qml全部都是通過調用C++的對象的槽函數,而C++對象是在main.cpp創建,所以在qml隨時可以訪問 槽函數。

import QtQuick 2.6 import QtQuick.Window 2.2 import QtQuick.Controls 2.1 import QtQuick.Dialogs 1.2 Window { id:root objectName: "Houdini" visible: true width: 640 height: 480 title: qsTr("Hello World") color:"#202020" function loadTextToTextEdit(text) { textEdit.clear() var buffer = stream_01.slot_getBuffer() textEdit.append(buffer) } function saveTextToDisk(file,buffer) { stream_01.slot_saveFile(file,buffer) } Column { id:mainLayout padding: 5 spacing: 10 Row { id:buttonLayout spacing: 10 Button { id:loadButton text:"load file" highlighted: true onClicked: { openDialog.open() } } Button { id:saveButton highlighted: true text:"save file" onClicked: { saveDialog.open() } } } Rectangle { height: 1 width: root.width id:menuRect color:"brown" } Flickable { id:flick width: root.width; height: root.height; contentWidth: textEdit.paintedWidth contentHeight: textEdit.paintedHeight clip: true function ensureVisible(r) { if (contentX >= r.x) contentX = r.x; else if (contentX+width <= r.x+r.width) contentX = r.x+r.width-width; if (contentY >= r.y) contentY = r.y; else if (contentY+height <= r.y+r.height) contentY = r.y+r.height-height; } TextEdit { width: flick.width height: flick.height anchors.margins: 10 focus: true id:textEdit text: "" color:"brown" font.family: "Helvetica" font.pointSize: 10 font.bold: true cursorVisible: true selectByKeyboard: true selectByMouse: true wrapMode:TextEdit.WrapAnywhere onCursorRectangleChanged: flick.ensureVisible(cursorRectangle) } } } FileDialog { id:openDialog title: "Please choose a file" folder: shortcuts.home onAccepted: { console.log("You chose: " + openDialog.fileUrls) stream_01.slot_readFile(openDialog.fileUrls) var buffer = stream_01.slot_getBuffer() loadTextToTextEdit(buffer) } onRejected: { console.log("Canceled") } } FileDialog { id:saveDialog title:"Save to a file" folder: shortcuts.home selectExisting : false onAccepted: { console.log("Save file : " + saveDialog.fileUrls) var text = textEdit.text; saveTextToDisk(saveDialog.fileUrl,text); } onRejected: { console.log("Canceled") } } }
(2)
這次變化使用了QML里的connections.
可以調用C++里的signal,signal帶參數也可以傳遞過來。注意查看新的main.qml
代碼區別就是讀取用的C++信號讀取的。
保存時用的信號在QML發射,然后調用C++的信號槽鏈接,來執行slot_saveFile()函數。
main.qml:

import QtQuick 2.6 import QtQuick.Window 2.2 import QtQuick.Controls 2.1 import QtQuick.Dialogs 1.2 Window { id:root objectName: "Houdini" visible: true width: 640 height: 480 title: qsTr("Hello World") color:"#202020" function loadTextToTextEdit(text) { textEdit.clear() var buffer = stream_01.slot_getBuffer() textEdit.append(buffer) } function saveTextToDisk(file,buffer) { stream_01.slot_saveFile(file,buffer) } Column { id:mainLayout padding: 5 spacing: 10 Row { id:buttonLayout spacing: 10 Button { id:loadButton text:"load file" highlighted: true onClicked: { openDialog.open() } } Button { id:saveButton highlighted: true text:"save file" onClicked: { saveDialog.open() } } } Rectangle { height: 1 width: root.width id:menuRect color:"brown" } Flickable { id:flick width: root.width; height: root.height; contentWidth: textEdit.paintedWidth contentHeight: textEdit.paintedHeight clip: true function ensureVisible(r) { if (contentX >= r.x) contentX = r.x; else if (contentX+width <= r.x+r.width) contentX = r.x+r.width-width; if (contentY >= r.y) contentY = r.y; else if (contentY+height <= r.y+r.height) contentY = r.y+r.height-height; } TextEdit { width: flick.width height: flick.height anchors.margins: 10 focus: true id:textEdit text: "" color:"brown" font.family: "Helvetica" font.pointSize: 10 font.bold: true cursorVisible: true selectByKeyboard: true selectByMouse: true wrapMode:TextEdit.WrapAnywhere onCursorRectangleChanged: flick.ensureVisible(cursorRectangle) } } } Connections { target: stream_01 onSignal_readFile://當讀取文件的時候回觸發這個信號 { var readText = buffer //buffer是signal_readFile(buffer)參數 textEdit.clear() textEdit.append(readText) } } // 讀取文件的窗口 FileDialog { id:openDialog title: "Please choose a file" folder: shortcuts.home onAccepted: { console.log("You chose: " + openDialog.fileUrl) //這句話會觸發signal_readFile信號 stream_01.slot_readFile(openDialog.fileUrl) } onRejected: { console.log("Canceled") } } //保存文件窗口 FileDialog { id:saveDialog title:"Save to a file" folder: shortcuts.home selectExisting : false onAccepted: { console.log("Save file : " + saveDialog.fileUrl) var text = textEdit.text; //保存觸發信號,在C++中這個信號會觸發保存 stream_01.signal_saveFile(saveDialog.fileUrl,text) } onRejected: { console.log("Canceled") } } }
(3)Q_PROPERTY宏,如果你想暴露一些member給QML對象。
Q_OBJECT Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged) public: QString message(){return _msg;} void setMessage(QString msg)
{
_msg = msg;
emit messageChanged();
}
類型如下:
Q_PROPERTY(任意類型 QML訪問屬性名 READ 讀取函數名 WRITE 寫的函數名 NOTIFY 信號觸發)
<2>Q_INVOKABLE 宏,讓QML可以隨心所以調用函數。跟槽槽函數,信號一樣調用。
<3>在C++修改QML對象的屬性,從C++call javaScript
(1)修改qml root object的對象屬性

qDebug() <<engine.rootObjects()[0]->objectName(); // this will be debug "Houdini" QObject *root_object = engine.rootObjects().value(0); // houdini object ,it's the main object // set QML object property //root_object->setProperty("x",600); QQmlProperty::write(root_object, "x", 600); // read QML object property qDebug() << root_object->property("x").toInt(); qDebug() << QQmlProperty::read(root_object,"x").toInt(); // read root object child by name //QObject *rect = root_object->findChild<QObject*>("rect");
(2) 假如qml root object 有個java函數:
function javefunctest(arg) { console.log(arg); return "I'm jave script" }
C++訪問:
QObject *root_object = engine.rootObjects().value(0); // houdini object ,it's the main object QVariant firstArg("I am C++ arg"); QVariant retValue; // call the jave script QMetaObject::invokeMethod(root_object, "javefunctest", Q_RETURN_ARG(QVariant,retValue), Q_ARG(QVariant,firstArg)); qDebug() << "ret value is " << retValue;
輸出:
qml: I am C++ arg
ret value is QVariant(QString, "I'm java script")
<4> EMCA:
(1) 基本類型

var flag =false //a boolean var x =1,y=2 var str = 'abc' / "abc" var test = {x:2,y:3} console.log(test.x) //2 console.log(test.y) //3 test// object (1) typeof()類型 關鍵字 To query the type of a variable, use the typeof keyword. typeof returns the name of the type as a string. var x=1; typeof(x) //"number" typeof {x:1} //'object ' typeof typeof { x : 1 } // ’string’ 因為typeof()返回的是字符串. (2) 轉換類型 1.3333333.toFixed(2) // ’1.33’ 7..toString() // ’7’ (3) 可以顯式的把boolean ,number,string轉換成對象: typeof 1. // ’number’ typeof new Number(1.) // ’object’ typeof new String(’Hi!’) // ’object’ (4) Objects themselves can be expressed using an array or object literal. Arrays have no separate type, but are specialized objects which use array indexes as properties: var o = { name: ’Werner’, age: 84 } // allocate simple object print(o.name, o[age]) // both notations are valid, but [] notation allows generated strings var a = [’a’, ’b’, 7, 11.] // an array, equivalent to {’0’: ’a’, ’1’: ’b’, ’2’: 7, ’3’: 11.} typeof o, a // ’object’, ’object’
(2)函數
函數:所有的函數都會evaluates to something:
function f() {} //evaluates as 'undefined'
function f() {} +1 // evaluates as 1 ,because 'undefined' is casted to 0
(function f() {}) //evaluates to a function object
(function () {return 0;}) () /evaluates as 0
(3)
for loop :
i 作為了index
(4)
delete p.z // remove p.z
p.z //undefined
(5)在列表中存入,或者在json對象中存在函數
(6) 創建對象new關鍵字
(1)
(2)創建對象默認構造函數:
這個時候Point其實就是個類。
為Point類添加個函數.
Each function in JavaScript can be used as a constructor in combination with the new operator.
To support inheritance, each function has a default property named prototype. Objects
created from a constructor inherit all properties from the constructor’s prototype. Consider the
following example:
其實 prototype里面的方法屬於派生出來的,如何檢查一個方法,或者一個類對象是原有的:
<2>公司一個小項目
按鈕效果模仿的是Google material design風格。流動起來。參考上篇有詳細代碼.
V2:
3,CG Browser
New Version:0.00001