[Qt技巧]用标准Qt库来解析JSON

随着移动开发的流行,JSON在app开发中也大行其道。目前,Qt开发基本都知道QJson是比较著名的第三方Qt库,除此之外,Qt5.0开始也会内置针对解析JSON的类。不过其实,从Qt4.3开始就可以用QtScript模块来解析JSON数据了。

主要要只用到QScriptEngine这个类

代码:

#include <QScriptEngine>
    QByteArray result;
    result = QhttpClient->readAll();
 
    QScriptValue sc; 
    QScriptEngine engine;
    sc = engine.evaluate(QString(result)); // In new versions it may need to look like engine.evaluate("(" + QString(result) + ")");
 
    if (sc.property("result").isArray())
    {
 
            QStringList items;
            qScriptValueToSequence(sc.property("result"), items); 
 
            foreach (QString str, items) {
                 qDebug("value %s",str.toStdString().c_str());
             }
 
    }

解析过程非常简单,使用QScriptEngine和QScriptValue就可以解析出来,然后就可以转到到我们的数据。当然,有可能会出错,使用下面代码来判断:

    if (sc.property("error").toBoolean() == true)
        qDebug("Error detected");
    else
        qDebug("All ok");

对于JSON数据中的数组,我们可以用QScriptValueIterator来遍历,代码如下:

    QByteArray result;
    result = QhttpClient->readAll();
 
    QScriptValue sc; 
    QScriptEngine engine;
    sc = engine.evaluate(QString(result));// In new versions it may need to look like engine.evaluate("(" + QString(result) + ")");
 
    if (sc.property("result").isArray())
    {    
             QScriptValueIterator it(sc.property("result"));
             while (it.hasNext()) {
                 it.next();
                 qDebug("Nick %s",it.value().property("nick").toString().toStdString().c_str());
             }
    }

通过这几组代码可以清晰地看出如何使用QtScript解析json数据,而且这样使用并不需要引入新的QJSON库,更加方便实际开发。

[翻译+感想]节选Necessitas alpha 4, a New Hope!

今天我有一个非常重要的消息要宣布,Necessitas的alpha第四个版本发布了。自从Nokia激进地改变了方向后,Qt渡过了一段非常苦难的时间,许多人都询问自己,包括我,是否要在未来将精力和金钱花在这前。我并不想对Nokia的愚蠢决定做评价,因为Nokia对于Qt的贡献已经足够大了。
相反得,我想要评论的是Qt的未来,将毫无疑问地Qt将继续存在。首先Qt是自由开源软件,根据KDE自由Qt基金会 与Nokia(未来将是Diga)的协议,在发布时候必须遵守LGPL2.1和GPL3协议,否者基金会将有权利将Qt在基于BSD风格的协议或者其他开源协议来发布。这项协议不管是是否Qt资产被出售,合并或者怕破产的情况下都依然保持有效。从这点来说我们任何人都不用担忧!至于Qt的未来发展呢,在Nokia抛弃它后将有谁来继续攻错的。一方面我们都对DIgia计息管理Qt项目有极大的期望,另一方面自由开源的软件的优势在于不仅是需要一个单一的公司来支配它,Qt还需要很多组织来帮助提交完善。譬如KDE,Necessitas, ICS, KDAB(这些都是以Qt为主的公司或基金会),还有更重要的是你们,众多的Qter的支持。没有比所有的开发者团结一致,聚集在一起支持更有力量。你可以自己思考下哪个选择对于你来说更好:
-处于无私的角度,你愿意花费你的时间或者是金钱去做下你喜欢做的事情,并且可以无偿提供给所有人。。
-处于自私的目的,你可以忘记Qt,然后重新去学蹩脚封闭的代码,如C#或者 iFramework什么的,有一天(或者很快)这些都会死因为这都背后都是有公司来支持的么?
对于我们毫无疑问是选择第一种,Necessitas的开发者们将完成Nokia失败的事情:将Qt部署到一个庞大数量得设备群上去,是得,Qter们,这才是真正得下一个十亿!

感想:

在Nokia放弃Qt后,放弃MeeGo后,很多人认为Qt已死,于是放弃自己几年得学习,投入到了android,投入到iOS中。但是Qt作为一个自由开源软件,正如文中说得,是不可能被一个公司支配得,他不是.net,不是MFC,如果MS不玩了,这些框架就完蛋了。可Qt背后还有社区支持得,即使没有digia,也会有KDE,也会有ICS这些来支持。

如今Digia也宣布了未来Qt的发展,android和iOS毫无疑问是移动方向重点,而在Win依然占据大量市场份额的情况下,支持Win8也是必然的。对于这些,对于我们Qter来说,关注Qt,使用Qt,未来才更美好。期待Qt横跨移动平台那天的到来!

[翻译]QML 引擎内部探析 Part 2: 绑定

