Skip to main content

import QtQuick 1.1

Comments

原文链接:[Alan Alpert](http://labs.qt.nokia.com/author/aalpert/) - [import QtQuick 1.1](http://labs.qt.nokia.com/2011/02/25/import-qtquick-1-1/)

对那些一直关注着QML的朋友们来说,大家或许还记得我们改变了import QtQuick 1.0的行为,从而允许我们按照Qt小型修订版而发布QtQuick的修订版。现在其中一个修订版即将完成,并很快就会出现在[Qt](http://qt.gitorious.org/qt) 4.7的代码分支上。 这里有[很多有趣的东西](http://doc.qt.nokia.com/4.7-snapshot/qtquick-whatsnew.html "QtQuick 1.1新功能列表") ,不过其中我想要重点介绍一下我们已经完成的在QtQuick版本化管理方面一些的改进。

去年我提到我会结合我的单词游戏模块写一篇关于QML版本系统的文章。碰巧当时我们注意到我们的版本系统中有些功能是缺失的 - 不过目前这些功能都已经被QtQuick 1.1所实现了, 这使得我这篇关于版本系统的文章在整体上可以变得更更好。现在就让我来分享给大家。

相比于Qt的C++部分,我们致力于使QML模块可以有一个更好的升级路线。我们已经努力允许在不同版本间的变更不会使得应用程序崩溃,或者对模块所有者的任何微量变更做出严格限定。这里的关键就是版本化的模块引用方式,这就是为什么你要写import "QtQuick 1.1"而不是仅仅QtQuick的原因。通过得到一个特殊的版本号可以使得我们有机会仅给你所要求的模块版本,即使这个模块现在已经有了更新的版本和更多的新功能。实现这一切的主要机制就是qmlRegisterType函数参数中的版本号。当你给出一个类型的主要和次要版本号时,应用程序如果要在该模块名字空间下使用这一类型就必须引入相同的版本号。这意味着模块在增加类型的时候可以不用担心符号的冲突。

作为示例,我为[单词游戏模块](http://gitorious.org/qt-qml-demo-playground/qt-qml-demo-playground/trees/master/wordgame)增加了一个Letters新类型。设想下面的代码片段来自于1.0版本:

import QtQuick 1.0
import MyTypes 1.0
import Qt.labs.wordgame 1.0
Item{
BoardLogic{
...
}
Letters{
count: 26
...
}
}

这段代码中的"Letters"类型来自于"MyTypes"模块, 并且其完成的功能和我们的新类型很相似。但是它确有不同的属性,所以当你试图运行(使用1.1版本并且不使用我们的版本系统)此QML文件时,你将会得到如下错误: Cannot assign to non-existent property "test"。如果这个单词游戏是一个系统模块并且会独立于这个游戏被更新,那么这个游戏程序将无法被加载,直到游戏的相关紧急更新出现。

但是这段代码并没有引入1.1版本而是引入的1.0。所以在我们的版本系统下,这一新的Letters类型将不会被加载,游戏也将像以往一样正常运行。这一应用的维护者可以很轻松地在下一版中使用这一功能,并通过改变他们的类型名或者把单词游戏模块引入到单独的名字空间(import Qt.labs.wordgame 1.1 as WordGame)来修正这一问题。而且他们不会在两次更新之间有无法工作的程序。

需要注意的是如果你在开发中引入了更老的版本而不是你需要的那个,在按照这一老版本部署的时候QML并不会给出错误警告,并且相干代码可以不会正常工作。不过这一问题很容易解决 - 只要在开发时使用你需要的那个版本即可。

一个更加激进的例子,比如你要完全改变模块的实现(这正是我们正在对下一版Qt.labs.particles模块所作的工作)。通过为这个类型注册一个不同版本号的的完全不同的C++类, 那么应用将仅当他们明确引用了该版本或其后续版本时才能使用这一新类型。他们仍然可以通过该类型使用通过早期版本注册的原来的C++类, 得到的C++类型取决于引用时所提供的版本号。所以当新的方式无法工作时,你也完全不必因为老版本的实现被取消了而把事情搞砸。

不过这还不是故事的全部 - 在QtQuick 1.1中我们还在单独属性,信号和槽的的级别增加了版本化的支持。版本化的类型很棒,不过这只是在大量变更时最有效, 比如新增一个元素或者完全重写一个(这事实上也算一个新元素)。你并不会想仅为了增加一个lineCount属性到Text类型而不得不写一个全新的C++类。比如在单词游戏模块中,为了使用新的Letters对象, 它需要和BoardLogic类集成起来; 但是这仅需通过一个属性来微调现有行为即可。 下面的来自boardlogic.h的代码片段显示了仅需做出变更:

//A Letters object is how you can set the individual letter frequencies and score
Q_PROPERTY(Letters* letters READ letters WRITE setLetters NOTIFY lettersChanged REVISION 1);
...
signals:
Q_REVISION(1) void lettersChanged(Letters* arg);

请注意因为这里的getters/setters不能通过QML直接访问,所以并不需要版本信息。并且不要忘记在wordgame.cpp文件中注册这一新版本:

qmlRegisterType(uri,1,1,"BoardLogic");

现在, BoardLogic中的"letters"属性就仅当你引入1.1版本时才会出现在QML中,这就避免了前面说的在类型级别的上的冲突。所以通过仅仅增加一些属性/信号/槽来更新系统模块就变得既安全又容易,也不会因此一直破坏依赖于他们的应用程序。

通过使用这一级别的版本标识,我们才可以能够做到使QtQuick 1.1成为一个增量发布版本,从而不会破坏任何人正在运行中的代码。这一工作填补了如何避免不得不编写大量新类才能做到的工作 - 仅仅在需要的地方增加一些属性而已。当然也新增加了一些新的类型,不过这是另一件事了,和本话题关系不大。

Comments

Subscribe to our blog

Try Qt 6.11 Now!

Download the latest release here: www.qt.io/download

Qt 6.11 is now available, with new features and improvements for application developers and device creators.

We're Hiring

Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.