原文地址:http://www.kdab.com/qml-engine-internals-part-2-bindings/

在上一篇博文里,我们主要阐述了QML引擎是如何载入QML文件的。再次说明下,首先是QML文件被解析,其次生成对应QML文件里所有元素的C++对象。举个例子,我们看见QML文件中包含了一个文本(Text)元素,那引擎就会生成一个C++ QQuickText类的实例对象。

事实上载入文件就是是QML文件所做的所有了。在此之后,在运行阶段QML引擎再也不会被调用了。例如事件处理和绘制等都是C++类来处理的。举个例子,一个文本输入(TextInput)元素处理输入是使用QQuickTextInput::keyPressEvent(),而绘制处理则是QQuickTextInput::updatePaintNode(),都没有调用QML引擎。

这里有两个重要的事务是QML引擎在运行阶段仍然会调用的,范围内信号处理和属性绑定这两者的更新。范围内信号处理是例如针对鼠标区域(MouseArea)元素的点击处理。这就是我们在这篇文章要探讨的绑定。思考下下个这个代码例子:

import QtQuick 2.0
Rectangle {
  width: 300
  height: 300
  color: "lightsteelblue"
  Text {
    anchors.centerIn: parent
    text: "Window Area: " + (parent.width * parent.height)
  }
}

这个代码例子包含了两种属性值的分配:

1.简单的值分配,比如給QQuickRectangle的宽度属性分配了300。在这个情形下,将会使用VME指令 STORE_DOUBLE,它将在这这个组件生成时候执行。这个VME仅仅会调用QMetaObject::metacall(QMetaObject::WriteProperty, …),而最终则会在调用QQuickRectangle::setWidth()后结束。当完成初始分配后,QML引擎就再也不会接触该元素宽度属性相关了。

2.绑定分配,类似例子中,分配时候将窗口区域大小绑定到文本属性text: “Window Area: ” + (parent.width * parent.height)

),将其布局位置配绑定到其父元素的中心(

anchors.centerIn: parent

)。多亏了绑定的神奇机制,文本内容将会随着矩形宽和高的大小改变而自动更新。这是如何工作的呢?实际上这其中并没有什么神奇的地方,接着往下阅读来探索。

创建绑定

使用 QML_COMPILER_DUMP=1查看VME指令集,我们可以看到所有的绑定都是由STORE_COMPILED_BINDING指令生成的:

...
9               STORE_COMPILED_BINDING  43      1       0
10              FETCH                   19
11              STORE_COMPILED_BINDING  17      0       1
...

编译绑定是一个优化过程,我们首先来看看普通的绑定,它是由STORE_BINDING指令生成的。可以查看其在QQmlVME::run()中的代码,我们可以发现代码生成了QQmlBinding对象,并且使用字符串“function $text() { return “Window Area: ” + (parent.width * parent.height) }”来作为它的表达式。没错,每个绑定本质上都是JavaScript函数!这个函数function $text()”是由QML编译器来增加,并且自从v8 JavaScript引擎在QML使用后,就只能评估(evaluate)完整的函数。该函数字符串随后将由v8编译器编辑成一个v8::Function对象。该v8使用Just-in-Time (JIT) compiler(实时编译器)来生成机器码。该v8::Function不会立刻执行,但是会一直保持

简单来总结 STORE_BINDING 指令生成绑定过程的话就是:一个QQmlBinding对象生成,然后根据传递的函数字符串编译至 v8::Function。

运行绑定

当在某个点上,绑定需要运行了,那就意味让v8引擎运行绑定函数,并且将结果写入到目标属性。这一般都在创建阶段的最后完成,QQmlVME::complete()调用一个update()函数来对应每个绑定,在我们例子中,对应的是QQmlBinding::update()update()函数仅仅调用 v8::Function对象并且将返回值写入到目标熟悉,在我例子里文本内容属性对应的是矩形的宽高。

但是等等,v8是怎么知道父对象(矩形)宽和高的值呢?事实上它甚至是如何知道父对象是哪个呢?答案也非常明确,不知道,v8引擎并不知道这些QObject对象存在哪些对应的QML文件中,连那些属性也是。当v8遭遇到未知对象或者未知属性时候,它回去询问QML引擎中的对象封装器(objectwrapper),于是对象封装器回去寻找正确的对象或者属性并将之返回給v8引擎。让我们看看一个QQuickItem的宽度属性在回溯里是如何访问的:

#0  QQuickItem::width (this=0x6d8580) at items/qquickitem.cpp:4711
#1  0x00007ffff78e592d in QQuickItem::qt_metacall (this=0x6d8580, _c=QMetaObject::ReadProperty, _id=8, _a=0x7fffffffc270) at .moc/debug-shared/moc_qquickitem.cpp:675
#2  0x00007ffff7a61689 in QQuickRectangle::qt_metacall (this=0x6d8580, _c=QMetaObject::ReadProperty, _id=9, _a=0x7fffffffc270) at .moc/debug-shared/moc_qquickrectangle_p.cpp:526
#3  0x00007ffff7406dc3 in ReadAccessor::Direct (object=0x6d8580, property=..., output=0x7fffffffc2c8, n=0x0) at qml/v8/qv8qobjectwrapper.cpp:243
#4  0x00007ffff7406330 in GenericValueGetter (info=...) at qml/v8/qv8qobjectwrapper.cpp:296
#5  0x00007ffff49bf16a in v8::internal::JSObject::GetPropertyWithCallback (this=0x363c64f4ccb1, receiver=0x363c64f4ccb1, structure=0x1311a45651a9, name=0x3c3c6811b7f9) at ../3rdparty/v8/src/objects.cc:198
#6  0x00007ffff49c11c3 in v8::internal::Object::GetProperty (this=0x363c64f4ccb1, receiver=0x363c64f4ccb1, result=0x7fffffffc570, name=0x3c3c6811b7f9, attributes=0x7fffffffc5e8)
    at ../3rdparty/v8/src/objects.cc:627
#7  0x00007ffff495c0f1 in v8::internal::LoadIC::Load (this=0x7fffffffc660, state=v8::internal::UNINITIALIZED, object=..., name=...) at ../3rdparty/v8/src/ic.cc:933
#8  0x00007ffff4960ff5 in v8::internal::LoadIC_Miss (args=..., isolate=0x603070) at ../3rdparty/v8/src/ic.cc:2001
#9  0x000034b88ae0618e in ?? ()
...
[more ?? frames from the JIT'ed v8::Function code]
...
#1  0x00007ffff481c3ef in v8::Function::Call (this=0x694fe0, recv=..., argc=0, argv=0x0) at ../3rdparty/v8/src/api.cc:3709
#2  0x00007ffff7379afd in QQmlJavaScriptExpression::evaluate (this=0x6d7430, context=0x6d8440, function=..., isUndefined=0x7fffffffcd23) at qml/qqmljavascriptexpression.cpp:171
#3  0x00007ffff72b7b85 in QQmlBinding::update (this=0x6d7410, flags=...) at qml/qqmlbinding.cpp:285
#4  0x00007ffff72b8237 in QQmlBinding::setEnabled (this=0x6d7410, e=true, flags=...) at qml/qqmlbinding.cpp:389
#5  0x00007ffff72b8173 in QQmlBinding::setEnabled (This=0x6d7448, e=true, f=...) at qml/qqmlbinding.cpp:370
#6  0x00007ffff72c15fb in QQmlAbstractBinding::setEnabled (this=0x6d7448, e=true, f=...) a /../../qtbase/include/QtQml/5.0.0/QtQml/private/../../../../../../qtdeclarative/src/qml/qml/qqmlabstractbinding_p.h:98
#7  0x00007ffff72dcb14 in QQmlVME::complete (this=0x698930, interrupt=...) at qml/qqmlvme.cpp:1292
#8  0x00007ffff72c72ae in QQmlComponentPrivate::complete (enginePriv=0x650560, state=0x698930) at qml/qqmlcomponent.cpp:919
#9  0x00007ffff72c739b in QQmlComponentPrivate::completeCreate (this=0x698890) at qml/qqmlcomponent.cpp:954
#10 0x00007ffff72c734c in QQmlComponent::completeCreate (this=0x698750) at qml/qqmlcomponent.cpp:947
#11 0x00007ffff72c6b2f in QQmlComponent::create (this=0x698750, context=0x68ea30) at qml/qqmlcomponent.cpp:781
#12 0x00007ffff79d4dce in QQuickView::continueExecute (this=0x7fffffffd2f0) at items/qquickview.cpp:445
#13 0x00007ffff79d3fca in QQuickViewPrivate::execute (this=0x64dc10) at items/qquickview.cpp:106
#14 0x00007ffff79d4400 in QQuickView::setSource (this=0x7fffffffd2f0 at items/qquickview.cpp:243
#15 0x0000000000400d70 in main ()

我们可以发现封装器在qv8qobjectwrapper.cpp中,并且最后是调用了QObject::qt_metacall(QMetaObject::ReadProperty, …)来获取属性值。封装器是从v8代码中被调用的,但是其本身是由于生成v8::Function机器码的对象而被调用的。该生成的机器码是没有栈结构的,因此GDB也是无法显示其回溯过程的。我是使用两个独立的回溯来创建了这一个过程,这样可以用来解释上述回溯矛盾的编号。

因此v8是调用了对象封装器来获取了属性值。出于同样的方式,它调用了上下文封装器(context wrapper)来找到对象们,比如父对象就是绑定解析来访问的。

简单总结下,一个绑定是由运行 v8::Function 代码解析评估的。v8通过Qt里的封装器来访问未知对象和未知属性。最后结果由v8::Function返回随后写入倒目标属性。

更新绑定

好的,现在我们已经知道文本属性是如何获得初始值了。那么绑定更新是如何做的呢?QML引擎怎么知道当宽和高属性改变时去预备运行绑定呢?

答案同样隐藏在对象封装器中,正如你记忆的,从v8引擎中调用事需要访问属性的。对象封装器所需要做的无非只是返回属性值:它将捕获所有访问过对属性。从本质上来说,当一个属性被访问时候,对象封装器调用当前正在运行绑定的捕获函数,再我们例子中是QQmlJavaScriptExpression::GuardCapture::captureProperty()QQmlBindingQQmlJavaScriptExpression的子类)。

在捕获函数中,绑定只是连接了捕捉属性的NOTIFY信号。当NOTIFY信号触发时候,一个连接的绑定槽函数在预备运行绑定时候调用了。如果你从来没有听说过NOTIFY信号,不要担心,这是十分简单的概念:当一个属性被声明为Q_PROPERTY,也有可能会声明一个NOTIFY信号。无论何时何地这个对象的属性改变时,这个信号都会被触发。

举个例子,QQuickItem的宽度属性声明是:

For example, the declaration for the width property in QQuickItem looks like this:Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged)。在我们代码方案中,当宽度属性第一次被访问运行时候,属性捕捉代码就连接的widthChanged()信号。当QQuickItem之后出发widthChanged()信号后,连接的槽绑定函数就会被调用,绑定也自然会被重新评估。

这就是NOTIFY信号如此重要的原因,因此当在你的属性改变时候,是由出发它们来发出通知消息。如果你忘记做了,那么绑定就不会重新计算评估,那属性绑定本质上也就不会正常工作。从另一方面来说,即使你出发了NOTIFY信号即使属性没有发生改变,那么绑定也应该被重新评估计算。

总结下:当访问属性时,对象封装器会从绑定理调用捕获函数,去连接属性的NOTIFY信号,以便当属性改变时候重新评估计算。

结论

在这篇博文了,我们全面探索了绑定时如何工作的。简而言之就是,每个绑定都会被编译成JavaScript函数,并且在对应引用的属性改变时候调用。

我希望读者们能够享受阅读这些内容,我发现实验绑定属性是非常有趣的过程。

在下个博文系列理,我们将探索不同的绑定属性。当然,本文理我们只探索最多使用的基础绑定,QQml绑定(QQmlBinding),但是我们知道其实已经知道其他绑定类型,比如编译办绑定。这些内容的奥秘我们将会在未来探索出来,请期待。

[翻译]QML 引擎内部探析 Part 1: QML 文件载入

原文地址:http://www.kdab.com/qml-engine-internals-part-1-qml-file-loading/

在这一系列的blog文章里,我们将探索QML引擎,并且揭开其内部的工作机制。这些文章内容都是基于Qt5的QtQuick2.0版本。

大多数人已经知道QML中各个元素背后其实是C++类。当一个QML文件载入时,QML引擎将根据文件中的所有元素,以某种机制来生产一个C++对象。在这篇文章里,我们解释这个过程,知道QML引擎是如何阅读一个基于文本的文件来生成一个完整的C++对象树。在Qt的文档中,已经详细解释了QML是如何与C++一起工作,这些文档非常值得花时间去阅读。在这个blog文章系列里,我假设你已经阅读过了这些文档并且都明白了。

例子

我们将使用一个例子贯穿全文,这个例子并不具有实际的用处或者激动的地方,但是覆盖了几个QML有趣的部分:

import QtQuick 2.0
 
Rectangle {
    id: root
    width: 360
    height: width + 50
    color: "lightsteelblue"
    property alias myWidth: root.width
    property int counter: 1
 
    function reactToClick() {
        root.counter++
    }
 
    Text {
        id: text
        text: qsTr("Hello World: " + counter)
        anchors.centerIn: parent
    }
 
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        onClicked: {
            reactToClick()
        }
    }
}

This file has three elements in it, RectangleText and MouseArea. These correspond to the C++ classes QQuickRectangleQQuickText and QQuickMouseArea. Those classes are only exported to QML, the C++ versions are private and not available for users of Qt. The elements are drawn using a OpenGL scenegraph. Drawing and event handling are both orchestrated byQQuickView . The C++ object tree corresponds to the one in the QML file, which we can verify with KDAB’s Qt introspection tool, Gammaray:

这个QML文件里有三个元素,分别是Rectangle,Text和MouseArea。 它们分别对应C++类中的QQuickRectangleQQuickText 和 QQuickMouseArea。这些类只暴露给了QML,其C++版本是私有的,并且Qt的使用者们无法使用。这些元素的绘制都使用了一个OpenGL scenegrap。绘制和事件的处理则都是由QQuickView负责协调。下面的C++对象树对应了一个QML文件,可以通过使用KDAB的Qt introspection tool, Gammaray来验证:

As expected, the classes QQuickMouseArea and QQuickText show up in the object tree. But what is QQuickRectangle_QML_0? There is no C++ class with such a name in the Qt sources! We’ll come back to that in a later blog post, for now you can assume that an object of type QQuickRectangle was used.

Let’s go a step further and run the application in the QML profiler:

正如预测的,类QQuickMouseArea和QQuickText都在对象树显示了,但是QQuickRectangle_QML_0是啥呢?在Qt源代码里并没有这样的C++类名字。不过我们将在稍后的blog文章了解释这些,现在我们只需知道,一个QQuickRectangle的对象的确使用到了。

让我们接着下一步,在QML profiler运行这个程序:

 

We see that a bunch of time is spent setting up the scene, which is the Creating phase. This is followed by a bit of Painting, which is what we would expect. But what is this Compiling phase? Is it creating machine code? Time to dig into the QML file loading code a bit deeper.

我们可以看到一堆时间花费在设置场景,这对应的是创建阶段。接下来的一点则是绘制阶段,就是我们预想将要出现的画面。但是编译阶段是什么呢?难道是创建机器码的步骤?需要花费我们一定时间来深入QML文件的载入步骤,因为这些过程相对来说已经比较深入了。

QML文件载入步骤

When loading a QML file, there are 3 distinct steps happening, which we’ll examine in the following sections:

当载入一个QML文件时候,这里将会有三个明确的步骤发生,这将是我们下面章节将要解释的:

1.解析阶段

2.编辑阶段

3.创建阶段

解析阶段

First of all, the QML file is parsed, which is handled by QQmlScript::Parser. Most of the parser internals are auto-generated from a grammar file. The abstract syntax tree (AST) of our example looks like this:

首先,QML文件要被解析,这个过程是由QQmlScript::Parser来完成。大多数内部将是将自动从grammar file中生成。本文里,例子的抽象标记叔(AST)看过去是这样的:

(这图生成的工具graphviz使用了一个位图生成器的补丁,其补丁在http://www.kdab.com/~thomas/stuff/ast-graph.diff)

这个对象标记树是十分底层的,在下个步骤才转换到更高层次的结构如Objects(对象),Properties(属性) and Values(值)。这一切是使用AST的visitor(观察者,探索器)完成的。在这一层,对象代表了QML元素,属性/值的配置代表了QML属性与值,例如”color”属性,被赋值了”lightsteelblue“。甚至信号处理如onClicked也是属性/值的配对,在这个情况下,值代表了Javascript的函数体。

编译阶段

现在理论上,Objects(对象集合), Properties(属性集合)以及Values(值集合)的结构已经足够解释如何创建C++对象以及属性值类之间的关联。尽管如此,Objects(对象集合), Properties(属性集合)以及Values(值集合)仍旧是十分原始,并且需要在C++对象集合生成前进行一些后续处理。这些后续处理主要是由QQmlCompiler完成,这解释了QML profiler(QML性能检测器)中编译阶段所展示的。这个编译过将针对这个QML文件生成一个QQmlCompiledData。审查QQmlCompiledData并且生成C++对象的过程,其速度远胜于审查Objects(对象集合), Properties(属性集合)以及Values(值集合)。当使用一个QML文件多次后,假设是例子是一个Button.qml并且使用了在其他QML文件里的各个地方,那么 Button.qml将只会被编译一次。Buttom.qml的QQmlCompiledData将会保持,当每次Buttom组件使用时,C++对象将会由QQmlCompiledData来审查。在后续的创建阶段,可以通过QML性能监测器看到输出。

简单地总结下:QML文件的解析和编译将会只执行一次,接下去QQmlCompiledData对象将会被使用快速创建C++对象。

创建阶段

笔者不想对QQmlCompiledData的细节做过度深入,但是有一样东西可以能吸引你的注意力:QByteArray字节码(QByteArray bytecode)成员变量。该指令用来创建C++对象,分配正确的值到对应属性,之后由字节码解释器编译到字节码去。这些字节码包含了一串的指令,并且当指令执行时候QQmlCompiledData的剩余部分将作为辅助的数据使用。

在创建阶段,字节码的解释是由QQmlVME。查看QQmlVME::run(),解释器简单地循环了所有字节码里的指令,并且是由一个庞大的switc状态正对不通的指令说明类型。在运行程序时,通过设置QML_COMPILER_DUMP=1,我们可以看到独立的字节码说明:

Index           Operation               Data1   Data2   Data3   Comments
-------------------------------------------------------------------------------
0               INIT                    4       3       0       0
1               INIT_V8_BINDING 0       17
2               CREATECPP                       0
3               STORE_META
4               SETID                   0                       "root"
5               BEGIN                   16
6               STORE_INTEGER           45      1
7               STORE_COLOR             41                      "ffb0c4de"
8               STORE_COMPILED_BINDING  10      2       0
9               STORE_DOUBLE            9       360
10              FETCH_QLIST             2
11              CREATE_SIMPLE           32
12              SETID                   1                       "text"
13              BEGIN                   16
14              STORE_V8_BINDING        43      0       0
15              FETCH                   19
16              STORE_COMPILED_BINDING  17      1       1
17              POP
18              STORE_OBJECT_QLIST
19              CREATE_SIMPLE           32
20              SETID                   2                       "mouseArea"
21              BEGIN                   16
22              STORE_SIGNAL            42      2
23              FETCH                   19
24              STORE_COMPILED_BINDING  16      0       1
25              POP
26              STORE_OBJECT_QLIST
27              POP_QLIST
28              SET_DEFAULT
29              DONE
-------------------------------------------------------------------------------

CREATE_SIMPLE是最重要的指令,它产生C++对象,使用QQmlMetaType中注册对象的数据库。

STORE_INTEGER指令用来向一个属性写入整型。

STORE_SIGNAL 指令用来处理一个约束的信号处理者。

STORE_*_BINDING 指令用来处理生成属性绑定。更多关于绑定的内容将会在下一篇blog文章内提到。

SETID 显然是用来设置一个对象的识别,这可不是一个普通的属性。

VME有一个对象集合的站,所有类似STORE_*操作的指令都在顶部对象。FFTCH指令将特定的对象放置到栈顶,POP指令则是移植栈顶的对象。所有的指令都大量使用了整数指数,比如 STORE_COLOR指令写入属性41,代表了在这个目标元数据对象中的属性索引。

简单总结下:一旦QML文件解析完毕,创建实例的过程就仅是是执行编译数据字节码的过程事务。

结论

在这篇文章结尾,我们已经知道了QML文件时如何解析,处理,编译以及稍后对象时如何通过VME生成的。我希望你能从QML引擎的这些知识中获得许多有趣的见解。

请等待下一篇文章,在那里我们解释属性绑定是如何工作的。

 

[翻译]在Mac OS X上安装Consolas(How to Install Consolas on Mac OS X)

原文地址:http://www.wezm.net/technical/2010/08/howto-install-consolas-font-mac/

Consolas是笔者十分喜欢的一个编程字体,是VS默认的编程字体,在过去笔者也把它作为我默认的文本编辑字体。

不过转变到一个mac兼职linux程序员后,就再也没有使用它。最近,一位同仁介绍了这篇文章,让笔者得以重新在Mac OS X上能够使用该字体了。

安装

1.下载针对Mac的Open XML File Format Converter,地址为Microsoft Mactopia download page

2.双击安装镜像,一般情况下都会自动挂载。如果没有,你需要查看下Open XML File Format Converter原始安装包

3.鼠标右击(或者control + 鼠标点击)原始安装包,选择“显示包内容”

4.在Finder窗口中,点击“Contents”,最后进入“Packages”

5.双击“OpenXML_all_fonts.pkg”,然后就会自动安装

Step 1: Show Package Contents

步骤3:显示包内容Step 4: Navigating to the package

步骤四:导航到packageStep 5: Running the OpenXML_all_fonts.pkg installer

步骤5:运行OpenXML_all_fonts.pkg安装

 

优化调整

现在Consolas已经安装豪了,不过按照目前字体的平滑设置,它会看起来有点小并且有点丑,所以需要调整这些设置。

对于Mac OS X雪豹版本来说,需要在终端理设置正确的值,因为apple从系统偏好设置里移除了选项:

1.打开终端(应用程序->实用工具->终端)

2.复制并粘贴下面的终端命令,然后回车

defaults -currentHost write -globalDomain AppleFontSmoothing -int 2

对于终端小白来说,可能并不能理解该命令的作用,其实该命令主要做了以下事情:

defaults命令是用来维护用户的默认设置,众所周知的就是偏好设置。其中AppleFontSmoothing设置是特殊的集合,针对全局的(对于所有的用户和系统),这里,设置级别为整数2,它在主要之前到现在的Mac OS X版本负责中等字体的平衡设置。

对于Mac OS X Leopard之前的版本来说:

1.打开系统偏好设置

2.点击”外观”

3. 在最底部,设置字体平滑为:“Medium (best for Flat Panel)”

设置完毕后,你需要重启系统,才能让这些设置生效。

 

zeroconf研究笔记(1) ——zeroconf初步认识


最近对zeroconf协议进行了一系列深入的研究,深深地被这一技术折服,在1999年就出现的该协议,在技术的应用上已经走向成熟,走向向大众普及之路了。
apple的airplay,airprint都是依赖了zeroconf的基础上,才展现出强大的功能。

zeroconf介绍

Zeroconf全称为Zero configuration networking,中文名则为零配置网络服务规范,是一种用于自动生成可用IP地址的网络技术,不需要额外的手动配置和专属的配置服务器。

“零配置网络服务”的目标,是让非专业用户也能便捷的连接各种网络设备,例如计算机,打印机等。整个搭建网络的过程都是通过程式自动化实现。如果没有zeroconf,用户必须手动配置一些服务,例如DHCP、DNS,计算机网络的其他设置等。这些对非技术用户和新用户们来说是很难的事情。

使用例子来形象地说明:
用户拥有一台apple tv和一台iPhone4s,那之只要都连入到同一个无线局域网内,iphone4s就会自动找出apple tv,那么在播放音乐或者视频时候,用户只要点击推送,就可以讲音乐和视频推送到apple tv上播放。

zeroconf协议的实现

zeroconf是协议,因此对应的是各种产品的实现,现在最主要的实现是apple的Bonjour和开源的Avahi。
这两套实现在程序接口上是可以兼容的,因此可以对zeroconf技术依赖的产品,可以使用兼容的开发接口,而不需要考虑到底是使用了Bonjour还是avahi。

Apple的zeroconf协议技术实现 – Bonjour

Bonjour是由apple实现的zeroconf协议的技术产品,Bonjour来源于法语,意思为你好。
使用了zeroconf技术的产品和服务,在网络中自动传播它们自己的服务信息并聆听其它设备的服务信息,设备之间就象在打招呼,这也是命名为Bonjour(法语:你好)的原因。
Bonjour是一套跨平台的产品,可以使用在Mac,Linux和Winows,以及是兼容POSIX的操作系统上,并且apple已经將其开源,所以也可以方便应用于各个产品。
Bonjour是由纯C编写的,同时也提供了Java的接口,目前如python或者ruby语言也可以很方便地调用使用它。

开源的zeroconf协议技术实现 – Avahi

Avahi 是Zeroconf规范的开源实现,基本是使用在Linux和FreeBSD上。包含了一整套多播DNS(multicastDNS)/DNS-SD网络服务的实现,使用的发布授权是LGPL。
在程序接口上,它使用DNSD与apple的Bonjour进行兼容,方便原来使用Bonjour的产品进行迁移。
目前在绝大多数的Linux发行版本中,都讲avahi作为系统启动进程,并且大量的服务也依赖于avahi。
Avahi也是用纯C编写的,同样也可以使用诸如Java的语言去调用使用开发产品或者服务。

嵌入式中的zeroconf – WiSe-Zeroconf

Wise-Zeroconf是Wise公司基于开源的Bonjour的基础上,提供给嵌入式产品的zeroconf技术实现。
由于是商业产品,详细资料不想,但是基本功能与Bonjour应该基本相同。

zeroconf最基础原理

zerconf协议主要是定义了三个层次:
1.不需利用dhcp server取得 设备地址如IP的相关资料
RFC 3927 , Dynamic Configuration of IPv4 Link-Local Addresses

http://www.ietf.org/rfc/rfc3927.txt

2.不需要通过DNS server就转换domain name和IP的关系
Multicast DNS

http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt

3.利用 DNS-SD来取得设备服务,而不需通过directory server
DNS-based Service Discovery, or DNS-SD.

http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt

zeroconf的未来分析

虽然zeroconf协议名声不大,即使是计算机专业开发人员也知之甚少,但是其实由于这几年apple发展的强势,其应用已经越来越广。
比如在iOS4.2推出时候的airplay,以及airprint都是在这基础上实现的,甚至iOS5.0后的air mirroing技术,也是在zeroconf技术上实现的。
可以预想在未来,zeroconf和DLNA將会有激烈的竞争关系。

小西GoogleReader发布

本身由于对Google Reader很挺依赖的,但是在N9上没有特别好的Google Reader软件,所以就萌生了做一个的年头。
这个软件是今年1月开始动手的,陆陆续续做到2月底,差不多完工了。不过由于当时没有N9,所以没办法进行真机测试,后来失业到现在,也没把心思花在这上面。现在已经5月了,N9就刚刚入手,所以就感觉加上了中文,测试了下,发布出来。
预计未来应该是一个月发更新一个版本,尽量功能上向Reeder学习,希望能做成那样强大。
现在暂时还没发布到ovi store上去,所以就发直接发deb安装包吧。
更新日志
0.0.1版本
1.可查看全部订阅RSS内容
2.可查看加星标,未读和加笔记RSS内容
3.可以查看订阅blog列表
4.支持添加订阅
5.支持添加笔记,标记可读和标记星标
0.0.2版本
1.修正https失效问题

下载地址:
0.0.1版本

http://vdisk.weibo.com/s/4-cuT

0.0.2版本

http://vdisk.weibo.com/s/4-yyT

由于现在还是失业阶段,估计还有大量时间可以优化,所以有bug可以及时邮件反馈给我,如果有什么功能想法和创意也可以mail。

附:程序图标比较丑,如果有PS大拿可以帮忙做下,非常感激,启动画面也暂时没有,也希望PS高手可以顺手帮忙做一个,thanks。
附注2:一开始就考虑到了伟大的墙,所以内部都是强制用HTTPS,有时会出现延迟的情况,比较无奈,不是app本身原因,是墙在起作用,在PC上测试也经常会出现。

bug反馈:
cnnbboy@gmail.com

无法Deb安装到N9/N950原因分析

最近为N9开发app,使用QtSDK开发过程中,经常会出现Deb无法安装到设备的情况发生,严重的干扰了开发效率。
经过初步研究,主要原因有如下3种:
1.权限问题
harmattan内虽然是基于linux,但是也有权限认证,使用aegis。
如果有库文件或者配置文件需要安装到系统路径中,同时又没有修改manifest.aegis,那必然会出现安装失败的情况。
解决的办法也很简单:
找到你app的 manifest.aegis文件,针对你安装文件分别添加 进去
2.Deb大小问题
使用QtCreator上传deb到N9中,都是上传到/tmp目录,然后进行安装。
但是harmattan,为/tmp目录分配的空间是极小的,所以一旦Deb超过3m大小,那么会出现安装失败的情况。
解决办法也很简单,使用scp命令將deb包安装到用户主目录下进行安装。
3.莫名奇妙的错误
这种错误存在最郁闷,因为基本出现是有几率性的,而且令人感觉是莫名奇妙。
一般可以综合为,dkpg异常中断,导致dpkg的进程被锁;使用的了daemon的机制,写了启动脚本,启动脚本如果异常退出,也会导致错误的发生。
针对这些错误,只有跟踪安装log,然后依次针对改对应步骤的进行修改才有望解决。

如何在meego harmattan上发布和链接动态库

介绍

在为meego harmattan(N9)开发过程中,我们经验需要用到第三方库,由于Nokia Store的对于系统的保护策略,虽然harmattan是纯正的linux操作系统,但是我们不可能將动态库放在系统级别的目录,比如/usr/lib,/usr/local/lib。所以如果app使用了其他的动态库,在发布时候,会有链接失败的现象出现,并且同时我们也无法使用设置,考虑到过多的静态库会增加app的体积,所以研究一种可用的发布方式是必要的。

发布动态库

Nokia商店的策略建议讲动态库发布到/opt位置,一般是内置在你的程序目录内,我们假设程序目录目录为/opt/myapp/lib,同时名字为libcool.so。
那为了发布该库,你需要在你的.pro文件中加入如下行:

coollib.files = /local/path/to/libcool.so
coollib.path = /opt/myapp/lib
INSTALLS += coollib

假如你是在windows环境中,你的本地路径需要doc斜线符号来取代反斜线,比如c:/local/path/to/libcool.so。
你也可以考虑使用$$PWD变量来指定动态相对你的.pro文件的相对路径,比如

coollib.files = $$PWD/../coollib/libcool.so

链接到动态库

There are two stages needed for linking against a shared library: compile-time and runtime. At compile-time the shared library is being searched for the functions it exports to build dependencies inside your application’s binary. At runtime these dependencies are followed and the code of the shared library is actually executed.
这里有两种情况需要你链接到动态库,编译阶段和运行阶段。编译阶段,动态库用来和你的程序编译至二进制文件,运行阶段,程序依赖动态库代码而运行。

编译阶段需要在你的.pro文件中添加:

LIBS += -L/local/path/to -lcool
INCLUDEPATH = /local/headers-path

cool是库的名字去除后缀面的前缀lib,同时/local/headers-path是库头文件目录所在,你也可以使用$$PWD来使用。
为了成功编译,防止意外出来,你应该需要修改器的rules文件,將行

# dh_shlibdeps # Uncomment this line for use without Qt Creator
注释二次为
## dh_shlibdeps # Uncomment this line for use without Qt Creator
或者删除它。
这样做的理由主要出于未知理由(在Qt4.8.0) dh_shlibdeps命令如果只注释一次,那么仍将执行,这样会阻止你的工程编译链接动态库

在运行阶段,你需要告诉你的二进制程序文件,你的动态库文件位置那里,对于普通linux,我们可以使用 LD_LIBRARY_PATH环境变量,但是这里并不适用。
为了解决这个问题,你可以使用–rpath选项链接你的程序,添加下列一行在你的.pro文件中
QMAKE_LFLAGS += -Wl,–rpath=/opt/myapp/lib
然后,就完成了

总结

以上过程笔者已经在harmattan1.2测试通过,基本包含了绝大多数情况,偶然有特殊情况的话,可以考虑修改环境变量或者將库安装在系统级别的范围。

参考

http://www.developer.nokia.com/Community/Wiki/How_to_deploy_and_link_a_shared_library_on_Harmattan